CSS/SASS techniques I’ve learned as a front-end developer

This post is a list of CSS/SASS techniques I’ve learned since I got my current soft engineer role, which is mostly concerned with front-end development.

Before I started to work for my current position, I wasn’t absolutely confident with my CSS skills, so I had to teach myself techniques which were:

  • not 100% clear to me at that time (e.g. positioning of elements, the px/em/rem units)
  • essential to modern front-end development (e.g. responsive design with the media query, flex-box)

Memorizing all the CSS properties and functions wouldn’t be practical due to the sheer volume of them. Nonetheless, the techniques on this list will be worth memorizing (to me, at least), because I use them quite often when I write code at the office or work on my personal projects.

This list is meant to be a cheat sheet for myself, and I didn’t put detailed explanations for each technique. They just have a tiny piece of code and a brief description. I can (usually) recall what each technique was about by reading those descriptions and snippets, but those tiny explanations themselves might not make sense to other people.

Still, if you recently got a web developer role but aren’t quite confident with CSS, this list can be a guide as to what you’ll need to learn in order to survive in your new workplace.

NOTE: I didn’t write about the flex-box and media query in this post. I learned about them after I got my current job and found them highly useful, but they were omitted here because:

  • if I included them, this post would be a bit too long
  • there are already many online articles about them which are quite detailed and easy to understand

The base setting

The universal selector

-- * (universal selector) chooses every elements.
-- NOTE: don't confuse this with inheritance!

* {
  margin: 0;
  padding: 0;
}

-- This prevents the browser from putting any margin/padding by default.
-- This can be useful if it's put at the top of the CSS file(s)

-- NOTE: the unversal selector doesn't have any specificity, so it'll be overwritten by any CSS declaration.

body {
 -- I usually put "body" after *
}

Inheritance

*,
*::after,
*::before {
  box-sizing: inherit;
}
-- Each element is now supposed to inherit the value of box-sizing from body.

body {
  box-sizing: border-box;
  -- You can put font-family, font-weight etc
}

The 7-1 pattern

This is a technique that is introduced in Sass Guidelines. This technique consists of 7 folders and 1 file (Depending on the size of your project, you may not need 7 folders).

I found this technique useful for logically organizing (S)CSS files and folders.

ref: https://sass-guidelin.es

