Barbarian Meets Coding
barbarianmeetscoding

WebDev, UX & a Pinch of Fantasy

23 minutes read

CSS

Table of Contents

CSS Selectors

Basic Selectors

  • Type selector: Select elements by their type. Ex: a, p, div will select all elements of type a, p and div respectively
  • Id selector: Select elements by their id. Ex: #john-doe will select any element with id john-doe, div#john-doe will select a div element with #jonh-doe id
  • Descendant selector: Select an element inside another element. Ex: p strong will select all strong elements inside a p element, ul li#john-doe will select the li#john-doe element within a ul element, ul#people li will select all li elements within a ul#people element.
  • Class selector: Select elements with a given class. Ex: li.spanish will select all li elements with .spanish class, .spanish will select all elements with .spanish class
  • Univeral selector: Selects every element. Ex: * selects every element, ul * selects every element inside a ul

You can also combine selectors by separating them with ,, that way you can apply the same styling rules to groups of elements. For instance:


li.warning,
li.special,
li.important {
    font-weight: bold;
}

Advanced Selectors

Attribute selectors

The attribute selectors allow you to select elements that have a specific attribute or a specific value for an attribute. The attribute selectors are quite flexible:

  • Select an paragraph with an attribute class: p[class]
  • Select an paragraph whose class attribute value is equal to news: E[class=“news”]
  • Select an paragraph whose class attribute value is a list of whitespace separated values and one of which is news: E[class~=“news”]
  • Select an paragraph whose class attribute value begins with bar: E[class^=“news”]
  • Select an paragraph whose class attribute value ends with bar: E[class$=“news”]
  • Select an paragraph whose class attribute value contains the substring bar: E[class*=“news”]
  • Select an paragraph whose class attribute value is a list of hyphen separated values beginning with bar: E[class|=“news”]

Adjacent sibling selector

Selects an element that directly follows another element. Elements that follow one another are called siblings. They are on the same level of depth, so when I say that an element follows another element directly I mean at the same level of depth within the DOM tree.

plate + apple {
    /* css */
}
<table>
    <plate><apple/></plate>
    <plate></plate>
    <apple/>  <!-- SELECTED -->
    <plate><orange></plate>
    <apple/> <!-- SELECTED -->
    <apple/>
</table>

General sibling selector

As above but this time it selects an element that follows another element (it doesn’t have to be immediately after).

plate ~ apple {
    /* css */
}
<table>
    <plate><apple/></plate>
    <plate></plate>
    <apple/>  <!-- SELECTED -->
    <plate><orange></plate>
    <apple/> <!-- SELECTED -->
    <apple/> <!-- ALSO SELECTED -->
</table>

Child selector

Selects a direct children of another element, a direct children is the first level (direct) descendant.

/* select an apple directly on the table */
table > apple {
    /* css */
}
<table>
    <apple/>  <!-- SELECTED -->
    <plate><apple/></plate>
    <plate><apple/></plate>
    <apple/>  <!-- SELECTED -->
    <plate><orange></plate>
</table>

Pseudo-class and Pseudo-elemnet Selectors

This type of selectors allow providing styling based on information that lies outside of the document tree or that cannot be expressed using the other simple selectors, for instance, whether an a element has been visited or has the mouse pointer hovering over, or whether al element is the first child of another element.

Pseudo-classes are allowed anywhere in selectors while pseudo-elements may only be appended after the last simple selector of the selector.

Pseudo-class Selectors

:first-child and :last-child

:first-child selects the first element inside another element. :last-child selects the last element inside another element. Ex: p:first-child selects all first child p elements, that is all first elements that are also a p element:

/* select the first element in a plate if it is an apple */
plate apple:first-child {
    /* css */
}
<table>
    <apple/>  
    <plate>
        <apple/> <!-- SELECTED -->
        <orange/>
    </plate>
    <apple/>
    <plate>
        <orange/>
        <apple/>
    </plate>
</table>
:only-child

Selects an element that is the only element inside another one:

/* select an apple when it is the only thing on a plate */
plate apple:only-child {
    /* css */
}
<table>
    <apple/>  
    <plate>
        <apple/> <!-- SELECTED -->
    </plate>
    <apple/>
    <plate>
        <orange/>
        <apple/>
    </plate>
</table>
:nth-child selector and :nth-last-child

The nth-child(n) selector selects an element by its order in another element. nth-last-child(n) does the same thing but starting the count from the back. Ex: p:nth-child(2) selects a p that is the second child of an element (both conditions must occur i.e. the second child of an element must be a paragraph).

