Author Image
by Ilija Ištuk
Dec 30th 2020

Guide to writing modern CSS

Tags: CSS, modern

CSS has evolved a lot in the past few years, and the main reason is the arrival of responsive design. For those unfamiliar with responsive design, responsive design is the process of designing websites that respond to different devices in order to provide the best user experience. With the arrival of CSS3, we got a lot of amazing features that enabled us to create responsive websites a lot easier with less code. In this post, we will cover some interesting features from CSS3, best practices for writing styles for your application, and cool tips for making your CSS better.

Reset CSS and Normalize CSS

As mentioned above we want our website to work on all devices. The first issue we will face while creating a modern responsive website is inconsistent User Agent Styles. Let me explain, basically each browser comes with predefined styles for elements like <h1> or <p> and they are not always the same (especially in IE). To solve this problem we have two options. The first and more aggressive approach is Reset CSS which will remove all User Agent Styles so that we can define them ourselves in our project. There are several good Reset.css implementations around, and it is not very hard to create your own. My number one solution is Eric Meyer’s Reset CSS

A second and more elegant approach is to use Normalize.css by Nicolas Gallagher. Normalize CSS provides consistent styles across devices, therefore, if a certain browser is not consistent with other browsers, Normalize CSS will modify styles to make them compatible.

An additional approach and my personal favorite is to combine them. In this case, Reset CSS should be a lot less aggressive since we don't want to override our Normalize CSS instead just remove styling from elements like <button>, <a> and <h1>. Here is a Reset CSS example I use in my projects. This is actually a slightly modified version of Reset CSS by Elad Shechter's

html {box-sizing: border-box;}
*, *::before, *::after {box-sizing: inherit;}
h1, h2, h3, h4, h5, h6{margin:0; font-size:inherit; font-weight:inherit;}
p{margin:0;}
a{text-decoration:none; color:inherit; cursor:pointer;}
button{background-color:transparent; color:inherit; border-width:0; padding:0; cursor:pointer;}
input::-moz-focus-inner {border:0; padding:0; margin:0;}
input, textarea {outline: 0;}
ul, ol, dd{margin:0; padding:0; list-style:none;}
cite {font-style:normal;}
fieldset{border-width:0; padding:0; margin:0;}
figure{margin:0;}

CSS Box Model

Each HTML element has a box around it, this box can be either a block as <div> or an inline as <span>. The type of element's box describes how the element behaves in relation to other elements. For example, the box element as a block will extend across the entire line filling the whole container width. If we set the width of our blockelement, the margin will occupy the rest of the container width. Also, a block element will break onto a new line and cannot be in the same line as any other element.

In the case of aninline element, the box will stay in the same line, and only horizontal margins, paddings, and borders will affect other inline elements. inline elements cannot have custom width and height.

Block cheatsheet

  • The box will break onto a new line.
  • Padding, margin and border will cause other elements to move
  • The box will extend across entire line filling entire container width
  • The width and height properties will be applied.

Inline cheatsheet

  • The box will not break onto a new line.
  • Only horizontal margins, paddings and borders will cause other elements to move
  • The box will be as wide as its content
  • The width and height properties will be ignored

Box type can be changed using display: property. There are also other box types like flex and grid, but we will talk about those later.

CSS Box Model consists of four elements Content box, Padding box, Border box and Margin box. By default, width: and height: properties will set the width and height of our Content box, and paddings and borders will increase the overall size. In some cases, we want to be able to set the overall width and height of some elements and have paddings and borders included in the overall size. Before CSS3, this was quite hard, but now we have box-sizing: property. Using this property, we can specify how we want our box to calculate its size. So now, if we want our paddings and borders to be included in specified width and height, we can just add box-sizing: border-box; and width and height we set for our element will be the actual render size including paddings and borders. This property became so popular in responsive designs that reset styles includes it by default (If you check my Reset CSS above, it sets <html> Box Sizing to border-box and then sets all other elements to inherit Box Sizing value from the parent).

Using rem unit

To achieve a harmonious and balanced responsive design, we must use rem unit instead of pixels. Basically 1rem is equal to the font size of the <html> element which is by default 16px in most browsers. One disadvantage of using rem units is that the values are somewhat difficult to use if we want the font size to be 20px, we must set it to 1.25rem. Therefore we use 62.5% trick to set the font size to 10px, so we can more easily use rem units (20px, in this case, would be 2rem). Example:

html {font-size: 62.5%;}
body {font-size: 1.6rem;}

The advantages of using rem units are numerous. We can create much more fluid designs that respond to different screen sizes, all browser features like font scale and zoom will work as usual. Also, if we make use of em unit (em unit is equal to the font size of the current element) we can create styles that reflect changes across documents immediately without additional changes. For example, if we want the font size of <h1> element inside an element with .article-content class to be 2 times the size of its parent, we can set its size to 2em