sass/
|
|– abstracts/
|   |– _variables.scss    # Sass Variables
|   |– _functions.scss    # Sass Functions
|   |– _mixins.scss       # Sass Mixins
|   |– _placeholders.scss # Sass Placeholders
|
|– base/
|   |– _reset.scss        # Reset/normalize
|   |– _typography.scss   # Typography rules
|   …                     # Etc.
|
|– components/
|   |– _buttons.scss      # Buttons
|   |– _carousel.scss     # Carousel
|   |– _cover.scss        # Cover
|   |– _dropdown.scss     # Dropdown
|   …                     # Etc.
|
|– layout/
|   |– _navigation.scss   # Navigation
|   |– _grid.scss         # Grid system
|   |– _header.scss       # Header
|   |– _footer.scss       # Footer
|   |– _sidebar.scss      # Sidebar
|   |– _forms.scss        # Forms
|   …                     # Etc.
|
|– pages/
|   |– _home.scss         # Home specific styles
|   |– _contact.scss      # Contact specific styles
|   …                     # Etc.
|
|– themes/
|   |– _theme.scss        # Default theme
|   |– _admin.scss        # Admin theme
|   …                     # Etc.
|
|– vendors/
|   |– _bootstrap.scss    # Bootstrap
|   |– _jquery-ui.scss    # jQuery UI
|   …                     # Etc.
|
`– main.scss              # Main Sass file

BEM (naming convention)

Block: Standalone entity that is meaningful on its own

Element: A part of a block that has no standalone meaning and is semantically tied to its block.

Modifier: A flag on a block or element. Use them to change appearance or behavior.

ref: http://getbem.com/introduction/

In my opinion, it’s easier to understand if Modifier is used as a different version of a block/element.

e.g.
.btn {}
.btn--success {}

mixin (SASS)

ref: https://sass-lang.com/documentation/at-rules/mixin


@mixin reset-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

@mixin horizontal-list {
  @include reset-list;

  li {
    display: inline-block;
    margin: {
      left: -2px;
      right: 2em;
    }
  }
}

nav ul {
  @include horizontal-list;
}

// mixin can have arguments

@mixin replace-text($image, $x: 50%, $y: 50%) {
  text-indent: -99999em;
  overflow: hidden;
  text-align: left;

  background: {
    image: $image;
    repeat: no-repeat;
    position: $x $y;
  }
}

.mail-icon {
  @include replace-text(url("/images/mail.svg"), 0);
}

extend (SCSS)

ref: https://sass-lang.com/documentation/at-rules/extend

.error {
  border: 1px #f00;
  background-color: #fdd;

  &--serious {
    @extend .error;
    border-width: 3px;
  }
}

Positioning

The position property

Normal flows (e.g. position: relative):

  • Not flowing
  • Not absolutely positioned
  • Elements are positioned accordingly to the order

Floats (e.g. position: left, right):

  • Elements are removed from the normal flow
  • Surrounding texts and inline elements will wrap around the floated elements
  • The content won’t adjust its height to the element

Absolute positioning (e.g. position: absolute, fixed)

  • (Like Floats,) elements are removed from the normal flow
  • Has no impact on surrounding texts and inline elements
  • You’ll use top, right, bottom, left in order to remove the element from its relatively positioned container

Using absolute in a relative container

<div class="header">
  <div class="logo"><!-- logo --></div>
</div>

.header {
  position: relative;
}

.logo {
  position: absolute;
  top: 40px;
  left: 40px;
}

-- An element with "position: absolute" is positioned relative to its closest positioned ancestor, if the ancestor has "position: relative".
-- Its final position is determined by the values of top and left

-- (ref: https://developer.mozilla.org/en-US/docs/Web/CSS/position)

Centering elements using max-width and auto margins

.row { 
  max-width: 100rem;
  margin: 0 auto 
}

text alignment

<div class="text-box-center">Welcome</div>
<div class="text-box-justify">One Two Three</div>

.text-box-center { text-align: center; }
.text-box-justify{ text-align: justify; }

-- Sometimes I'm temptated to use flex-box in order to position
-- an element. flex-box is useful, but it can be overkill to use it.
-- If it sounds familir to you, learn text-align.

-- text-align sets the horizontal alignment.

Displaying elements

Box-types (display)

There are so many types of display properties, but I found the types below worth memorizing.

Box-level boxes (e.g. display: block, display: flex, display: list-item, display: table):

  • Elements are formatted as blocks.
  • They take 100% of their parent’s width.
  • You can determine the width and height.
  • You can use box-sizing: border-box;

Inline boxes (display: inline):

  • Elements are distributed in a line
  • No line breaks
  • You can NOT determine the width and height.
  • You can NOT use box-sizing: border-box;

Inline-block boxes (display: inline-block)

  • Elements are distributed in a line, like inline elements
  • No line breaks, like inline elements
  • You can determine the width and height, unlike inline elements
  • You can use box-sizing: border-box;
<h1 class="title">
  <span class="main">Hiroki Takahashi</span>
  <span class="sub">Fullstack Web Developer</span>
</h1>

.main, .sub {
  display: block;
}

-- Both .main and .sub start on a new line and take up the whole width.

<div>
  <span>One</span>
  <span class="center" style="display: inline-block;">Two</span>
  <span>Three</span>
</div>

.center {
  display: inline-block;
  background-color: red;
  height: 100px;
}

-- .center is formatted as an inline element, but you can apply height and width values
-- (ref: https://www.w3schools.com/cssref/pr_class_display.asp)

box-sizing

* {
  box-sizing: border-box;
}
-- This changes the box-model, so that the borders and paddings won't be added to the total width/heigh.

transform (translate, rotate, scale, etc)

<div class="header">
  <div class="box-in-the-center"><!-- text, image etc --></div>
</div>

.header { position: relative; }

.box-in-the-center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

-- The translate() CSS function repositions an element in the horizontal and/or vertical directions. Its result is a <transform-function> data type.
-- (ref: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate)

-- In this example, "box-in-the-center" is put in the center in "header", because translate(-50%, -50%) is not relative to the parent. However, it's relative to itself!

.box-in-the-center:hover {
  transform: rotate(180deg);
}
-- transform works with :hover too.

-- transform: scale(), scaleX(), scaleY() are also worth learning.

outline & outline offest

-- The outline property is like the border outside of the border property.
-- The outline-offset property determines the distance between the outline and the border.
-- ref: https://www.w3schools.com/css/css_outline.asp

p {
  margin: 30px;
  padding: 5px;
  border: 1px solid black;
  outline: 5px solid red;
  outline-offset: 5px;
}

Units (em, rem, vh, vw)

em and rem

Both units are converted to pixels. The differences are:

The em unit means “my parent element’s font-size”.

The rem unit means “The root element’s font-size (usually it’s 16px)”.

From Mozilla’s website
html { 
  font-size: 62.5%; -- 1rem = 10px.

  @media (min-width: 20rem) {
    font-size: 150%;
  }

  @media (min-width: 30em) {
    font-size: 200%;
  }
}

-- I like to put this at the root of CSS.
-- Putting "font-size" and using "rem" is helpfull because, when you write media queries (making the website responsible) you don't have to change the px of every single ID/class/element.
-- You just need to change "font-size" in html for each media query.

-- It's usually better to put a percentage instead of a pixel, because some people change the browser's default font-size.
-- If that's the case, the user can't see your website with their setting of the font-size.

-- If you don't expect the default font-size to be 16px, calculate the percentage by
-- "expected default px / 16"
-- e.g. If it's 10 px, it's 10 / 16 = 0.625, so you'll put 
-- html { font-size: 62.5%; }
-- If the default font-size is 62.5%, it's easy to caluculate rem.
-- You just need to divide the rem by 10 in order to get the resulting px.

vh (viewpoint height) and vw (viewpoint width)

.hero {
  height: 90vh;
}
-- It determines that the height of .hero is 90% of the viewpoint.
-- viewpoint =  the browser window size. If the viewport is 50cm wide, 1vw = 0.5cm. (ref: https://www.w3schools.com/cssref/css_units.asp)

Animation

With @keyframes <identifier>

<div class="text-container">
  <div class="text">Blah blah...</div>
  <div class="sub-text">Blah blah...</div>
</div>

-- @keyframes allows you to controll the intermediate steps of CSS animation.
-- If you don't need to detemine intermediate steps, just use transition / transform (there is an example below).

.text {
  animation-name: slideFromLeft; -- defined below
  animation-duration: 3s;        -- animation continues for 3 sec
  animation-delay: 1s;           -- animation begins 1 sec later
  animation-count: 3;            -- animation rendered 3 times
}

-- Animation can be written in a shorthand manner.
-- e.g.
--            duration | timing-function | delay | @keyframes
-- animation: 3s ease-out 1s slideFromLeft;
--            duration | @keyframes
-- animation: 3s slideFromLeft;

@keyframes slideFromLeft {
  0%   { transform: translateX(-100%) } -- initial state
  80%  { transform: translateX(10%) }   -- animation finished 80%
  100% { transform: translateX(0%) }    -- final state
}

-- Sometimes elements with CSS animation shake a little just before
-- completing animation, but hidding backface-visibility prevents it
-- from happening.

.text-container {
  backface-visibility: hidden;
}

-- backface-visibility sets whether the back face of an element 
-- is visible when turned towards the user.
-- (ref: https://www.w3schools.com/cssref/css3_pr_backface-visibility.asp)


.sub-text:hover {
  animation-name: slideFromLeft; 
}

-- @keyframes can be used with :hover too

Without @keyframes <identifier> (using transition / transform)

<a href="#" class="btn">Click</a>

.btn {
  transition: all 2s;
}

.btn:active {
  transform: translateY(-1px);
}

-- "transition: all 2s;" determines that "all" properties of .btn will be animated.
-- Instead of "all", you can put width, height etc.

Pseudo classes (:) / Pseudo elements (::)

:active

<a href="#" class="btn">Click</a>

.btn:active {
  transform: translateY(-1px);
}

-- :active represents an element (such as a button) that is being activated by the user.
-- When using a mouse, "activation" typically starts when the user presses down the primary mouse button.
--(ref: https://developer.mozilla.org/en-US/docs/Web/CSS/:active)

::after

<a href="#" class="btn">Btn</a>

.btn {
  margin: 1rem;
  padding: 1rem 2rem;
  background-color: violet;
  display: inline-block;
  border-radius: 10rem;
  position: relative;
}
.btn::after {
  content: '';
  background-color: violet;
  display: inline-block;
  height: 100%;
  width: 100%;
  border-radius: 10rem;
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  transition: all .5s;       
}
-- When you want to make a pseudo element animated, you can put "transition" in it (just like this example)

.btn:hover::after { transform: scale(1.5); }
-- hovering .btn makes it 1.5 times bigger

.btn:active::after { transform: scale(1.75); }
-- clicking .btn makes it 1.75 times bigger (than the original one)

:not and :last-child

-- :not represents elements that do not match a list of selectors.
-- :last-child represents the last element among a group of sibling elements.
-- The following example uses SCSS.

.row {
  margin-bottom: 0;

  $:not(:last-child) {
    margin-bottom: .25rem;
  }
}

-- The last .row will NOT have "margin-bottom: .25rem;"

Attribute Selector

ref: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors
[class*="example"] {
  font-size: 2em;
}

-- * <a> elements with an href containing "example
a[href*="test.com"] {
  font-size: 2em;
}

Decorating elements

border-radius

<a href="#" class="btn">Click</a>

.btn {
  border-radius: 50px;
}

-- Here's a useful tool for writing border-radius
-- https://border-radius.com/

box-shadow

<div class="box">
  <p>box-shadow</p>
</div>

.box {
  box-shadow: 10px 5px 5px red; -- offset-x | offset-y | blur-radius | color
}

-- There are other types of syntax, but I found this the easiest to use.
-- (ref: https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow)
-- A usefull tool for writing box-shadow
-- https://www.cssmatic.com/box-shadow

rgb / rgba

.sample-b {
  background-image: linear-gradient(
    to right,
    rgba(255, 0, 0, 0.8),
    rgb(0, 0, 255, 0.8)),
    url(../img/hero.jpg);
}

-- rgba allows you to determine the opacity with rgb.
-- r = Red, g = Green, b = Blue, a = Alpha
-- opacity 1 = Fully opaque (not transparent)
-- opacity 0 = Fully transparent (not opaque)

lighten/darken (SASS functions)

ref: https://sass-lang.com/documentation/modules/color#lighten

a.lighter {
 // #e1d7d2 has lightness 85%, so when lighten() adds 30% it just returns white.
  color: lighten(#e1d7d2, 30%); // white
}

// Lightness 46% becomes 66%.
@debug lighten(#6b717f, 20%); // #a1a5af

// Lightness 20% becomes 80%.
@debug lighten(#036, 60%); // #99ccff

// Lightness 85% becomes 100%.
@debug lighten(#e1d7d2, 30%); // white

Linear Gradients

.sample-a {
  background-image: linear-gradient(to right, red, blue);
}

-- The backgroud color will gradually change from red (left) to blue (right).

background-clip

-- ref: https://developer.mozilla.org/en-US/docs/Web/CSS/background-clip
-- It sets whether an element's background extends underneath its border box, padding box, or content box.

background-clip: text;
-webkit-background-clip: text;
color: transparent;

clip-path

.hero {
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}

-- clip-patch creates a clipping region that sets what part of an element should be shown.
-- other than polygon( ), circle( ) and ellipse( ) are available.
-- (ref: https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path)

-- Here's a useful webapp for writing clip-path
-- https://bennettfeely.com/clippy/

Leave a Reply

Your email address will not be published. Required fields are marked *