/* select the second thing on the table if it is a plate */
table plate:nth-child(2) {
    /* css */
}
/* select the third thing on the table from the back if it is a plate */
table plate:nth-last-child(3) {
    /* css */
}
<table>
    <plate/>  
    <plate> <!-- SELECTED --> <!-- SELECTED -->
        <apple/> 
    </plate>
    <apple/>
    <plate> <orange/> </plate>
</table>
:first-of-type and :last-of-type

:first-of-type selects the first element of a specific type. :last-of-type selects the last element of a specific type. Ex: ul a:first-of-type selects the first a element within a ul element, a:first-of-type selects the first a element.

/* select the first apple on the table */
table apple:first-of-type {
    /* css */
}
<table>
    <plate/>  
    <plate> 
        <apple/> <!-- SELECTED -->
    </plate>
    <apple/>
    <plate><orange/></plate>
</table>
:nth-of-type(n)

Selects a specific element based on its type and order in another element. You can also use the special odd or event selectors as a value for n to select elements in odd and even positions. Ex: article p:nth-of-type(2) selects the second paragraph within a article element, but this time, as opposed to the :nth-child selector it doesn’t necessarily have to be the second child.

/* select the second apple on the table */
table apple:nth-of-type(2) {
    /* css */
}
<table>
    <plate/>  
    <plate> 
        <apple/> 
    </plate>
    <apple/> <!-- SELECTED -->
    <plate><orange/></plate>
</table>

Additionally, you can use a more complex formula to select elemnets through :nth-of-type. You can use 3n+2 to select every third element after the second element.

:only-of-type

Selects an element if it is the only one of its type. Ex: ul li:only-of-type selects an li element only if it is the single li inside a ul element.

/* select an apple if it is the only apple in a plate */
plate apple:only-of-type {
    /* css */
}
<table>
    <plate/>  
    <plate> 
        <apple/> <!-- SELECTED -->
        <orange/>
    </plate>
    <apple/> 
    <plate>
        <apple/>
        <apple/>
    </plate>
</table>
:empty

Selects elements that don’t have any children.

/* select plates that are empty */
plate:empty {
    /* css */
}
<table>
    <plate/>  <!-- SELECTED -->
    <plate> 
        <apple/> 
        <orange/>
    </plate>
    <apple/> 
    <plate>
        <apple/>
        <apple/>
    </plate>
</table>
Negation pseudo class

The negation pseudo class :not selects all elements that do not match the negation selector. Ex: article p:not(:first-of-type) selects all p elements but the first one within an article. article:not(.news) selects all article elements that don’t have the class news.

Pseudo-element Selectors

Pseudo-element selectors create abstractions about the document tree beyond those specified by the document language. Pseudo-elements provide authors with the means to style elements such as the first letter or first line of an elements’ content. These are:

  • ::first-line: selects the contents of the first line of an element. Ex p::first-line selects the first line of a p element. It doesn’t match a real element, it matches a pseudo-element that conforming user agents will insert at the beginning of every p element.
  • ::first-letter: selects the first letter of an element, if it is not preceded by any other content (such as images or inline tables) on its line.
  • ::before and ::after: they can be used to describe generated content before or after an element’s own content. Ex: li::before { content: '-'} adds - before the content of any li element.

jQuery Special Selectors

jQuery offers a lot of cool extensions to CSS3 selectors to help you select DOM elements. Some these are:

  • :animated: select all elements being animated
  • [name!="value"]: select all elements that don’t have this attribute, or do have the attribute with another value
  • :button: select all button elements or elements with [type="button"].
  • :checkbox: select all elements of type checkbox
  • :eq(n): select all elements at index n within the matched set
  • :even(): select even elements, zero-indexed
  • :odd(): select odd elements, zero-indexed
  • :file(): select all elements of type file
  • :first(): select the first matched element
  • :gt(n): select all elements at an index greater that n within the matched set
  • :has(): selects elements which contain at least one element that matches the specified selector
  • :header: selects all elements that are headers, like h1, h2, and so on
  • :hidden: selects all elements that are hidden. Hidden elements either have display:0, or type="hidden", or width and height set explicitly to 0, or have an ancestor element that is hidden and therefore they are not shown in the page
  • :image: selects all elements of type image
  • :input: selects all input, textarea, select and button elements
  • :last: selects the last element within a matched set
  • :lt(n): selects all elements at an index lower than index n within the matched set
  • :parent: selects all elements that have at least one child node (either element or text)
  • :password: select all elements of type password
  • :radio: select all elements of type radi
  • :reset: select all elements of type reset
  • :selected: select all elements that are selected (for option elements)
  • :submit: select all elements of type submit
  • :text: select all input elements of type text
  • :visible: slect all elements that are visible (elements that consume space in the document, that is, opacity: 0 and visibility:hidden are considered visible)

