Recently, I’ve been using (and loving) the new Gutenberg editor in WordPress 5.0+. It’s a huge step forward in both what developers can offer, and what users can expect out of their content creation experience.
One of the new features of Gutenberg that I particularly enjoy is the ability to set an image as either “wide width” or “full width,” to allow it to break out of its container element in order to span a greater width of the screen.
Here’s a visual example of what I mean:
Ordinarily, an image would be constrained to the content width (visualized by the dotted lines in the image above). Being able to allow images to break out of those confines is a powerful layout tool, as it allows content authors to add a great deal of visual interest and hierarchy to any page, post, or content supported by the new Gutenberg editor!
Adding Theme Support
Adding support for wide- and full-width images is up to the theme developer. Fortunately, from the backend, it’s dead simple; just add this line to the theme’s functions.php file (please be sure to use a child theme as appropriate):
add_theme_support( 'align-wide' );
That tidy little snippet will make two new options available for image blocks in the Gutenberg editor, in addition to the usual options: “wide width” and “full width,” highlighted in the image below:
When the user chooses either of these options, the <figure> element that appears on the front-end of the site (oh yeah—by default, Gutenberg puts images inside <figure> elements, so that captions can be added easily. Anyway, that element, i.e., the image’s container) will have either an alignwide or alignfull class applied to it (depending, of course, on which was selected by the content author).
That’s it for the PHP/back-end setup. Other than the snippet above, everything we’ve covered so far is fully automatic and just handled by WordPress for us.
However, we still need to actually implement these layout techniques on the front-end of the site, using our theme’s CSS. Otherwise, nothing will happen visually when a content author chooses the full-width or wide-with image option.
Front-End CSS for Full-Width Images
I wanted to write this post mainly to share one technique that I came across online, which I feel is particularly clever in this situation (and which is not at all exclusive to Gutenberg or WordPress):
Even though that bit of CSS above is very brief (only two properties!), I still want to be sure we cover what it’s doing, because it’s a pretty elegant solution for our needs.
The width property is pretty straightforward: a value of 100vw ensures that the image is always exactly as wide as the viewport, no matter what size that might be. (Remember, width: 100% might not work here, because percentages are based on the width of the parent element, not the screen, and our image’s parent element may or may not be as wide as the viewport.)
However, making the image 100vw wide on its own doesn’t do us much good on its own, because it would overflow the screen, as shown in this image:
That brings us to the margin property, which is the clever part. This is where the real CSS magic happens:
margin-left: calc(50% - 50vw);
In case you’re new to the calc function, in essence, it lets you do math to set CSS values. It’s most commonly used in responsive design to, say, let your image take up a quarter of the available space, minus an 8px margin (which would be width: calc(25% - 8px);).
But calc has many other uses, and can crunch numbers on any dynamic or static values, even between two different units of measurement (as in the previous example, to subtract pixels from a percentage).
Back to our fullwidth image: in order to make the image the full width of the screen and position it properly, we want to set a negative margin. And as you’ve probably guessed, we’ll need calc to help us, because the distance between the side of our container and the left edge of the screen is responsive, and always changing.
So how do we determine how far the image needs to shift to the left? Answer: we don’t. 😎
Instead, we’re going to send our image halfway to the right. That’s the 50% portion of our calc formula:
Now we can begin to see the full picture (no pun intended)!
Since percentage values are calculated based on the parent element’s width, a margin of 50% sends the image exactly halfway across the parent element. And since our parent element is already centered on the screen, that means our image is now exactly halfway across the viewport, no matter how wide the viewport is!
Now that our image’s left side is directly in the center of the screen, the rest is just subtracting50vw from the left margin—which is the other half of our calculation. Thus, calc(50% - 50vw) gives us exactly the full-width image we’re looking for!
There’s one small issue here, which is: we don’t take into account the possibility that our .alignfull element might already have a right margin. If it does, it will actually be taking up more than the full width of the screen, and that’s no good.
Plus, we probably want space above and below our fullwidth image, just to make it stand out a little more. So really, instead of setting just a margin-left property, we’d most likely be better off setting all four sides at once:
margin: 2rem calc(50% - 50vw);
This way, we’ve made sure all four sides of our image are accounted for while also giving the image a little breathing room.
And if you’re wondering (or just wanting to get super technical): yes, this does mean that both sides of the image get brought in by 50%, then are each pulled back out 50vw. If you didn’t have the - 50vw part of the CSS above, the image would effectively be 0% wide (since it would have a margin of 50% on both sides). Interesting! 🤓
Lastly, as you probably realized: this post assumes the content container is already centered on the screen. If your content is not already centered in the viewport, this specific CSS won’t work for you, and you’ll need to do something a little more creative to get your images full-width.
Front-End CSS for Wide-Width Images
Wide-width images work similarly to the above, but naturally, we don’t want to make them the full width of the screen; otherwise, there would be no difference between wide-width and full-width (and that, of course, would just be silly).
How wide the image should be, exactly, as well as how to achieve the effect, is ultimately up to the theme author. However, I find something like this bit of CSS works quite well:
You might notice that in this case, I chose not to use negative margin, and instead, opted for a negative value on the left property (paired with relative positioning). Why’s that, and what’s the difference?
For the “why,” it’s mainly because: I wanted to illustrate that there’s more than one technique available here.
As for the difference…well, to be honest, which works better will probably depend on your use case, and the environment you’re working in. None of this CSS exists in a vacuum (hopefully).
If your images already have a side margin, then overriding that with a negative margin will probably work better (or, alternatively, you could just be aware that you may need to remove the side margin if you’re utilizing relative positioning).
There are undoubtedly posts written on the advantages and disadvantages of both techniques, and I don’t feel the need to retread that ground here. Some developers avoid negative margins like the plague; I think they’re fine in a situation like this, and as long as you’re not just using them to avoid changing a different part of the CSS, or as a hacky way to get around something that should just be fixed on its own.
Another note here: unless you’re ok with your wide-width images bleeding off the page at smaller screen sizes, you’ll need to either use a media query, and/or replace the 10vw with a value that doesn’t exceed the side padding/margin around your main content container.
(For example: if your main content container element, whatever that may be, has a padding or margin of 32px on each side, you’d want to make sure your .alignwide class had a width of no greater than calc(100% + 64px)).
I eventually landed on something like this for my personal use on wide-width images; they’re fullscreen up to a certain screen size (since they may as well be on mobile), then differentiate themselves starting at a certain @media breakpoint (likely the same one, or just above, where your content container element stops expanding and centers itself at a static width instead):
The usefulness of CSS variables should be fairly apparent if you’ve managed any sizable stylesheet before. If you have, you probably already know how untidy it can be at large scale. In fact, that’s one of the biggest knocks against CSS; it’s very easy for a stylesheet to balloon, making updates difficult as you’re forced to search through hundreds (or thousands) of lines of code to make changes.
Fortunately for us, browsers are always adapting newer and better ways of doing things, and so we get an awesome, fairly new feature called CSS variables!
(Pedantic side note: technically, these are called “custom properties.” But that’s boring, not as clear, and honestly a less common name than CSS variables. So I’m gonna stick with the latter.)
The Old Way
To demonstrate what CSS variables are good for, let’s take a common example: you’re managing a robust stylesheet for a client, and their brand color is used all over the place. It’s in buttons, borders, backgrounds, text colors, and all kinds of other places, something like this:
And so on and so on. Eventually, though, your client decides that this is not the proper color, or rebrands, or for whatever other reason, this color needs to change and be updated everywhere it exists on the website.
That’s obviously a huge pain, because you’ve got to do a large-scale find-and-replace now. With some text editor know-how, it’s not too big a deal, but things can be missed or even changed when they weren’t supposed to be if you’re not careful, especially when dealing with multiple stylesheets (or, *shudder*, CSS outside of stylesheets).
Fortunately for us, this is the black-and-white part of the infomercial where the poor, hapless CSS author says “there’s got to be a better way,” and the announcer cheerfully replies, “well, now there is!” as the world bursts into color. Enter CSS variables!
CSS Variable Basics
Rather than using the same value over and over again (making it tough to manage and update your stylesheet), a CSS variable allows you to simply set a name for any given value. Then, whenever you want to use that value (in this case, our specific color), you put the name in your stylesheet, rather than the actual hex code. The name is essentially an alias or placeholder for the color; a reference back to the original setting.
Then, if you ever want to change the value, you only need to update it in one location; everywhere else updates automatically!
But instead of talking about it, let me show you how you might use it:
Whoa! That might look like a lot of new syntax, depending on your current familiarity with CSS. And some of it is brand new, so let’s break it down piece by piece, starting at the top.
Putting Together the Pieces of CSS Variable Syntax
You might not have used the :root CSS pseudo-class before, but it refers to the topmost element in the HTML document. In a webpage, this will always be the <html> element, and in fact, the :root selector is pretty much the exact same as the html selector. (The only difference, for those curious, is that :root is slightly more specific. So if you used both selectors, the styles applied to :root would take precedence.)
That explains what:root is, but not why. Why are we putting variables in a rule targeting the :root? Turns out, there’s a very good reason for this, and it is: the cascade.
Remember, in CSS, everything trickles down the cascade, and elements inherit properties from their parent and ancestor elements. So the reason we define CSS variables inside the :root selector is that we want them to cascade down, and be “known” to every other element in the document to use as needed.
In other words: applying a style to the :root means it gets “passed down” to every other element in the document. This wouldn’t be the case if we applied CSS variables to, say, a random <div>. Elements inside that <div> would know about the variables and could use them, but no elements outside would. So it makes the most sense to apply CSS variables to the :root pseudo-class, since everything is inside of the root tag, which is <html>.
In the example above, I’ve named my CSS variable “brand-yellow,” but there’s nothing special about those words. You can actually name your CSS variables anything you want to! (I’d recommend something intuitive, though, so that when you or anybody else comes across the variable in a CSS file, its name will confer its value and purpose. Variable names like --myVariable or --x aren’t very helpful or descriptive.)
The only special part is the double dashes (--) before the variable name. Browsers have decided that these dashes are how we must name our variables, to indicate that they are different than normal CSS properties.
So you could name your variable something like --myYellow or --brand-orange or --em or anything you want!
And by the way: variables can be anything, not just colors!
If you have a particular unit of measurement you’re using over and over again—say, for example, 16px—you could set a CSS variable for it, and use it anywhere you need!
And so on. Anything that can be a CSS value can be a CSS variable! So if you’re repeating it often, it may be worth setting a variable for it. That way, if you decide to change all of those instances—if 16px needed to change to 18px, for example—you only need to make the change in one place!
Those of you who have worked in pretty much any common programming language will recognize that var() is a function. (And for those of you who aren’t familiar with functions, don’t worry: this one’s very easy to use.)
As you probably guessed, “var” is short for “variable,” and the var() function is how you actually use those values you set up in the :root element. Just insert the var() function, and put the name of whichever variable you’d like to use inside the parentheses. Easy as that!
Once more, let’s have a look at the whole thing put all together in a new example:
In the above example, we’ve got a --base-size variable set to 18px, and our <p> elements will use it as both their font-size and their bottom margin. Plus, it will be the padding measure used by our <header> element. And if we ever decide that’s too much or too little, all we need to do is update the value of the variable where it’s declared in the :root, and all changes will be made together quickly and neatly!
A Couple of Fancy CSS Variable Tricks
Using CSS Variables with calc()
You might be familiar with another of CSS’s (few) functions, calc(). The calc() function (short, fairly obviously, for “calculation”) allows you to have CSS do math that would otherwise be impossible in the language. Here’s a basic example of calc() in action:
width: calc(100% - 32px);
That bit of CSS sets elements with the .container class to be 100% wide, but then subtracts 32px from whatever that total may be (probably to account for 16 pixels of padding or margin on each side of the element).
Mixing units of measurement like this—units such as % and px (or even vw or vh)—is one of the things calc() is really useful for.
But what does this have to do with CSS variables? Get excited: we can do a little CSS function inception to use CSS variables inside of a calc() function!
Nifty, huh? By using calc( var(--base-unit) * 1.2), we’ve had CSS take our --base-unit variable (which, remember, is 16px) and multiply it by 1.2—resulting in a font-size of roughly 19px. The padding is 1.5 times our --base-unit variable, resulting in a value of 24px, and the bottom margin is the variable divided by two, thus, 8px.
Are you excited? I’m excited.
Redefining CSS Variables with Media Queries
Let’s keep using the example above; 16px might be a suitable unit of measurement for some screens, but we might want it to grow or shrink depending on the screen size. Easy! Just use a media query:
You can’t tell me that’s not cool (and much easier than updating each of those values individually at every breakpoint)!
As with any new feature, browser support is key. Fortunately, as of this writing, there’s very little to be wary about as far as using CSS variables right away; the only major browser without support is Internet Explorer 11 (and lower):
Global support is near 90%, with IE11 and Opera Mini (which seems to have many gaps in support) making up the vast majority of the remaining 10%.
Right now, I personally wouldn’t hesitate to use CSS variables in production; that’s hefty support. But it will depend on your site’s users. If some are likely to be on IE11, I’d definitely recommend using fallback values for custom properties, like so: