As we have discussed in many articles on The Foundry, class naming patterns are one of the most pivotal pieces to coherent CSS architecture. Some years ago we tried developing our own naming conventions, but trial and error led us to see the value and strengths of the BEM naming convention. Today, we’ve wholly adopted Harry Roberts’ BEMIT approach, which combines the BEM naming convention with the Inverted Triangle CSS organization method. In that article, Roberts’ briefly mentions responsive suffixes as a way to create classes scoped to a media query value. Creating media query scoped classes isn’t new, but Roberts’ approach provides a highly visual indicator that we found to coincide with our ideals of good class naming.
A responsive suffix is an identifier appended to an established class name with properties scoped to a media query, e.g. .my-class@large
. This allows us to have a class that adds a margin-top: 1rem
scoped to occur at a specific screen width. We can then create a system of classes that allow us to apply changes to elements at various sizes, shifting the margin-top
of that element from 0
to 2rem
then to 4rem
as the size of the screen changes.
Getting Started with Responsive Suffixes
The idea of responsive classes is not new or unique to the suffix approach. Bootstrap has had this built into the framework for years. However, the class naming approach in Bootstrap buries the identifier for a responsive class in the middle of the class name, which is not easily discernible (e.g. .d-sm-block
is the class used to define display: block
at the small breakpoint). With the responsive suffix approach, the breakpoint portion of the class is always at the end. Additionally, the at symbol (@
) indicates that it is a media query breakpoint (e.g. .display-block@sm
is a utility class that applies a display: block style when the screen width hits the small breakpoint).
While class names are often created by CSS authors, they’re used most by HTML writers. HTML writers range in skillsets from content authors to programmers. Ideal class names are
Clear in their function
Identifiable in the class attribute’s space-separated list
Consistent in their structure
Comprehensible to someone who doesn’t know CSS
The responsive suffix approach hits all four of these ideals, and so much of that work is done by the @. The @ sign makes the function clear since in CSS the @ is most commonly used for media queries–the heart of responsive design. These classes are clearly identifiable in a space-separated list, thanks to the visual difference of the @ symbol. The structure is consistent as it typically starts with an established class name with an @ and abbreviated size name. Due to the abbreviated size names being fairly common, a pattern can be identified and comprehended by those who don’t know CSS.
Automated Classes with Sass Mixins and Maps
The pattern for a responsive suffix class name has a predictable and consistent structure–which is a terrific opportunity for automation. Sass provides tools to quickly create a myriad of classes based on the parameters of our primary breakpoints found in the responsive suffixes.
Breakpoint Map
Start automating with a Sass map. If you are unfamiliar with Sass maps, they are a key value pair set. For our uses, the map is called $breakpoints
, and we have four primary breakpoints that will be used to determine our breakpoint suffixes. These keys will be used as the suffixes, and the value will define the media query breakpoint.
$breakpoints: (
'sm': 30rem,
'md': 52rem,
'lg': 68rem,
'xl': 84rem
);
Loop Mixin
Our mixin does not accept any parameters and utilizes the mixin as a selector block, which means we pass in properties via the @content
block. During the first instance the mixin is used, the properties are immediately printed out. Then our map is put into play with the @each
rule, which loops over every key value pair in the $breakpoint
map. This creates each media query using the value, which is our screen width size with a unit of measure. Then the original class name is passed into the media query block with the ampersand symbol (&
). The ampersand is followed by a backslash. Note that the backslash is a CSS requirement to escape the @
sign so it can be used in a class name. Next, the $key
is selected from the map to finish generating the class name with a responsive suffix. Finally, the same styles are dropped into the @content
block again. This loop repeats until each key value pair in the map is read.
@mixin loop-mq {
@content;
@each $key, $value in $breakpoints {
@media (min-width: #{$value}) {
&\@#{$key} {
@content;
}
}
}
}
Using the Loop Mixin
The mixin is used as a content block and can either wrap a group of selectors or be nested within a selector. When creating utility classes that modify the same property with different values, you must put the related classes inside the mixin. Otherwise, the output will run into a cascade issue, preventing properties from being changed depending on the order of the selectors. In our example below, two utility classes are focused on the display property, both wrapped inside our loop-mq
mixin.
@include loop-mq {
.display-inline {
display: inline;
}
.display-block {
display: block;
}
}
Those 8 lines of Sass output several classes that we can now use in our HTML to modify elements and adjust with the screen size.
.display-inline {
display: inline;
}
.display-block {
display: block;
}
@media (min-width: 30rem) {
.display-inline\@sm {
display: inline;
}
.display-block\@sm {
display: block;
}
}
@media (min-width: 52rem) {
.display-inline\@md {
display: inline;
}
.display-block\@md {
display: block;
}
}
@media (min-width: 68rem) {
.display-inline\@lg {
display: inline;
}
.display-block\@lg {
display: block;
}
}
@media (min-width: 84rem) {
.display-inline\@xl {
display: inline;
}
.display-block\@xl {
display: block;
}
}
Using the Classes
Now that we have our classes generated, we can hop over to the HTML to start using these new utilities. Here’s our scenario: we need to have an element be inline on a small screen and then be a block at a larger breakpoint. The classes without a responsive suffix will work regardless of screen size. These classes are our base styles. We’ll start with display-inline
to define the element as display: inline
. Next, we’ll add the display-block@lg
class, which will apply a display: block
style to the element once the screen reaches 68rem
(1088px
). We can add further utility classes with and without suffixes to quickly piece together a layout or design that morphs with the device the website is viewed from.
<div class="display-inline display-block@lg">
Bonus: Print Media Queries!
With some modifications to the loop-mq mixin, we can optimize a page for printing. Adding in a print
query can come in very handy if you need to adjust spacing or remove an element. For the map, all we need to do is add a new key of print
. We don’t need to set the value, as it won’t be needed.
$breakpoints: (
'sm': 30rem,
'md': 52rem,
'lg': 68rem,
'xl': 84rem,
'print'
);
The structure of a print media query is much different than a screen width query. Therefore, we have to make a special exception for the print
key in our map, using a conditional to choose when to use the correct format. We start by checking that the $key
does not equal print and does not print out the screen-width queries first. This allows the loop to work as before until it hits print in the map. Once the loop comes to the print key, the code will jump down to the @else
block. Here, the print query is defined, the class is appended with a @print
suffix, and the properties are then added.
@mixin loop-mq {
@content;
@each $key, $val in $grid-breakpoints {
@if $key != 'print' {
@media (min-width: #{$val}) {
&\@#{$key} {
@content;
}
}
}
@else {
@media print {
&\@print {
@content
}
}
}
}
}
This can be especially handy for hiding page elements that don’t make sense in the printed format. Examples of this are navigation, the site footer, and maybe sidebar content as well. Taking this further and applying this concept to a grid system would allow changing the layout for an even more optimized print layout.
<div class="display-inline display-block@lg display-none@print">
Sufficient Suffixes
The big drawback that I’m sure some developers will see is that this potentially increases the classes on an element. This is certainly true, though I find the benefits to be a fair trade-off. Additionally, this does not negate the need for creating custom component classes. Always be on the lookout for often repeating groupings of utility classes: they might be better served as a component class. Responsive suffixes expand on the rapid development that utility classes already afford. They allow us to adjust our website designs quickly and can be automated to limit the amount of code written. The loop-mq mixin
and responsive suffixes have been helping Sparkbox make responsive utility systems for several years. We hope they help you on your next project as well.
Sparkbox’s Development Capabilities Assessment
Struggle to deliver quality software sustainably for the business? Give your development organization research-backed direction on improving practices. Simply answer a few questions to generate a customized, confidential report addressing your challenges.