Other Selectors

For other selectors visit the W3C CSS3 selectors standard.

Using CSS to Animate Elements

CSS Transforms

CSS transforms allow you to perform visual transformations on elements such as translation, rotation, scaling or skewing.

Translation

The translate transform lets you translate an element in space:

translate(tx, ty)
translateX(tx)
translateY(ty)

For instance:

.move{
    transform: translate(10px, 2em);
}

See JsFiddle for a practical example.

Scaling

The scale transform allows you to scale elements:

scale(sx, sy)
scaleX(sx)
scaleY(sy)

For instance:

.scale{
    transform: scale(2, 0.5);
}

See JsFiddle for a practical example.

Rotation

The rotate transform allows you to rotate elements:

rotate(deg)

For instance:

.rotate{
    transform: rotate(30deg);
}

See JsFiddle for a practical example.

Skewing

The skew transform allows you to skew elements:

skew(anglex, angley)
skewX(angle)
skewY(angle)

For instance:

.skew{
   transform: skew(10deg, 10deg); 
}

See JsFiddle for a practical example.

Combining Transformations

You can also combine transforms together:

.move-and-rotate{
    transform: translate(100px, 50px) rotate(50deg);
}

See JsFiddle for a practical example.

3D Transforms

In addition to the 2D transforms above, css transforms also provides support for 3D transforms by adding the z axis to the previous transforms:


translate3d(tx, ty, tz)
translateZ(tz)
rotate3d(rx, ry, rz, deg)
rotateZ(deg)
scale3d(sx, sy, sz)
/* etc... */

CSS Transitions

Transitions provides a very simple API to control the animation behavior of changing CSS styles. By using transitions you can provide smooth animations while elements transition between CSS style states instead of reflecting these changes in style immediately.

CSS transitions allow you to specify which property to animate, how long the animation will take and how the transition itself will run (will timing function to use, i.e. linear, fast an the beginning and slowly at the end, etc):


.becomes-opaque{
   opacity: 0.5; 
   transition: opacity 1s linear; 
}
.becomes-opaque:hover{
   opacity: 1; 
}

You can see this example on jsfiddle. The complete rule with all its options looks like this:


transition: none | <property> <time> <timing-function> <delay>

Note that you cannot animate all css properies in the universe. This is a list of the css properties that you can animate.

You can also animate multiple properties via css transitions at the same time. For instance:


.becomes-opaque{
    opacity: 0.5;
    transition: opacity 1s, transform .35s ease-in-out;
}

.becomes-opaque:hover{
    opacity: 1;
    transform: translateX(50px);
}

Check this example at jsfiddle. Finally you can transition all properties using all.

CSS Animations

CSS animations bring you one step further from css transitions and allow you to design finely grained animations between different css styles that can affect an element or multiple elements. They are composed of a style that describes the animation itself with the animation CSS rule and a series of keyframes that describe the animation frame by frame:

.infinite-fade-out{
   animation: infinite-fadeout 5s infinite; 
}

@keyframes infinite-fadeout{
    from { opacity: 0; }
    to {opacity: 1;}
}

// also

@keyframes infinite-fadeout{
    0% { opacity: 0; }
    50% {opacity: .75;}
    100% {opacity: 1;}
}

The full short-hand notation for the animation property is:

.myanimation{
    animation: <name> <duration> <timing-function> <delay> <iteration-count> <direction> <fill-mode> <play-state>;
}
// example
.myanimation{
    animation: move 4s linear 0s infinite alternate [none] [running];
}

CSS Layout

Display

The display property in CSS is the most fundamental way to manage layout in CSS. display controls how an element, and sometimes even its children, are laid out within a web page. The display property can take these different values:

  • block: Element generates a block element box with line breaks before and after the element. A block element will normally take the full width of the viewport unless specified otherwise.
  • inline: Element generates an inline element box without line breaks. If we add another inline element it will be laid out in the same line that the first inline element as long as there’s enough space.
  • inline-block: Element generates an block element box that will be flowed with its surrounding content as if it were an inline element.
  • flex: Element behaves like a block element and lays out its content with flexbox.
  • inline-flex: Element behaves like an inline element and lays out its content with flexbox.
  • grid: Element behaves like a block element and lays out its conent with CSS grid.
  • inline-grid: Element behaves like an inline element and lays out its content with CSS gird.
  • none: Element is not displayed.

