This article is intended for developers already familiar with CSS and how to use it, seeking a reintroduction to a few key concepts of CSS as well as being introduced to a few lesser-known aspects. This article was created with the goal of being used as a reference in mind.
With that being said, let’s get started.
Within the Browser
CSS works by combining the content from an HTML document with its corresponding style information. To understand how CSS works under the hood, there must first be an explanation on what happens within the browser as both HTML and CSS are loaded.
According to the Mozilla documentation, the process of a browser loading a webpage (which includes both HTML & CSS) is as follows:
- The browser loads the HTML (retrieves the index.html as soon as a server request is completed)
- The HTML is converted into the DOM (Document Object Model) which represents the document in the computer’s memory (the same type of thing happens with .css files, creating a tree by the name of CSSOM)
- The browser then fetches any defined resources (images, videos or .css files in our case)
- The browser parses the CSS, identifying which rules apply to which elements currently in the DOM and applies them, changing the layout and behavior of the HTML
- The render tree (which is the culmination of both the DOM and the CSSOM) is then laid out in the structure it should appear to the client
- The render tree is then painted to show the final product as the webpage
As you can see, CSS has been introduced in such a way as to complement HTML in the highest degree possible based on the original desire to add style to HTML pages. To learn more about how CSS came to join so well with our favorite markup language, click here.
Cascading Style Sheets
CSS stands for Cascading Style Sheets. This means that any code statements further down in the file take precedence over those that have been defined previously. If we were to have the following code in our CSS file:
then the <p> tags located within the corresponding HTML documents would all have the text color of red, due to the effect of cascading. Because the color: red statement appears after the color: blue statement, the color red is used when changing the color of paragraphs within the web page. As the order of execution cascades from top to bottom within this CSS file, the color red statement is recognized most recently, taking itself into effect.
*Note — if you believe you are having issues relating to how your CSS files cascade (perhaps with some third party resources), try adding the !important keyword to your declarations to allow for easer debugging, like so:
The CSS Box Model
The heart of element dimensions within CSS is revolved around the idea of the box model. Each individual HTML element has its own. Each box model includes properties such as margin, border, padding, as well as the actual content the HTML element contains (this could be something as simple as text within an <h1>).
Let’s look at this visually.
The exact specification of how margin, border, padding and content of an HTML element is extremely important to understand in order to produce precise and accurate user interfaces.
By default, the border and padding properties set to an element will contribute in addition to an element’s width and height respectively. This happens by default because of the CSS box-sizing property. We can change this so that the width or the height of an element includes its border and padding into its calculations. More specifically, we can change an element’s box sizing property value from the default content-box to border-box. Here’s what that looks like in code:
For both of these boxes, we have defined a width and a height of 75px, but they obviously do not have the same dimensions. This is because the first box has defined a box-sizing property value of content-box (this is the default value), while the second box has defined its value as border-box.
The first box, though having a defined width of 75px, actually has a calculated width of 105px. This is because the padding and the border defined in the CSS file adds to the total width of the element, on top of the specified content width of 75px.
The second box, because it uses box-sizing: border-box, always has an actual width of 75px. CSS includes the padding and the border while calculating this box’s width, shrinking the element’s intrinsic width, allowing for the padding and the borders to remain their specified values.
Here are the values that contribute to the width and the height of both boxes in a visual format:
I recommend using the universal selector within any project that uses CSS to apply box-sizing: border-box to each HTML element. This ensures accurate dimensions without having to calculate the offset of any padding or borders. For your reference, here’s what it looks like:
I also include setting the margin and padding to 0 for all elements as well, preventing unwanted layout behavior later on down the road. This is extremely useful when making sure a web page is responsive. Still, the choice is completely up to you (though I recommend it).
Useful CSS Properties
Here are just a few of the CSS properties that I believe are crucial to understand as front-end developers.
Property #1 — Display
The display property specifies the display behavior of an HTML element, each of which has their own default value There are many different values that an element can have its display property assigned to (23, to be exact), so I’ll just go over those that are most commonly seen.
The next three examples will use the following HTML:
Elements displayed as block are moved to a new line and take up the entire width of the page. This is the default value for <div> and <p> elements.
This value allows elements to be displayed on the same line as other elements, and is especially useful for elements that take up more than one line by default. Width and height have no effect with elements of this display property value.
Elements displayed with inline-block have the ability to display within the same line as other inline elements, yet maintaining the ability to modify the width and height as a block element is capable of doing.
Also known as flexbox, this display property value is extremely powerful and allows for many different layout options for the children of the element using it. Elements can use flexbox as block elements (display: flex) or as inline elements (display: inline-flex). Let’s look at an example of using flexbox to vertically and horizontally center the children of a <div> within itself.
First, the HTML:
Now, the CSS and result:
Discussing all the various possibilities of flexbox would require a standalone article. That being said, you can find an informative and complete guide on how to use flexbox here.
Elements with this display property value displays children elements as a block level grid container. This is especially useful when you want to create precise, uniform layouts. Just as with flexbox, defining elements with the grid value can be either inline (display: inline-grid) or block (display: grid).
For more information on the power of CSS grid: check out this handy guide.
Property #2 — Position
As the name suggests, the position property specifies how an element should obtain its position within the normal flow of a web page.
This is the default value for all HTML elements. Elements that do not have a specified position value are positioned according to the normal flow of the page, and are not affected by setting top, left, right or bottom values.
This causes an element to be positioned relative to its original position. After applying this value, an element may then specify left, right, bottom or top values to allow the element to be positioned away from those directions, relative to where it would appear in the normal flow of the page.
Elements with this position value remain in the same position, even if scrolled. This is because elements containing this property value are positioned relative to the viewport. An element can then modify its fixed position by using top, left, right or bottom.
Scroll down in the following code example to see this in action.
Elements with this position value are positioned relative to the nearest positioned ancestor. If the nearest ancestor has no position specified, then the element will be positioned relative to the body (and will therefore move with the page if scrollable).
In the example below, the parent <div> has a specified position, so the child <div> is positioned relative to the parent.
Elements defined with sticky are able to display as both fixed and relative, depending on the location of the vertical scroll. If a user scrolls past the view area of an element defined by position:sticky, the element will change from being displayed as a relatively positioned element to a fixed positioned element, as long as the top value is set to 0 as well.
Note that that in order for this to work with Internet Explorer, you must include the following property inside your sticky selector’s declarations:
Pseudo-elements allow the styling of specific parts of an element. They can be used to style the first letter or line of an element, insert content before and after elements, and more.
We can use this property to style the first line or the first letter of text in the active element, like so:
One important item to note is that pseudo-elements are not the same as pseudo-classes. Pseudo-elements are denoted using a double colon, while pseudo-classes are denoted using a single colon.
If you need a refresher on pseudo-classes, make sure to check this page out.
We can use these pseudo-elements to insert content before and after active HTML elements, including text, images, gifs, and more.
Handy Trick: Maintaining Aspect Ratio (using only CSS)
The first thing to do is recognize the most appropriate width and height that you want to display your content as. By content, I mean a variety of possible things — this could be a video, image, iframe, canvas element, you name it — whatever needs to maintain a specific aspect ratio. In this example, I’m going to be using a simple container <div> to hold a content <div>. This method will work for whichever sort of element you choose to use this on.
With all that said, let’s look at some code, and I’ll explain what’s going on after.
Cool, right? If we resize the result window after clicking on the option to edit directly on CodePen, we see that the container element maintains an aspect ratio of 16:9, no matter the size of the window.
This approach first requires the width to be set for the element in which we want to maintain the aspect ratio for; in our case, this is the #container <div>. After setting its width to 100% of the body (a fluid width for maintaining aspect ratios, crazy I know), we do not have to worry about setting the height ourselves. This is because of the built-in CSS aspect-ratio property. This property works by checking the existing width and height, and formatting them both to adjust to a specified aspect ratio. In this case, the width is set to 100% and the aspect ratio is set to 16:9, and the height of the #container <div> is updated automatically. The cool thing is, we can set the aspect ratio to anything we like, and it will be maintained! All we have to do is set the aspect ratio as aspect-ratio: width / height.
With this approach, notice we have also specified a max-height: 90vh. Remember, vw and vh and relative units, meaning they change depending on the browser window. In our case, 90vh denotes 90% of the browser height. For a browser with a pixel height of 1000px, 90vh would actually be 900px under the hood, as 1vh is 1/100th of the window height. We can see that once that #container <div> reaches max-height: 90vh, it is no longer allowed to increase in size, maintaining the aspect ratio and ensuring that all the web content is still visible. We also set the min-height: 25vh, which ensures that our #container <div> will never be shrunk to a size too small to see.
Though this is not a complete lesson of all that CSS entails, I hope that this has served as a brief reintroduction to some of the concepts that I believe to be central when styling web pages. CSS is a powerful tool to creating elegantly designed applications, and it must be truly understood to reach the level of potential that all software craftsman of the web must strive for continually.
(With helpful advice from Anthony Feldhake & Zechariah Schwerman)