20 Tips For Writing Modern CSS
In this post we want to share with you a collection of 20 useful conventions and best practices that are recommend by the CSS community. Some are tailored more towards beginners, and some are a bit advanced, but we hope everyone will find a cool trick they didn't know about. Enjoy!
1. Beware of Margin Collapse
Unlike most other properties, vertical margins collapse when they meet. What this means is that when the bottom margin of one element touches the top margin of another, only the bigger of the two survives. Here is a simple example:
.square { width: 80px; height: 80px; } .red { background-color: #F44336; margin-bottom: 40px; } .blue { background-color: #2196F3; margin-top: 30px; }
<div class="square red"></div> <div class="square blue"></div>
Instead of 70px between the red and blue square we have only 40px, the margin of the blue square isn't taken into consideration at all. There are ways to battle this behavior, but it's better to just work with it and use margins only going in one direction, preferably margin-bottom
.
2. Use Flexbox For Layouts
The flexbox model exists for a reason. Floats and inline-blocks work, but they are all essentially tools for styling documents, not websites. Flexbox on the other hand is specifically designed to make it easy to create any layout exactly the way it was envisioned.
The set of properties that come with the flexbox model give developers lots of flexibility (no pun intended), and once you get used to them, doing any responsive layout is a piece of cake. Browser support nowadays is almost perfect, so there shouldn't be anything stopping you from going full flexbox.
.container { display: flex; /* Don't forget to add prefixes for Safari */ display: -webkit-flex; }
We've featured a number of tips and trick with flexbox before on Tutorialzine. You can check them out here: 5 Flexbox Techniques You Need to Know About.
3. Do a CSS Reset
Although the situation has greatly improved over the years, there is still plenty of variation in the way different browsers behave. The best way to resolve this issue is to apply a CSS reset that sets universal default values for all elements, allowing you to start working on a clean style sheet that will yield the same result everywhere.
There are libraries like normalize.css, minireset, and ress that do this very well, correcting all imaginable browser inconsistencies. If you don't want to use a library, you can do a very basic CSS reset yourself with these styles:
* { margin: 0; padding: 0; box-sizing: border-box; }
This may seem a bit harsh, but nullifying margins and paddings actually makes laying out elements much easier as there are no default spaces between them to take into account. The box-sizing: border-box;
property is another good default, which we will talk about more in our next tip.
4. Border-box for All
Most beginners don't know about the box-sizing
property but it's actually quite important. The best way to understand what it does is to look at it's two possible values:
content-box
(default) - When we set a width/hight to an element, that's just the size for it's content. All paddings and borders are on top of that. E.g. a<div>
has a width of 100 and padding of 10, our element will take up 120 pixels (100 + 2*10).border-box
- The padding and border are included in the width/height. A<div>
withwidth: 100px;
andbox-sizing: border-box;
will be 100 pixels wide no matter what paddings or borders are added.
Setting border-box to all elements makes it so much easier to style everything, since you don't have to do math all the time.
5. Images as Background
When adding images to your design, especially if it's going to be responsive, use a <div>
tag with the background
CSS property instead of <img>
elements.
This may seem like more work for nothing, but it actually makes it much easier to style images properly, keeping their original size and aspect-ratio, thanks to background-size
, background-position
, and other properties.
img { width: 300px; height: 200px; } div { width: 300px; height: 200px; background: url('https://blog.daitra.xyz/media/2016/08/bicycle.jpg'); background-position: center center; background-size: cover; } section{ float: left; margin: 15px; }
<section> <p>Img element</p> <img src="https://blog.daitra.xyz/media/2016/08/bicycle.jpg" alt="bicycle"> </section> <section> <p>Div with background image</p> <div></div> </section>
A drawback of this technique is that the web accessibility of your page will take a slight hit, as images won't be crawled properly by screen readers and search engines. This issue can be resolved by the awesome object-fit but it doesn't have full browser support yet.
6. Better Table Borders
Tables in HTML are not fun. They are quirky, almost impossible to be made responsive, and overall difficult to style. For example, if you want to add simple borders to your table and its cells, you will most probably end up with this:
table { width: 600px; border: 1px solid #505050; margin-bottom: 15px; color:#505050; } td{ border: 1px solid #505050; padding: 10px; }
<table> <thead> <tr> <th >Title</th> <th >Description</th> </tr> </thead> <tbody> <tr> <td><a href="https://blog.daitra.xyz/2016/07/take-a-selfie-with-js/" target="_blank">Take a Selfie With JavaScript</a></td> <td>A quick tutorial that covers a pure-JavaScript way to take photos directly in the browser using various native APIs and interesting JS techniques.</td> </tr> <tr> <td><a href="https://blog.daitra.xyz/2016/08/20-awesome-php-libraries-for-summer-2016/" target="_blank">20 Awesome PHP Libraries</a></td> <td>A handcrafted collection of 20 open-source libraries containing some of the most useful and top-quality PHP resources.</td> </tr> </tbody> </table>
As you can see, there are quite a lot of repeating borders everywhere and it doesn't look good. Here is a quick, hack-free way to remove all doubling borders: simply add border-collapse: collapse;
to the table.
table { width: 600px; border: 1px solid #505050; margin-bottom: 15px; color: #505050; border-collapse: collapse; } td{ border: 1px solid #505050; padding: 10px; }
<table> <thead> <tr> <th >Title</th> <th >Description</th> </tr> </thead> <tbody> <tr> <td><a href="https://blog.daitra.xyz/2016/07/take-a-selfie-with-js/" target="_blank">Take a Selfie With JavaScript</a></td> <td>A quick tutorial that covers a pure-JavaScript way to take photos directly in the browser using various native APIs and interesting JS techniques.</td> </tr> <tr> <td><a href="https://blog.daitra.xyz/2016/08/20-awesome-php-libraries-for-summer-2016/" target="_blank">20 Awesome PHP Libraries</a></td> <td>A handcrafted collection of 20 open-source libraries containing some of the most useful and top-quality PHP resources.</td> </tr> </tbody> </table>
Much better!
7. Write Better Comments
CSS might not be a programming language but it's code still needs to be documented. Some simple comments are all it takes to organize a style sheet and make it more accessible to your colleagues or your future self.
For larger sections of the CSS such as major components or media-queries, use a stylized comment and leave a couple of new lines after:
/*--------------- #Header ---------------*/ header { } header nav { } /*--------------- #Slideshow ---------------*/ .slideshow { }
Details in the design or less important components can be marked with a single-line comment.
/* Footer Buttons */ .footer button { } .footer button:hover { }
Also, remember that CSS doesn't have single line //
comments, so when commenting something out you still need to use the / /
syntax.
/* Do */ p { padding: 15px; /*border: 1px solid #222;*/ } /* Don't */ p { padding: 15px; // border: 1px solid #222; }
8. Everyone Loves kebab-case
Class names and ids should be written with a hyphen (-) when they contain more then one word. CSS is case-insensitive so camelCase is not an option. A long time ago, underscores used to not be supported (they are now) which made dashes the default convention.
/* Do */ .footer-column-left { } /* Don't */ .footerColumnLeft { } .footer_column_left { }
When it comes to naming, you may also consider BEM, which follows a set of principles that add consistency and provide a component-based approach to development. You can read more about it in this excellent CSS-Tricks article.
9. Don't Repeat Yourself
The values for most CSS properties are inherited from the element one level up in the DOM tree, hence the name Cascading Style Sheets. Let's take the font
property for example - it is almost always inherited from the parent, you don't have to set it again separately for each and every element on the page.
Simply add the font styles that will be most prevalent in your design to the <html>
or <body>
element and let them trickle down. Here are some good defaults:
html { font: normal 16px/1.4 sans-serif; }
Later on you can always change the styles for any given element. What we are saying is just to avoid repetition and use inheritance as much as possible.
10. CSS Animations with transform
Don't animate elements by directly changing their width
and height
, or left/top/bottom/right
. It's preferred to use the transform()
property as it provides smoother transitions and makes your intentions easier to understand when reading the code.
Here's an example. We want to animate a ball and slide it out to the right. Instead of changing the value of left
, it's better to use translateX():
.ball { left: 50px; transition: 0.4s ease-out; } /* Not Cool*/ .ball.slide-out { left: 500px; } /* Cool*/ .ball.slide-out { transform: translateX(450px); }
Transform, as well as all of its many functions (translate
, rotate
, scale
, etc.) have almost universal browser compatibility and can be used freely.
11. Don't DIY, Use A Library
The CSS community is enormous and there are constantly new libraries coming out. They serve all kinds of purposes, from tiny snippets to full-blown frameworks for building responsive apps. Most of them are open-source too.
Next time you are faced with a CSS problem, before you try to tackle it with all your might and hacks, check if there isn't already a solution available on GitHub or CodePen.
12. Keep Selector Specificity Low
Not all CSS selectors are created equal. When novice developers write CSS they usually expect that selectors will always overwrite everything above them. However, this isn't always the case, as we've illustrated in the following example:
a{ color: #fff; padding: 15px; } a#blue-btn { background-color: blue; } a.active { background-color: red; }
<a href='#' id='blue-btn' class="active">Active Button </a>
We want to be able to add the .active
class to any button and make it red. This won't work here because our button has it's background-color
set with an ID selector, which has a higher selector specificity. The rule goes like this:
ID (#id
) > Class (.class
) > Type (e.g. header
)
Specifity also stacks so a#button.active
ranks higher than a#button
. Using selectors with high specificity will cause you to constantly trump old selectors with even higher ones and eventually result in !important
. This leads us into our next tip:
13. Don't Use !important
Seriously, don't. What is a quick fix now may end up causing lots of rewrites in the future. Instead, find why your CSS selector isn't working and change it.
The only time when it's acceptable to !important
CSS rules is when you want to override inline styles from the HTML, which in itself is another bad practice to be avoided.
14. Caps Lock For Meaning, text-transform
For Style
In the HTML, write upper case letters when you want to use them for their intended semantic meaning, like when you want to emphasize the importance of a word.
<h3>Employees MUST wear a helmet!</h3>
If you need to have some text in all caps for stylistic reasons, write the text normally in the HTML, and transform it to all-caps with CSS. It will look the same but your content will make more sense if taken out of context.
<div class="movie-poster">Star Wars: The Force Awakens</div>
.movie-poster { text-transform: uppercase; }
The same goes for lowercasing and capitalizing strings - text-transform handles those just as well.
15. Em, Rem, and Pixel
There is a lot of debate whether people should use em, rem, or px values for setting the size of elements and text. Truth is, all three options are viable and have their pros and cons.
All developers and projects are different, so there can't be any strict rules on when to use which. Here are, however, some tips and general good practices for each unit:
- em - The value of 1 em is relative to the
font-size
of the direct parent. Often used in media-queries, em is great for responsiveness, but it can get really confusing tracing back the exchange rate of ems to pixels for each element (1.25em of 1.4em of 16px = ?). - rem - Relative to the font-size of the
<html>
element, rem makes it really easy to scale all headings and paragraphs on the page. Leaving the<html>
with it's default fontsize and setting everything else with rem is a great approach accessibility-wise. - px - Pixels give you the most precision but don't offer any scaling when used in responsive designs. They are reliable, easy to understand, and present a good visual connection between value and actual result (15px is close, maybe just a pixel or two more).
Bottom line is, don't be afraid to experiment, try them all and see what you like best. Sometimes em and rem can save you a lot of work, especially when building responsive pages.
16. Use a Preprocessor on Large Projects
You've heard about them - Sass, Less, PostCSS, Stylus. Preprocessors are the next step in the evolution of CSS. They provide features such as variables, CSS functions, selector nesting, and lots of other cool stuff, making CSS code easier to manage, especially in large projects.
For a quick example, here is a snippet of using CSS variables and functions directly in a style sheet with Sass:
$accent-color: #2196F3; a { padding: 10px 15px; background-color: $accent-color; } a:hover { background-color: darken($accent-color,10%); }
The only real drawback of preprocessors is that they need compiling to vanilla CSS, but if you are already using a build script in your project this shouldn't be too much of a hassle.
To learn more about preprocessors, check out our tutorials on two of the most popular systems - Sass and Less.
17. Autoprefixers For Better Compatibility
Writing browser-specific prefixes is one of the most annoying things in CSS. They aren't consistent, you never know exactly which ones you need, and if you do the actual process of placing them in your style sheet is a boring nightmare.
Thankfully, there are tools that automatically do that for you and will even let you decide which browsers you need supported:
- Online tools: Autoprefixer
- Text editor plugins: Sublime Text, Atom
- Libraries: Autoprefixer (PostCSS)
18. Use Minified Code In Production
To improve the page load of your websites and apps you should always use minified resources. The minified version of your code will have all whitespace and repetitions removed, reducing the total file size. Of course, this process also makes style sheets completely unreadable so always keep a .min version for production and a regular version for development.
There are many different ways to minify CSS code:
- Online tools - CSS Minifier (API included), CSS Compressor
- Text editor plugins: Sublime Text, Atom
- Libraries: Minfiy (PHP), CSSO and CSSNano (PostCSS, Grunt, Gulp)
Depending on your workflow, any of the above options can be used, but it's recommended to automate the process in one way or another.
19. Caniuse Is Your Friend
The different web browsers still have lots of compatibility inconsistencies. Use caniuse or a similar service to check if what you are using is widely supported, if it needs prefixes, or if it causes any bugs in a certain platform.
Just checking caniuse isn't enough though. You also need to do tests (either manually or through a service) as sometimes layouts break for no obvious reasons. Knowing the preferred browsers of your userbase also helps a lot, since you can see where good support is most crucial.
20. Validate
Validating CSS might not be as important as validating HTML or JavaScript code, but running your code through a CSS Linter can still be very helpful. It will tell you if you've made any mistakes, warn you about bad practices, and give you general tips for improving the code.
Just like minfiers and autoprefixers, there are plenty of free validators available:
- Online tools: W3 Validator, CSS Lint
- Text editor plugins: Sublime Text, Atom
- Libraries: stylelint (Node.js, PostCSS), css-validator (Node.js)
Bootstrap Studio
The revolutionary web design tool for creating responsive websites and apps.
Learn more
I disagree with #14. If we really want to go with semantics, something needing emphasis ought to be surrounded with <em> tags. Then, if the desired way to emphasize it happens to be making it uppercase, the em tag can be styled using CSS to make it uppercase and remove the default italicization.
RE: "The only time when it’s acceptable to !important CSS rules is when you want to override inline styles from the HTML, which in itself is another bad practice to be avoided."
There may be another case when it is acceptable... when a WordPress plugin sets styles, it is better to override in css, than to mess with the plugin code and rewrite everytime the plugin updates.
Same goes for some WP included styles.
8: CSS class name is Case sensitive. While CSS properties are case insensitive
TNX so much, Danny!
I always enjoy your works!
Regards,
Robbie
PS: Do you happen to think about writing a React post?
Thanks for the kind words Robbie :)
Sorry, I don't have any ideas for React tutorials at the moment, if you have any feel free to share!
Thanks for the great sum-up!
However, I disagree with #13. There were times when I thought it's bad to use !important, but I changed my mind, here are some of the reasons why: http://csswizardry.com/2016/05/the-importance-of-important/
Thanks for the comment, Kalo!
The article you've shared brings up a very solid point. Adding
!important
to utility classes will make sure they are always applied properly. I see how this can be a a good reason to break the rule.What about CSSModules and camelCase usage? When I develop a react application I use smth like <div className={s.quoteWrapper}>...</div>, and it feels more natural to use camelCase everywhere, when I integrate CSSModules in my project
Thank you, very nice list and all are very good points.
Ty man you really helped me <3
I think you should only use images as background if they are only part of the design of the website (e.g., like they are actually background images or some design aspect), and not part of the content (e.g., a figure image).
Thanks for the comment Frank, that's a fair point!
Thank you for your tips!