.article-content {font-size: 1.4rem;}
.article-content h1 {font-size: 2em;}

Now, if we decide that we want our article to be larger, we can just set its font size to 1.6rem and the heading will increase accordingly. Notice how I said that em is equal to the font size of the current element, but in this case, we use em to set font size according to the parent's font-size. That is because when we use em unit on font-size: property it'll be relative to parent's font size, but if we use em on any other property it'll use current element font size.

Designing page Layout

Before we even start creating styles for our website, we must know the flow of content on our page. For example, let's say that we got an assignment to create a brand new responsive item preview page for an eCommerce website. We know that our page must include an item title, product image, details, and a description. To keep it simple, let's say that navigation is already done. Since 51% of people use only mobile devices to browse the web, we will start designing our layout for mobile devices first, and we will decide how we want to distribute our content on larger screens. Below we can see an example of the layout for our new item page for a mobile device, it is quite simple actually. Notice the large box around all our elements, that is our main container, and all our page content will go inside.

The real fun starts when we start moving to a larger screen. We don't want our page to look like a stretched mobile site on tablets and PC browsers, therefore we must decide how we want to design our layout. Let's say that we want our item title to always stay on its own line, but we want images and details to be placed on the same line while on larger screens. Description can also stay on its own line. According to that our layout for larger screens will look something like this.

Notice the yellow box I added around the image and details box. The reason I did that is because we want the layout design to be as close as possible to the actual structure of the document. The yellow box represents the block element, which will be on its own line and contain an image and details box. Each one will be on its own line on a mobile device and on the same line on larger devices, also our container box now has a limited width. According to our layout design, our HTML should look something like this.

<div id="page-content">
  <h1>Item Name</h1>
  <div id="info-panel">
    <div id="image-panel">
      <!-- Item Image code -->
    </div>
    <div id="item-details">
      <!-- Item Details code -->
    </div>
  </div>
  <div id="item-details">
    <!-- Item Description -->
  </div>
</div>

Flexbox

Flex allows us to create flexible responsive layouts easily. Let's take our item preview page as an example, and create a CSS stylesheet that will behave as we specified in our design layout. Since <h1> and <div> elements are blocks they will, by default, take each its own line, therefore the only thing left is to create styles for our .info-panel and its children. To achieve that we will use display: flex;. Flex is an inner display type, meaning it'll change how its children are displayed. The outer display type of flex is a block and its siblings will see it as a block. Now we got all our children in the same line, but we want our children to be displayed on their own line if the screen is not wide enough. For that, we add flex-wrap: wrap; to our element and specify the min-width of its children. This way we told our flex element to break onto a new line if there is not enough space to display elements. The last thing want is to set flex-grow: 1; to our details element so that it takes the rest of the space available in the flex container. CSS will look something like this.

#info-panel {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
#info-panel div {
  max-width: 100%;
  min-width: 36rem;
}
#info-panel #item-details {
  flex-grow: 1;
}

You can also notice that I added justify-content: center; this will center our image element once the details element breaks onto a new line. Also, there is max-width: 100%; for our children. This is making sure that even if our content is wider than its container, the container will not overflow our flex container.

Grid

And the last great thing we will cover in this post is a grid. Grid, unlike flex which is a 1-Dimensional system, allows us to handle both columns and rows. Before grid, we were using tables, floats, and inline-blocks to create our layout, but now we have a powerful tool designed to do just that. With grid, we can specify exactly how we want our layout to behave. Let's take our layout from above and create it with a grid.

@media screen and (min-width: 72rem) {
  #page-content {
    display: grid;
    grid-template-columns: 36rem 1fr;
    grid-template-areas:
      "title title"
      "image details"
      "desc desc";
  }
}

h1 {
  grid-area: title;
}
#image-panel {
  grid-area: image;
}
#item-details {
  grid-area: details;
}
#item-description {
  grid-area: desc;
}

Since we don't have to use any additional elements to build the layout, our HTML is also cleaner. That's because grid allows us to specify exactly how we want our elements arranged in both directions, therefore we don't need #info-panel div around our image and details panel.

<div id="page-content">
  <h1>Item Name</h1>
  <div id="image-panel">
    <!-- Item Image code -->
  </div>
  <div id="item-details">
    <!-- Item Details code -->
  </div>
  <div id="item-description">
    <!-- Item Description -->
  </div>
</div>

Conclusion

In this post, we covered how to more easily create cross-browser styles using Normalize CSS and Reset CSS, how Box model works in CSS, and how to more easily use rem units. We also covered some basics on how to design page layout and then how to implement it using Flexbox and Grid. If you have any questions about a post or CSS in general please feel free to ask and I will give my best to answer them as fast as possible. Also if you liked this guide and would like to see more posts like this please comment below with your suggestions.