As a frontend developer, designer, and mentor at Thinkful, I talk with junior web developers on a daily basis. I see their struggles, inspect their portfolio sites, and am always on the lookout of how to improve their understanding of CSS.
In this post, I want to outline the most common issues junior frontend devs run into when building a responsive site on their own. The two major lessons that I’m skipping in this article are various CSS resets like normalize.css
and the box-sizing border-box * { box-sizing: border-box; }
. If these passing mentions aren’t familiar to you, I’d recommend reading about normalize here and about border-box here.
Without further ado, here are the 5 most pervasive mistakes I see early developers making.
1. Adding “responsiveness” to the content, rather than the container
One of the key problems I see on a daily basis is folks adding responsiveness to each piece of content of their site separately. This content is then shuffled in order right into the <body>
tag. This quite often leads to inconsistent edges on the left and right hand side of the page, with content occasionally aligning (maybe on the developer's normal screen size) and falling out of alignment at other sizes. On mobile, these sites either have huge %-based paddings, horizontal scroll, or lack some much needed space between the edge of the screen and the text.
Fig 1. Inconsistent margins d1
, d2
, d3
from the edge of the page.
Sites need to show up on a lot of different size screens, but that doesn’t mean you need media-queried changes on all the pieces of your site! You can tackle the majority of what makes a site responsive with one container class that gives you padding for mobile sizes and wraps your whole design (holds your grid) at large sizes.
Here’s an example:
.centered-container {
padding-left: 20px;
padding-right: 20px;
max-width: 1000px;
margin-left: auto;
margin-right: auto;
/* Optional: padding-top, padding-bottom, etc */
}
Fig 2. One container class creates consistent left/right margins d
.
At mobile sizes, the padding
on the sides creates a bit of space to push your content away from the edge of the screen. This container stays the same width as the viewport (browser window) until the viewport is above 1000px
width. After that point, the container stops growing and simply stays centered in the screen.
Note! You don’t need to use %
or other funky units to make a simple responsive container for your site. Explicit units like px
or em
/rem
can do the job. A media query can be used to alter aesthetics but shouldn't affect the core rules of max-width
, margin-left
, and margin-right
that make this technique work.
Want a section to have a different background? Simply wrap your .centered-container
in another HTML element and add class to that with the background
. Want the content to be off-center? Add a large-screen media query, and set an explicit margin-left: 120px;
and viola – your page no longer sticks to the middle, but instead stays on the left side of the screen, comfortably far from the edge.
2. Styling content before you have some default typography
Suppose you’re working on a portfolio site, something you just started. You have an image, you want your name to run in the middle of the screen, and a paragraph with some details. Here’s the HTML:
<section id="about-me" class="centered-container">
<img src="/olex.png" />
<h1>Olex Ponomarenko</h1>
<p>I help make do good wabsites.</p>
</section>
The next step you might take may be tempting to start adding classes or writing selectors like #about-me p {
– WAIT!
As soon as you have a chunk of content to start your website, you should set up your typography and default colors! If you hate picking fonts and/or have some theory about why you’re not “creative” – that’s OK, this is also the right time to add a CSS framework. In general, you’re looking for some typographic defaults on your body or html tag, defaults for display: block;
elements like p, h1 through h3, ul, and defaults for display: inline;
elements like strong and em. A complete styleguide or CSS framework would also include h4 through h6, blockquote, the table family of elements, pre (code blocks), figure + figcaption for images and a few rare inline elements such as sup (superscript). But don’t worry about covering all the edge cases, just pick a default font-size
, line-height
, and color
early on.
body {
font-family: "Open Sans", sans-serif;
font-size: 18px;
line-height: 1.5;
color: #333;
}
Default font-size should be 16px - 20px
. I suggest 1.5 - 1.85
as a good default line-height
. This value depends on which font you use, so you should set it up in concert with a font, not before.
You probably want to set line-height without units. This makes line-height on children dynamic, so elements like li
will multiply their own font-size by that unitless value to get their line-height. If you’re using normalize.css, the default line-height of 1.15
is bad for paragraphs, but works well for headlines. In your headlines like h1
through h6
, it looks best to reset line-height back to a lower number.
For color, it’s best to avoid full black #000000
and go with a dark gray default color, like #333333
. You can also turn contrast down with slightly-off-white colors like #f9f9f9
for the page background, but the default full-on white #ffffff
is a good standard background color.
Headers (h1-h6), paragraphs, and other typographic elements like buttons tend to have margins specified in the em
unit, which scales with their font-size. Commonly, a class like .button
for chunky links and input
styles are defined near the typography defaults.
This block of default makes it easy to
h1 {
font-size: 36px;
color: #689f38;
line-height: 1.2;
margin-top: 1em;
margin-bottom: 0.6em;
}
h2 {
font-size: 28px;
line-height: 1;
margin-bottom: 0.5em;
margin-top: 0.5em;
}
ul { /*...*/ }
ol { /*...*/ }
li { /*...*/ }
.button { /*...*/ }
input { /*...*/ }
Now, this next one is controversial!
A lot of developers would disagree with this, but I suggest adding a max-width
to your paragraphs by default. The value here should probably correspond to a number of columns (6, 8?) if you’re using a grid. The key is the number of characters per line – aka the measure – you want a max of about 70-75 characters in a line. Otherwise, a paragraph on its own looks like a pancake and your eye has a difficult time following the white space between lines to get back to the start of the next line. Wider paragraphs can look reasonable if the line-height
is also tall. Keep in mind we’re just inheriting line-height and fonts that from our body
or html
tag, you don’t need to set those values twice.
p {
font-size: 18px;
margin-top: 1em;
margin-bottom: 1em;
max-width: 650px; /* Please read above before starting flame war! */
}
You could, of course, always put your paragraphs into special columns that don’t expand to the whole grid, or otherwise limit their size, but I feel that an explicit max-width
declaration on paragraphs is a good restraint to hold on to for your first few web designs.
3. Messing with libraries and frameworks for hours before inspecting their CSS
Be careful about dropping in big chunks of CSS when you should be stealing from them.
Too much CSS, overuse of some framework hammer or another, is a common problem in large frontend projects. Ask any experienced frontend developer and they’ll be able to pull up some example from their history of sites using two copies of Bootstrap, or fighting with 7 conflicting body {
rulesets, or spending hours fixing their site after removing a disused framework.
Chances are, you don’t really need that whole framework. People routinely spend dozens of hours FIGHTING with a whole framework when all they need is the grid from that framework. Or worse, they try to jam a unique design into some framework’s grid, just because they like the style of buttons in that framework.
Whenever you see the result you want in the browser, even if it’s an example site, inspect it and figure out how it’s built. If you want a particular button style, inspect that button and toggle CSS rules on and off to see how it’s built. If you want a particular grid arrangement, inspect it and see how the container and gutters are formed out of % widths, paddings, and margins. Does this grid use float
or display: inline-block;
or display: flex;
? Frontend developers can’t really hide how they did something in CSS, their work is always visible via the inspector tools. All CSS is essentially open-source.
Inspecting the CSS you use early is critical to improving your skills as a frontend developer. Don’t assume that bringing in a pile of someone else’s CSS will fix issues on your site. On the other hand, if you know a framework has accomplished what you’re looking to do, don’t hesitate to use the pick out some CSS and tackle a problem you have.
Inspect early and often, and you’ll quickly get a balanced sense of what CSS you want to pull in from a framework, and what CSS you’re comfortable with building yourself.
4. Wasting time working around bad assets
One of the most common “good on every website” CSS blocks I recommend is this statement to keep images from overflowing their columns and containers.
img {
max-width: 100%;
}
Coupled with the standard box-sizing
change, this alleviates one of the most common causes of horizontal scroll on small screens. But this change can also trick you into feeling like a 5-megabyte DSLR photo of you in a 45px square is A-OK web development. It is not. I feel a growing tendency of early developers is to spend 20-30 minutes researching CSS tricks to solve an issue they could fix by cropping an image.
The two tricks they find – background-size: cover;
and object-fit: cover;
– solve a lot of legitimate issues, they’re great to know. But be wary of seeing all images as nails, and these things as a hammer. Tricks that fix image positioning let bad image assets bloat site after site.
Take the time to optimize your assets a little bit. Make sure you’re loading images that are just-right. Each image on your page should be shown it’s natural size or scaled down by about 1.5x. Going full 2x size and optimizing for retina is rarely worth it. Huge images and other unnecessary assets weigh down your page, negatively affect performance on all devices, and seriously hurt your search engine rankings.
Hacking around bad image proportions is a useful skill, but don’t do it on small websites you have full control of. Just fix the asset! It’s a much better solution most of the time.
5. Using anything other than class selectors
But Olex! You have examples in this very article that use element selectors!
– You
There are two issues that serve to confuse frontend devs who are just getting started in 2016-2017.
First, although many who learn CSS know about the different specificity levels of #id
selectos vs .class
, they’re not instructed to use one or the other. I believe the jury is long back from deliberation on this topic… 90% of your CSS selectors should be a single .class-name {
statement.
For any project that you start I suggest sticking to this rule. It’s much better to have slightly long / annoying class names, rather than veer off this trend and use a mix of id’s, classes, tag names for selection. It makes sense to have some basic defaults defined on element selectors (styleguide stuff like h1
‘s font sizing, as I mentioned above), but most of your CSS should be applied with just one class wherever you need to target an element. Modifier classes, like a special case of a certain element, can be made with two classes on the same element like so: .class-name.mod-awesome {
– using primarily classes keeps specificity manageable. Check out Bobby Grace’s trello CSS style guide if you’d like to see a more complete guide for using class selectors effectively.
Second, there are movements in the React community to use inline styles as the primary way of attaching CSS to HTML. Just because a framework tries to avoid CSS and selectors, doesn’t mean it’s not beholden to the browser’s layout model. Under the hood, even if some React library (like material-ui) avoids using regular CSS selectors, it's still using CSS for the actual styling.
There are some advantages to this technique, but I think it's a waste of time for those starting out. If some way to scope CSS to a component becomes de-facto, it’ll likely either make it into the body of web standards outside of React, or it’ll look so similar to using standard classes you’ll hardly notice the change. If you aren’t certain what real benefits javascript-injected styles present, you’re better off sticking to plain old CSS selectors and classes.
That’s it!
Thanks for reading these tips, I hope you’ll have a little more fun and
a little less frustration the next time you have to write some CSS!
🔌 To get random ramblings about 🎛 synthesizers, 🇺🇸 politics, and 🎨 CSS, follow me on twitter: @tholex