For more display values take a look at MDN.

Containing block

An element size and position is often affected by its containing block, the content area defined by the nearest block-level ancestor. This content area follows the box model and is determined by the original size of the block-level element minus any margin, border and padding defined in that element.

There are some exceptions as to what becomes the containing block of an element:

  • When position: absolute, the containing block is the padding box of the nearest positioned ancestor.
  • When position: fixed, the containing block is defined by the viewport
  • When position: absolute or fixed, the containing block can also be defined by the nearest ancestor with a transform, filter or perspective

Position

Another important property in CSS layouts is position. The position property determines how an element is positioned within a document. Based on the type of position, we can use the top, right, bottom and left properties to determine the final location of the element. The position property can take these values:

  • static: (This is the default). Element is positioned according to the normal flow of the document. Any additional position properties top, right, etc have no effect.
  • relative: Element is positioned according to the normal flow of the document with an offset that is relative to itself based on the top, right, bottom and left values.
  • absolute: Element is removed from the normal flow of the document and no space is created for the element in the layout (this means that it may overlay other elements). The element is positioned in relation to its nearest positioned ancestor (ancestor that has a position other than static) using the top, right, bottom and left values.
  • fixed: Element is removed from the normal flow of the document and no space is created for the element in the layout (this means that it may overlay other elements). The element is positioned in relation to the containing block established by the viewport using the top, right, bottom and left values. If there’s an ancestor with transform, perspective or filter then the containing block created by that ancestor is used instead of the viewport.
  • sticky: element is positioned according to the normal flow of the document with an offset relative to its nearest scrolling ancestor using the values of top, right, bottom, and left. The sticky element will stick to the nearest ancestor that has a scrolling mechanism (created when the overflow property has a value of hidden, scroll, auto or overlay) even if that ancestor isn’t the nearest ancestor with actual scrolling behavior. The observable behavior of a sticky element is that it is initally positioned like a relative positioned element and once its containing block crosses a specific threshold (e.g. defined by top) it sticks to the viewport until it reaches the end of the containing block.

For a more hands-on experimenting with CSS positionining play with this codepen and for more information about the position CSS property refer to MDN.

Issues with position: sticky

The position: sticky isn’t well supported in all browsers and it may not work under some scenarios:

  • When the overlay property is different from visible in any its parent elements and that ancestor doesn’t have a height set

Issues with position: fixed

The position: fixed may not work in some scenarios:

  • When there’s a transform defined in any of its parent elements.

Flexbox

The display: flex CSS rule lets you build CSS layouts using flexbox. For more information about CSS flexbox take a look at “Building flexible layouts with flexbox”.

Grid

The display: grid CSS rule lets you build CSS layouts using CSS Grid. For more informationa about CSS grid take a look at the CSS grid notebook.

Multicolumn layout

The CSS multicolumn layout allows you to define layouts with multiple columns of text a la newspaper. You enable this type of layout by using either the column-count property that specifies the number of columns to use, or the column-width property that specifies the width of the columns:

article{
    column-count: 3;
}
article {
    column-width: 20em;
}

You can use the following properties to configure the columns in different fashions:

  • columns, you can use the columns shorthand to specify either column-width, column-count or both
  • the browser will calculate the optimal height of the multiple column layout but you can specify height or max-height if you wish to have more control
  • the column-gap property allows you to specify the gap between columns.
  • the column-rule creates a rule(line) between columns
  • the column-span makes it possible for an element to span across all columns when its value is set to all (for instance, this would be helpful for a header element)
  • the column-fill determines how the content is particioned into columns. The content can either be balance as in all columns will have the same height or auto which will make the layout take up the room the content needs.

CSS Regions

CSS Regions are an interesting concept in which you define your content using semantic HMTL 5 elements as usual but, instead of styling this elements with a specific layout directly, you use a specific set of non-semantic elements to define the layout and flow the content from the semantic elements into the layout elements. In order to do this you use flow-into to mark the elements with content:

.content{
    flow-into: mycontent
}

And the flow-from css property to mark the elements that represent the layout.

.layout{
    flow-from: mycontent
}

Where the mycontent is an identifier that connects content with layout.

For more information about css regions look into this article at dev.opera.

Awesome CSS References


Jaime González García

Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.Jaime González García