Generally, if you’d like to rock a 100% full-width (viewport) image from inside a container, additional markup would be required to make it happen.
You’d have to close the container, add your 100% image, then reopen the container. Rinse repeat for each instance.
That’s all well and good, but this becomes a bit of an issue when creating blog post templates / layouts in a CMS like WordPress. Sure, you can write some custom functions to wrap images with the required markup, but honestly, that’s a pain in the ass. Especially if you only want some images or elements to go full-width.
Of course, you could write a js solution to calculate the distances and offsets, then recalc on resize, but that’s also kinda grimey.
No worries playas… there’s a better way – free from extra markup, functions, helpers, or js retardery.
Wait… What’s a Grid-Break Pattern?
Oh, right. Before we get into a solution, we should probably better define the issue. When I say “grid-breaking” pattern, I’m referring to a method of upping the sophistication of your layout game but having certain elements extend outside their parent container. Well suited for blog post designs, a number of content types can benefit form the visual interest this pattern creates – blockquotes, images, captions, etc.
Variations of the pattern include extending content beyond it’s container, completely (full viewport), partially (say 15%), and completely on mobile only. Medium and The Great Discontent both leverage grid-breaks in a masterful manner.
Partial grid-breaking patterns from The Great Discontent and Medium
A full width grid-break as seen on Medium
However, take a peak at the code and you’ll see that instead of a single container class, both sites accomplish their grid-break by wrapping all content into a series of full width blocks. While this certainly does the trick, it also cooks up a steamy bowl of div soup. Wouldn’t it be nice to use a simple, pure css approach that keeps your markup to a minimum?
Hello Viewport Units
Good news. With viewport units, namely viewport width (vw), and a single negative margin declaration, this full-width grid breaking pattern is achievable via a few lines of painless css. Sidebar: despite many a front-end’s affirmation otherwise, negative margins are not hacky, nor bad code. They exist within the box-modal for a reason. John Imbong’s 2009 Smashing Magazine article on a few use cases for negative margins still holds merit today.
The Run Down
So let’s say your centered container is 60% in width. That leaves you with 40% of available space, or a distance of 20% on each side of the container. To make our grid-breaking element go full width, just:
- Apply a
width
&max-width
of100vw
. - Add a
margin-left
of20vw
to account for the 20% distance outside the container (60 + 20 + 20 = 100).
Boom. We’re done son! That’s it.
/*---------------------------------
--Row/Container
-----------------------------------*/
.row{
width: 60%;
margin-left: auto;
margin-right: auto;
}
/*---------------------------------
--Grid Breaker
-----------------------------------*/
.gridbreak-full{
width: 100vw;
max-width: 100vw;
margin-left: -20vw;
}
Pretty Sweet
I know right? No weird hacks, no overflows to hide. No php functions or rails helpers in your CMS. No custom WordPress QTags stuffs. No JS nonsense. No hiding overflow to prevent horizontal scrolling. Just a nice full-width, grid-breaking element.
Why This Works
The secret sauce is the max-width: 100vw
, which takes the content outside it’s container in order to achieve 100 viewport width. With viewport units, 1 vw = 1% of the viewport. While a percentage-based width of 100% would size an element to fill it’s parent, viewports size elements relative to the viewport. As defined in the css relative sizing spec for viewports, “child elements do not inherit the relative values as specified for their parent; they inherit the computed values.”
Hey, but my container changes width at breakpoints?
Calm down dude. Of course it does. Your site would look pretty gross if it didn’t.
Shine on like a cuddle fish playa
But again, no worries. Just rock a few media queries to recalculate the required negative margin. This is where SCSS variables and media query bubbling shines on like a cuddle fish.
/*---------------------------------
--Row/Container
-----------------------------------*/
.row{
width: 90%;
margin-left: auto;
margin-right: auto;
@media (min-width: $mq-small) {
max-width: 80%;
}
@media (min-width: $mq-large) {
max-width: 60%
}
}
/*---------------------------------
--Grid Breaker
-----------------------------------*/
.gridbreak-full{
width: 100vw;
max-width: 100vw;
margin-left: -5vw;
@media (min-width: $mq-small) {
margin-left: -10vw;
}
@media (min-width: $mq-large) {
margin-left: -20vw;
}
}
What About Going Almost Full Width, or Full-Width Only on Mobile?
Sure, easy peasy lemon squeezy. For mobile-only grid-breaking, a margin-left: -5vw
at mobile sizes will do. Just remember to set the max-width: 100vw
to 100%
after your medium breakpoint.
/*---------------------------------
--Grid Break Mobile Only
-----------------------------------*/
.gridbreak-small{
width: 100vw;
max-width: 100vw;
margin-left: -5vw;
@media (min-width: $mq-med){
max-width: 100%;
margin-left: 0;
}
}
For a nice partial grid-break, a max-width: 80vw
, with a margin-left: -10vw
(80 + 10 + 10 = 100) will do it.
/*---------------------------------
--Grid Break Partial
-----------------------------------*/
.gridbreak-med{
@media (min-width: $mq-med){
width: 100vw;
max-width: 80vw;
margin-left: -10vw;
}
}
Support?
Support is actually pretty good. If the browser excepts viewports, you’re ready to ride.
Gotta Demo?
As always. Peep the Demo right here
Gotta a Download?
Of course. Snag the demo files on Github