Most page builders let you attach custom CSS to any element on the page using a simple input box.
The problem is that you must manually reference the element you’re styling, just like you’re writing actual CSS:
.this-element {
font-size: var(--text-l);
margin-block: var(--space-m);
}
Code language: CSS (css)
Or, even worse, the page builder auto-references the element so all you can add are the actual properties with no selector control:
font-size: var(--text-l);
margin-block: var(--space-m);
Code language: JavaScript (javascript)
Then, some page builders introduced a *basic* root selector that allows you to auto-reference the current selector. This lets you write CSS like this:
root {
font-size: var(--text-l);
margin-block: var(--space-m);
}
Code language: CSS (css)
This provides two major benefits:
- You don’t have to type selector names
- You can change the selector name without breaking your CSS.
There are still major drawbacks to a basic root selector, though, which is why I advocated for Bricks to upgrade to a dynamic root selector.
A dynamic root selector works like this:
%root% {
font-size: var(--text-l);
margin-block: var(--space-m);
}
Code language: CSS (css)
Looks very similar, right?
There are big differences, though.
- You can branch off of a dynamic root selector.
- You can style child elements from a parent element (all styling in one place instead of spread across multiple elements)
- It empowers you to use BEM modifiers in page builders.
At first glance, it doesn’t seem like that big of a deal, but it’s actually a true “game changer.” It allows us to do stuff like this (from Frames Image Group Kilo):
%root% {
--image-aspect-ratio: 3/4;
--offset: var(--section-space-m);
--image-radius: var(--fr-card-radius);
--caption-font-size: var(--text-s);
--caption-font-color: var(--black-trans-80);
--caption-align: left;
--caption-order: -1; /* 1 = above & 0 = below */
--caption-gap: var(--text-xs);
}
%root%__media {
aspect-ratio: var(--image-aspect-ratio);
}
@media (min-width: 767px) {
%root%__media-wrapper:nth-child(2) {
margin-block-start: var(--offset);
}
}
%root%__media img {
border-radius: var(--image-radius);
}
%root% figure {
display: flex;
flex-direction: column;
gap: var(--caption-gap);
}
%root% .bricks-image-caption {
position: static !important;
color: var(--black-trans-80);
background: transparent;
text-align: var(--caption-align);
padding: 0;
order: var(--caption-order);
}
Code language: CSS (css)
For an image group that needed special offsets, caption styling, etc. we are able to do everything from the parent element (the image group wrapper) while still targeting children properly, adding media queries, targeting nth-children, and more.
The dynamic root selector is also amazing for using pseudo-elements (%root%::before
) and pseudo-classes (%root%:hover
).
Remember, I can fully change the class names, and none of the CSS will break. That’s something you can do in a page builder like Bricks that you can’t even do when you’re hand-coding a site.
If your page builder of choice doesn’t have a dynamic root selector, you’re at a severe disadvantage. This is such an important feature that I’ll never personally use another page builder that doesn’t have this feature.
Note: Some page builders have what appears to be a dynamic root selector (they may even use the “%” nomenclature), but this doesn’t automatically mean they have the same functionality. The real test is: can you branch off the selector and is their root selector compatible with media queries and container queries? Very few page builders offer this.