CSS Basics

The Cascade

  • cascades from top to bottom of a style sheet
  • the specificity of the selectors breaks the cascade
  • Every selector in CSS has a specificity weight
selector specificity weight
type 0-0-1
class 0-1-0
ID 1-0-0
style-attribute overrides the above
!importatnt hightest specificity

Therefore, the ID selector will take precedence regardless of where it appears in the cascade, e.g. <div id="circle"></div> will be red:

#circle {
    background: red;
}

div {
    background: green;
}

Hack the Cascade

ul {
  list-style: circle !important;
}

Unset

Change all properties to the parent value if inheritable or the initial value if not

all: unset;

Comments

/* this is a comment in CSS */

Vendor prefixes

  • Mozilla Firefox: -moz-
  • Opera: -o-
  • Microsoft Internet Explorer: -ms-
  • Webkit (Google Chrome and Apple Safari): -webkit-

They still provide support for some of the older browsers that leveraged them. Use them if you wish to support older browsers.


CSS Variables

Define base values for variables in :root

:root {
  --bg-colour: #C5C6C7;
  --text-colour: #1A1B1C;
}

Overwrite variables for specific contexts

.dark {
  --bg-colour: #1A1B1C;
  --text-colour: #C5C6C7;
}

Use variables as property values

section {
  background-color: var(--bg-colour);
  color: var(--text-colour);
}

Fallback value (e.g. if clamp() is not supported)

:root {
  --padding: clamp(1rem, 2vw, 2rem);
}

section {
  padding: var(--padding, 1.5rem);
}

Manipulate CSS Variables from JavaScript

CSS

.flashlight {
  --cursorX: 0px;
  --cursorY: 0px;

  top: var(--cursorX);
  left: var(--cursorY);
}

JavaScript

let flashlight = document.querySelector('.flashlight');
flashlight.style.setProperty("--cursorX", e.offsetX + "px");
flashlight.style.setProperty("--cursorY", e.offsetY + "px");

flashlight.style.removeProperty("--cursorY");

Selectors

