CSS Fundamentals for Beginners


Borislav Hadzhiev

Wed Mar 10 20217 min read


Photo by Evan Brockett

Set min-height instead of height #

Most of the time - if you need to set height, set a min height because when you set a specific height things can overflow when you make the screen more narrow (mobile screen). Or when the content increases, someone adds an extra paragraph and it overflows.

By default the height of an element is determined by the content that's inside of it. If you add more content the height grows. Min-height means the height can't be less than the specified amount, but if it needs to grow with the content it will.

You should still set a height on icons / images to avoid cumulative layout shift.

CSS relationships #

The size of an element is influenced by it's containing block. If we set the width of an element using percentages, that is a percentage of its containing block's width.

If we set width 80% on an element, that means 80% of its parent's total width.

When we use position: absolute; the containing block of an element is no longer its parent, but instead its nearest ancestor which has position other than static. If there is no ancestor element with position other than static, the containing block is the root html element.

When using position:fixed; the containing block of that element is the viewport.

Box-Sizing: Border-Box #

With box-sizing: border-box; the size is not determined by the content or the content-box (it's called CONTENT box because you just set the size of the CONTENT), but by the border-box (includes the content, padding and border).

.box { box-sizing: border-box; width: 100px; padding: 20px; border: 10px solid red; margin: 10px; }

In the above example the 100px width includes - the border, padding and content. It's called BORDER box because inside your border - you have your border, your padding and your content.

Margin is not included in the border-box because margin is space between elements, not the element itself.

Set the box-sizing to border-box for all elements and pseudo elements:

*, *::before, *::after { box-sizing: border-box; }

CSS inheritance #

Anything related to typography will be inherited from the children - font-size, font-family, text-decoration, text-align, color. That's why we often place font-family or font-size or font-weight on our html element - because they're inherited from the children of that element. You can overwrite the inherited properties by explicitly specifying them on the child element.

Anything that is set by default by the browser, i.e. links, headings, won't inherit.

Nothing related to layout is inherited - margin, padding, height, width, position are not inherited by children.

By default button, input, select, textarea elements don't inherit anything because of the browser defaults. You can explicitly specify that you want these elements to inherit:

a { color: inherit; } button, input, select, textarea { font-family: inherit; }

CSS Cascade #

The cascade looks at:

  1. Origin and importance. Using important is frowned upon and sloppy.
  2. Specificity. It's best to keep specificity flat, avoid using #ids or .class .innerClass selectors. Because when we raise specificity if we need to override it in the future it can be annoying. If we eliminate specificity and use just classes tailwind style, we have less things to think about. And if we don't have specificity wars we don't have to use !important anyway.
  3. Order of appearance - in the .css file
.red { background: red; } .blue { background: blue; }
<div class="blue red">Hi there</div>

It doesn't matter what order you put the classes in the class string, but the order they appear in your .css file. So the .blue definition will override the .red one.

If a selector comes after another equal selector, it tends to win.

Boxes in Boxes in Boxes #

In a website everything is a box within a box, within a box. Everything participates in a formatting context.

  • Block formatting context
  • Inline formatting context
  • Flex formatting context
  • Grid formatting context

There are rules for how elements behave when inside a specific formatting context.

Understanding these rules is very important when trying to create and manage layouts.

  1. Inline Formatting context - elements like span, strong, em, links.

    • They are inline, they go next to one another not one on top of the other, as opposed to block level elements.
    • With inline elements elements - horizontal padding, borders and margin are applied to the element and push the text away left and right
    • Margins above and below the element will not be applied
    • vertical padding and borders will be applied but may overlap content above and below because the inline boxes will not be pushed apart by padding and borders.
  2. Block level elements either contain other Block level elements, or Inline elements, but not both. If we have a paragraph or a div, they can either contain other block level elements or they can contain inline elements, but not both.

    <div> lorem ipsum <p>dolor sit</p> amet consectur </div>

The browser takes the inline text and converts it to block level elements behind the scenes. It wraps the text on top and bottom and the text becomes block level elements.

Inside of Block formatting context, your content is laid out one on top of each other, even if there is room, they won't try to squeeze in. Even if you set width of 30% on 2 divs, they won't try to be on the same line next to one another, they'll be still placed one on top of the other.

  • Inside of a block context, margins collapse. If you have 2 divs one on top of each other, and both have margin of 100px, the margins will collapse and it will only be 100px of margin between the divs. The bigger margin wins and remains, the smaller margin is collapsed.
  • Only vertical margins collapse, horizontal margins don't collapse

If you create a new block formatting context, you can stop margins from collapsing. Ways to create a block formatting context include:

  1. Using floats

  2. Position absolute, fixed and inline-block

  3. overflow of anything except visible

  4. using columns

  5. flex and grid items

  6. display flow-root

  7. When you display: flex; you are establishing the flex formatting context. It is similar to a block formatting context, but with a few differences:

    • float and clear don't work
    • its margins don't collapse with its children's margins
    • the children are a part of a flex layout, not a box layout. They go one next to the other, not one on top of the other. In flex layout, it depends on the flex direction.
    • the children (flex items), establish their own formatting context

Z-index #

Z-index influences the way html elements stack on top of one another. When we use positioning we start overlaying elements on top of one another. A higher z-index pushes the element higher in the stack and a lower number - lower. Z-index can't be used in isolation, we need other properties to use z-index.

When there is no z-index applied, and no positioning, html elements stack in the order they appear in the HTML. The last element wins and is rendered on top of the other. This is also true if elements have an equal z-index.

When we apply a position other than static (the default) to an element, it will be rendered on top.

We can apply z-index only to positioned elements (not static). Z-index doesn't have effect on elements with static position. Z-index can also be negative value - i.e. -10.

The default z-index is 0.

We can also use z-index on flex and grid items.

When we create a new stacking context, we isolate the z-index to that group of elements in the stacking context. So when we create a new stacking context z-index is no longer relative to the root html element, it's relative to that individual stacking context.

Flex-Basis, Flex-Shrink, Flex-Grow #

You can influence the way flexbox updates the size of the flex items with the properties:

  • flex-basis
  • flex-shrink
  • flex-grow

Flex-Basis #

Flex-basis is the size of a flex item on the main axis. The main axis in flex changes according to the flex-direction property. So flex-direction changes the direction flex-basis works in. If you had a flex-direction column - flex-basis would be looking at the height instead of the width. By default flex-direction is row and flex-basis looks at the width property.

The default of flex-basis is auto. If we don't set a flex-basis on a flex-item, the default behavior is to set the flex-basis to auto, so it looks at the content of an element. The content inside of a flex item dictates how big the flex item is displayed. If the content is the same and flex-direction is row then the widths are equal. If one of the flex-items has less content - flexbox assumes it doesn't need as much room.

If you set flex-basis to 100%, all flex items become equal. We're saying all flex-items should be 100% of the parent's size, but they can't all be 100% of the parent's size, that's where the default value of flex-shrink comes in - elements are shrunk by equal proportions and now they're the same size.

Flex-Shrink #

Flex-shrink - allows / disallows flex items to shrink as the viewport narrows. The default value for flex-shrink is 1. If flex-shrink is a number greater than 0 - the flex item is allowed to shrink (become smaller) than its actual size if there isn't enough room. Without flex-shrink and flex-wrap elements would overflow out of the side and flexbox layout would not be very useful.

So with flex-basis, we're saying how big a flex item should be and with flex-shrink positive integer - we're allowing the flex item ot be smaller than that. If flex-shrink is set to 0, it means the flex-item is not allowed to shrink.

Flex-Grow #

Flex-grow defines the ability for a flex item to grow if necessary. It dictates what amount of the available space inside the flex container the item should take up.

If all flex items have flex-grow set to 1, every child will be set to an equal size inside the flex container. If you were to give one of the children a flex-grow of 2, that flex item would take twice as much space.

Default value for flex-grow is 0, which means elements are not allowed to grow by default.

Use the search field on my Home Page to filter through my more than 1,000 articles.