Techniques I Use in Most Projects
December 29, 2020
Earlier this year, I was reflecting that there are techniques or strategies that I use in almost every project. While this list is not all inclusive, it contains a lot of things that might not be familiar to everyone. I thought I would share my list in hopes that others might learn something new or find a technique that would be helpful in their work.
CSS Grid and Flexbox
Four years ago, I decided to learn about CSS Grid Layout during vacation time I took between Christmas and New Years’. I had bookmarked several articles that Rachel Andrew had written throughout the year that she had shared in her CSS Layout Newsletter. I had also purchased her book, Get Ready for CSS Grid Layout earlier in the year. I decided to take some time to read through it because I knew that CSS Grid would be coming to browsers in 2017.
After reading her book and working through her site, Grid by Example, I felt pretty confident to start using CSS Grid in my work. My first implementation was on a freelance project that was released right before CSS Grid was launched in Firefox and Chrome. I took advantage of feature queries (@supports
) to add it to the project.
I use Grid and Flexbox in every project that I build. A lot of the time I use it in combination using Grid for layout and Flexbox for components within the Grid. I try to hold the principle of using Flexbox for one-dimensional layout (row or column) and using Grid for two-dimensional layouts (rows and columns). This is something I picked up from Rachel Andrew.
Although I do find myself breaking that practice often by using Grid for a row instead of Flexbox. The reason I do it is because of gap
. Flexbox support for the gap
property just made it into Edge and Chrome this past July. Safari still does not support it. And I am still reluctant to use it because there is no way to provide a fallback using @supports
. Unfortunately, because gap
was already supported in Grid, there is no way to check for support in Flexbox. I find it much easier to reach for Grid than to use Flexbox because I have to use margins or width on the Flex items in combination with justify: space-between
.
Smallest Unit in Grid Template is 1fr
When created layouts with CSS Grid, I start with the element with the smallest width and make that 1fr
. Then I divide the width of other columns by the smallest width to come up with the fr
unit for that element, which will always be greater than 1. I have found it easier to keep track of units this way instead of using fractions for the fr
unit.
Responsive Typography
Most of the mockups that I work with are for desktop so I know what the designer wants the font size to be at a certain size. Through experimentation, I will find a size that works well at another viewport width. What responsive typography does is to grow the type consistently between those two points. I use a formula from Mike Riethmuller for creating type that grows with the viewport.
font-size: calc(16px + (24 - 16) * ((100vw - 400px) / (800 - 400)));
Let me break that down for you. In this example, I am wanting my type size to go from 16px to 24px between 400px viewport and 800px viewport.
font-size: calc([smallest font size]px + ([larger font size] - [smaller font size]) * ((100vw - [smaller viewport width]px) / ([larger viewport width] - [smaller viewport width)));
I find this technique helps to have fluid type (or margins or padding) for tablet and smaller desktop screens. I end up using it a lot in hero sections especially for the headings.
For More Information
Horizontal Centering with Padding using calc()
I learned this technique from Lea Verou when I read her book, CSS Secrets (secret #39). She refers to it as “fluid background, fixed content.” The use case for this technique was for sections that had a color background and then the content of the section has a maximum width of the content so that it is fixed inside the section while the space to the left and right of the content is fluid.
The beauty of this technique is that it cuts down on the amount of HTML that I need to write. Before using this technique, I would code something like this:
<section>
<div class="wrapper">
<!-- Text content would go here -->
</div>
</section>
With the accompanying CSS:
section {
background-color: lightblue;
}
.wrapper {
max-width: 660px;
margin: 30px auto;
}
The reason that you need the wrapper is that you are setting the background color on the section and then visually centering the content within the wrapper using margin: auto
. You cannot apply margin: auto
to the section tag because the background-color has to be within the box of the element which does not include margin
and would not show the background-color
in the space that the margin: auto
creates to the right and left of the element.
Understanding what margin: auto
does is helpful in coming up with another solution that cuts down on the amount of HTML code you need to write. The margin produced using margin: auto
is equal to half the viewport width, minus half of our element width of 660px (from the example above). We can use the calc() function to represent the simple math in our CSS code.
margin: 30px calc(50% - 330px);
Now that we understand that, we can use padding
instead of margin
and we no longer need the wrapper around the content.
<section>
<!-- Text content would go here -->
</section>
With the accompanying CSS:
section {
background-color: lightblue;
padding: 30px calc(50% - 330px);
}
Padding
is inside the box of the element, so the background-color
will fill the space to the left and right of the fixed content.
I began using this technique on the project I was building at the time that I read Lea’s book (July 2015) and have used it in every project since that time.
For More Information
- Secret 39 in Lea Verou’s CSS Secrets
- Ahmad Shadeed covers different techniques for styling layout wrappers and mentions this technique late in the article.
filter: drop-shadow
This is a new technique I added over the summer. Of all the techniques on this list, I have used it the least. This property works very much like box-shadow
. But the advantage of this one is that you can apply it to non-rectangular boxes (such as transparent PNG or SVG) images. A box-shadow
added to one of those images would add the shadow to the box of the element. The filter: drop-shadow
property only adds the shadow to the element.
Gone are the days when we have to apply a shadow to the image file. This technique came in handy on a project I built this summer. Our designers like to use Material Design shadows which can be rather big which translated to a bigger image file with dimensions that were bigger than space in the layout. Using the filter: drop-shadow
allowed me to have more precision in the alignment of the image and less file size.
Find Out More about filter: drop-shadow
- Tweet from Josh Comeau that I first learned about this property
- Article from Michelle Barker on CSS (In Real Life)
:not
I cannot remember when I started using this pseudo-class but it has a part of every project that I build. It allows me to target selectors that do not match a list of selectors. I use it most often to target elements that are not the first child of a parent container (:not(:first-child)
). I use this to add a margin to the top of those elements that are not the first child of the container. I have also used it to set link styles for any anchor tag that does not have the class of btn
(a:not(.btn)
), links that have a button appearance.
If you have multiple selectors that you don’t want to match, you have to use one :not
pseudo-class for each target selector you do not want to match.
Example
body:not(.page-enroll):not(.page-credential-month):not(.page-credential-month-thanks):not(.page-id-561) [role=banner]
I used this selector on a project where the header of some new pages did not have the same hero like all the other pages of the site. I was able to exclude these specific pages by using multiple :not
pseudo-classes to target the pages that had the full hero.
unset
I started using the unset
property to reset my CSS properties back to their inherited value. I use it most often in feature queries when I need to override margins or widths in items in a CSS Grid Layout. The advantage of using unset
is that if there is an initial value of the property that it inherits from its parent, I don’t have to know what the value is. I just use unset
. Plus semantically I think it does a good job of communicating what I am doing in my CSS without having to leave comments.
Desktop-first. Then Mobile-First
I am a firm believer in the mobile-first methodology. The idea is that you write styles for smaller screens first and then layer styles for wider screens through media queries. It is one of the tenets of progressive enhancement, which is another methodology that I champion. So in the past, I would always start building a site with mobile styles first and work myself up to the desktop view.
But I have adapted my workflow a bit. Most of the projects I build only have a desktop-view mockup. It is up to me to make decisions about how the design will adapt to smaller screens. I have found that it is easier to make decisions about how the layout needs to adapt to smaller screens by building out the desktop view first according to the design mockup.
My process is to build desktop-first and then to go back and refactor my CSS so that it is mobile-first, layering media queries as the screen get wider. I have found that my layouts come together quicker when building this way. I have fewer decisions to make on the front side of the project. I have also found that I have had more happy accidents occur that I would not have discovered if I built starting with the smallest screen.
Defined Breakpoints
Four years ago, I read an article, The 100% correct way to do CSS breakpoints. I would never prescribe something as definitive as this article title. To be honest, I almost did not read the article because of the title. But I did read the article and one of the things I liked about it was that the author explained why he came to the conclusion that he did.
He examined common devices and came up with a sensible range to define breakpoints. The breakpoints he came up with were 600px, 900px, 1200px, and if needed, 1800px. As I thought about this range, it fits pretty well with the sites that I have developed so I decided to adopt this approach. These are the main breakpoints that I define as variables in my Sass. I still use other breakpoints as needed. I like the approach of finding where the layout breaks or does not seem to work and then create a custom breakpoint.
Sass functions to calculate size values
I still use Sass in my everyday workflow. I mostly like it for variables and nesting. I use very few mixins or functions. But there are a few functions that I do use that I picked up when I was working with Aaron Gustafson years ago. The first function was to convert a pixel value to ems
. I use this function to convert font-size
values to ems
. I always use a base font-size of 100% (16px in desktop browsers). But I still define the default font size in a Sass variable ($browser-default-font-size
) that my Sass function uses.
SCSS that I write:
font-size: px-to-ems(24px);
Sass Function
@function px-to-ems( $pixels, $context: $browser-default-font-size ) {
@return #{$pixels/$context}em;
}
The second function that I use converts other values to ems like margin
and padding
. There is probably an easier way to do this but this helps me to remember the context of what the size is in relation to.
SCSS that I write:
margin: return-ems(12px, 24px) return-ems(16px, 24px);
Sass Function
@function return-ems( $pixels, $context ) {
@return #{$pixels/$context}em;
}
Putting Image Sizes in HTML
One practice that I got away from with the responsive design methodology was to stop defining image size in the HTML. But last year, Chrome and Firefox added some things to the browser that will create the correct space for your image before it loads if you define the width and height of the image. Jen Simmons first made me aware of this. From the time I read that tweet forward, I have been putting the image sizes in the HTML and continued to use height: auto
in combination with width: 100%
(and usually max-width: 100%
) for responsive images.