selector {
    property: value;
}
Selector CSS
Type div
Class .class
ID #id
Descendant .ancestor .descendant
Direct Child .parent > .child
General Sibling .element ~ .sibling
Adjacent Sibling .element + .sibling
Attribute Present [href]
Attribute Equals [href="value"]
Attribute Contains [href*="value"]
Attribute Begin [href^="value"]
Attribute End [href$="value"]
Attribute Spaced [href~="value"]
Attribute Hyphenated `[href

Type selector

identifies an element based on its type, i.e. HTML tag

div { /* ... */ }

Class selector

allow to apply the same styles to different elements at once by using the same class attribute value across multiple elements

.class { /* ... */ }

GOOD PRACTISE: value that refers to the content of an element

ID selector

target only one unique element per page at a time (not good practise)

#id { /* ... */ }

Child Selectors

Descendant Selector

*<a> element must reside within a <div> with the class attribute value parent-class

  • matches every element that follows an identified ancestor
  • descendant element does not have to come directly after the ancestor element inside the document tree
div.parent-class a {
    /* ... */
}
<div class="parent-class">
    <p>
        <a href="#"></a> <!-- selected -->
    </p>
    <a href="#"></a> <!-- selected -->
</div>

Direct Child Selector

only identify elements that fall directly within some other element

.parent-class > a {
    /* ... */
}
<div class="parent-class">
    <p>
        <a href="#"></a> <!-- not selected -->
    </p>
    <a href="#"></a> <!-- selected -->
</div>

Sibling Selectors

General Sibling Selector

  • elements that share a common parent
  • element is only selected if it comes after the specified element
.element ~ .sibling {
    /* ... */
}
<div class="parent">
    <div class="sibling"></div> <!-- not selected -->
    <div class="element"></div>
    <div class="sibling"></div> <!-- selected -->
    <div class="sibling"></div> <!-- selected -->
</div>

Adjacent Sibling Selector

  • elements that share a common parent
  • only select sibling elements directly following after another sibling element
.element + .sibling {
    /* ... */
}
<div class="parent">
    <div class="sibling"></div> <!-- not selected -->
    <div class="element"></div>
    <div class="sibling"></div> <!-- selected -->
    <div class="sibling"></div> <!-- not selected -->
</div>

Attribute Selectors

  • Attribute Present Selector: element includes an attribute or not
a[target] {
    /* ... */
}
.links[id] {
    /* ... */
}
[class] {
    /* ... */
}
<a href="">Link 1</a> <!-- not selected -->
<a href="" target="_blank">Link 1</a> <!-- selected -->

<nav class="links" id="nav"></nav> <!-- selected -->
<aside class="links"></aside> <!-- not selected -->

<div></div> <!-- not selected -->
<a class="button" href="#"></a> <!-- selected -->
  • Attribute Equals Selector: element includes an attribute and desired matching value
a[href="https://markusdoppler.at"] {
    /* ... */
}
  • Attribute Contains Selector: part of an attribute value
a[href*="markusdoppler"] { /* ... */ }
  • Attribute Begin Selector: attribute value should begin with the stated value
a[href^="https://"] { /* ... */ }
  • Attribute End Selector: attribute value should end with the stated value
a[href$=".pdf"] { /* ... */ }
  • Attribute Spaced Selector: attribute value that should be whitespace-separated, with one word matching the exact stated value
a[rel~="tag"] { /* ... */ }
  • Attribute Hyphenated Selector: attribute value may be hyphen-separated however the hyphen-separated words must begin with the stated value
a[lang|="en"] { /* ... */ }

Pseudo-Classes

  • :active
  • :checked
  • :disabled
  • :empty
  • :enabled
  • :first-child
  • :first-of-type
  • :focus
  • :focus-visible
  • :focus-within
  • :hover
  • :in-range
  • :invalid
  • :lang(language)
  • :last-child
  • :last-of-type
  • :link
  • :not(selector)
  • :nth-child(n)
  • :nth-last-child(n)
  • :nth-last-of-type(n)
  • :nth-of-type(n)
  • :only-of-type
  • :only-child
  • :optional
  • :out-of-range
  • :read-only
  • :read-write
  • :required
  • :root
  • :target – element's id matches fragment in URL
  • :valid
  • :visited

NEW:

  • :not()
  • :is()
  • :where()
  • :has()

Pseudo Classes

.item:not(.dragging) { ... } /* Chrome 88, iOS 9 */

.item:where(.active) { ... } /* Chrome 88, iOS 14 */
.item:where(.active, .allowed) { ... } /* Chrome 88, iOS 14 */

.item:is(.active) { ... } /* Chrome 88, iOS 14 */
.container :is(.mid, .center, .main) .detail { ... } /* Chrome 88, iOS 14 */

.item:focus-within { ... }
.item:focus-visible { ... } /* iOS 15.4 (previously focus-ring) */
  • :where() has specificity 0, :is() has highest specificity within it
  • selectors inside :is and :where can be invalid, others still applied

link specific (define if a link has or hasn’t been visited)

a:link {
    /* ... */
}
a:visited {
    /* ... */
}

User Action Pseudo-classes

when a user moves their cursor over the element

a:hover {
    /* ... */
}

when a user engages an element, such as clicking on an element

a:active {
    /* ... */
}

when a user has made an element the focus point of the page, often by using the keyboard to tab from one element to another

a:focus {
    /* ... */
}

Note: a:hover must come after a:link and a:visited in the CSS definition in order to be effective.

Note: a:active must come after a:hover in the CSS definition in order to be effective.

User Interface State Pseudo-classes

user interface state of elements, particularly within form elements

the :enabled pseudo-class selects an input that is in the default state of enabled and available for use

the :disabled pseudo-class selects an input that has the disabled attribute tied to it

input:enabled {
    /* ... */
}
input:disabled {
    /* ... */
}

for checkbox and radio button input elements

:checked pseudo-class selects checkboxes or radio buttons that are checked

when a checkbox or radio button has neither been selected nor unselected it lives in an indeterminate state

input:checked {
    /* ... */
}
input:indeterminate {
    /* ... */
}

Structural & Position Pseudo-classes

selects the first/last/only child element within its parent element

li:first-child a {
    /* ... */
}
li:last-child a {
    /* ... */
}
li:only-child a {
    /* ... */
}

will select the first/last/only element of its type within a parent

p:first-of-type {
    /* ... */
}
p:last-of-type {
    /* ... */
}
p:only-of-type {
    /* ... */
}

will select the element(s) specified by n

p:nth-child(n)
p:nth-last-child(n)
p:nth-of-type(n)
p:nth-last-of-type(n)

Examples for n:

1
5
3n
2n+1
odd
even
n+2
2n-1
-3n+12
  • Counting begins at 1, i.e. n must be a positive value
  • General syntax is (a×n)±b: every a'th element starting at b (b can be negative; if a is negative, b has to be positive)
  • n+b: every element starting at the b'th

Example:

p:nth-child(n+1) {
    /* ... */
}
<p></p> <!-- not selected -->
<p></p> <!-- selected -->
<p></p> <!-- selected -->
<p></p> <!-- selected -->

Target Pseudo-class

selects the element whose ID attribute value matches the URI fragment identifier (part after # in a URL)

:target { /* ... */ }

Empty Pseudo-class

selects elements that do not contain children or text nodes

:empty { /* ... */ }

Negation Pseudo-class

takes an argument which is filtered out from the selection to be made

div:not(.lovely) { /* ... */ }

Pseudo-elements (also ::pseudo-element)

  • ::after

  • ::before

  • ::first-letter

  • ::first-line

  • ::selection

  • ::marker

  • only one pseudo-element may be used within a selector at a given time

  • first letter/line of text within an element

::first-letter
::first-line

Generated Content Pseudo-elements

  • create new inline level pseudo-elements just inside the selected element
::before {
    content: "";
}
::after {
    content: "(" attr(href) ")";
}

Fragment Pseudo-element

identifies part of the document that has been selected, or highlighted, by a user’s actions

::selection {
    /* ... */
}
::-moz-selection {
    /* ... */
}

Universal selector

  • selects all elements
* {
    /* ... */
}
  • selects every imaginable element
*, *::before, *::after {
    /* ... */
}

Combining selectors

general syntax

prequalifiers key-selector {
    /* ... */
}

combined syntax

only select <div> elements with the class class-name (not the best practise though)

div.class-name {
    /* ... */
}

select all elements within a parent

.parent > * {
    /* ... */
}

Selecting several elements

  • for elements that share the same style
  • apply style to several selectors at one time, seperated with commas ,
b, emph {
    /* ... */
}

The Box model

Box Model

Properties

  • height
  • width
  • padding
  • border
  • margin

Width & Height

for block- and inline-block-level elements

width: 100px;
height: 50px;

min/max width

max-width: 200px;
min-width: 900px;

The best way to use min-width is to define a width value as a percentage and use an absolute value for the min-width property

Margin & Padding

INFO: margin and padding properties are completely transparent and do not accept any color values

Shorthands

  • all four sides
margin: 20px;
padding: 5px;
  • top+bottom & left+right
margin: 10px 20px;
padding: 10px 20px;
  • unique values for all four sides (top - right - bottom - left)
margin: 10px 20px 30px 0px;
padding: 10px 20px 30px 0px;

Longhands

margin-top: 20px;
margin-right: 20px;
margin-bottom: 20px;
margin-left: 20px;

padding-top: 20px;
padding-right: 20px;
padding-bottom: 20px;
padding-left: 20px;

BEST USAGE: When we wish to identify only one margin or padding value

Logical properties

.item {
   margin-block-end: 0.5em;
   margin-block: 0.5em;
   padding-inline: 0.5em;
   border-block: 1px solid black;
   padding-inline: 1px solid black;
   max-inline-size: 400px;
}

Margin Center Trick

in order to center a block-level element (with width property set) inside its parent element, one can use

margin: 0 auto;

Margin Overlap Trick

Set a negative margin to make it overlap its parent box (and possibly other content)

margin: -66px 0 22px 0;

Padding Aspect Ratio Trick

%-value for padding specifies a padding in % of the width of the parent element (even the vertical padding!)

.aspect-ratio-box {
  width: 100%;
  padding-bottom: 66.67%;
}

Border

shorthand

border: 3px solid #fba;

longhand

border-width [→ CSS Lengths]

border-style

  • solid
  • double
  • dashed
  • dotted

border-color [→ CSS Color]

border-top
border-right
border-bottom
border-left
border-top-width
border-top-style
border-top-color

Border Radius

  • round all four corners equally
border-radius: 5px;
border-radius: 50%;
  • round the top-left/bottom-right and top-right/bottom-left corners
border-radius: 5px 10px;
  • round the top-left, top-right, bottom-right, and bottom-left corners
border-radius: 5px 10px 15px 20px;

longhand

border-top-right-radius: 5px;

Box Sizing

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

possible values

  • content-box: default, which means box model is an additive design
  • border-box: any border or padding property values are included within the width and height of an element.

Min, Max, Clamp

Min

.a {
  padding: min(100px, 10vw);
}

Max

.b {
  padding: max(100px, 10vw);
}

Clamp

.b {
  padding: clamp(1rem, 10vw, 2rem);
}

Fluid Fontsize

.c {
  font-size: clamp(1.75rem, 3vw, 2.1rem);
}

@supports not (font-size: clamp(1.75rem, 3vw, 2.1rem)) {
  .c {
    font-size: min(max(1.75rem, 3vw), 2.1rem); 
  }
}

Calc

.d {
  padding: calc(50% - var(--sizeHeader) - 1rem);
}