# 30 Seconds of CSS ![logo](https://i.imgur.com/kPMfyD4.jpg) [![License](https://img.shields.io/badge/license-CC0--1.0-blue.svg)](https://github.com/30-seconds/30-seconds-of-css/blob/master/LICENSE) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) [![Insight.io](https://img.shields.io/badge/insight.io-Ready-brightgreen.svg)](https://insight.io/github.com/30-seconds/30-seconds-of-css/tree/master/?source=0) A curated collection of useful CSS snippets you can understand in 30 seconds or less. Inspired by [30 seconds of code](https://github.com/30-seconds/30-seconds-of-code). ## View online https://css.30secondsofcode.org ## Contributing See CONTRIBUTING.md for the snippet template. #### Related projects - [30 Seconds of Code](https://30secondsofcode.org/) - [30 Seconds of Interviews](https://30secondsofinterviews.org/) - [30 Seconds of React](https://github.com/30-seconds/30-seconds-of-react) ### Animation
View contents * [`Bouncing loader`](#bouncing-loader) * [`Button border animation`](#button-border-animation) * [`Donut spinner`](#donut-spinner) * [`Easing variables`](#easing-variables) * [`Height transition`](#height-transition) * [`Hover shadow box animation`](#hover-shadow-box-animation) * [`Hover underline animation`](#hover-underline-animation) * [`Pulse loader`](#pulse-loader)
### Interactivity
View contents * [`Disable selection`](#disable-selection) * [`Hamburguer Button`](#hamburguer-button) * [`Popout menu`](#popout-menu) * [`Sibling fade`](#sibling-fade)
### Layout
View contents * [`Box-sizing reset`](#box-sizing-reset) * [`Clearfix`](#clearfix) * [`Constant width to height ratio`](#constant-width-to-height-ratio) * [`Display table centering`](#display-table-centering) * [`Evenly distributed children`](#evenly-distributed-children) * [`Fit image in container`](#fit-image-in-container) * [`Flexbox centering`](#flexbox-centering) * [`Ghost trick`](#ghost-trick) * [`Grid centering`](#grid-centering) * [`Last item with remaining available height`](#last-item-with-remaining-available-height) * [`Lobotomized Owl Selector`](#lobotomized-owl-selector) * [`Offscreen`](#offscreen) * [`3-tile layout`](#3-tile-layout) * [`Transform centering`](#transform-centering) * [`Truncate text multiline`](#truncate-text-multiline) * [`Truncate text`](#truncate-text)
### Other
View contents * [`Calc()`](#calc) * [`Custom variables`](#custom-variables)
### Visual
View contents * [`Border with top triangle`](#border-with-top-triangle) * [`Circle`](#circle) * [`Counter`](#counter) * [`Custom scrollbar`](#custom-scrollbar) * [`Custom text selection`](#custom-text-selection) * [`Drop cap`](#drop-cap) * [`Dynamic shadow`](#dynamic-shadow) * [`Etched text`](#etched-text) * [`Focus Within`](#focus-within) * [`Fullscreen`](#fullscreen) * [`Gradient text`](#gradient-text) * [`Hairline border`](#hairline-border) * [`Mouse cursor gradient tracking`](#mouse-cursor-gradient-tracking) * [`Navigation list item hover and focus effect`](#navigation-list-item-hover-and-focus-effect) * [`:not selector`](#not-selector) * [`Overflow scroll gradient`](#overflow-scroll-gradient) * [`Pretty text underline`](#pretty-text-underline) * [`Reset all styles`](#reset-all-styles) * [`Shape separator`](#shape-separator) * [`System font stack`](#system-font-stack) * [`Toggle switch`](#toggle-switch) * [`Transform - Detransform`](#transform---detransform) * [`Triangle`](#triangle) * [`Zebra striped list`](#zebra-striped-list)
--- ## Animation ### Bouncing loader Creates a bouncing loader animation. ```html
``` ```css @keyframes bouncing-loader { to { opacity: 0.1; transform: translate3d(0, -1rem, 0); } } .bouncing-loader { display: flex; justify-content: center; } .bouncing-loader > div { width: 1rem; height: 1rem; margin: 3rem 0.2rem; background: #8385aa; border-radius: 50%; animation: bouncing-loader 0.6s infinite alternate; } .bouncing-loader > div:nth-child(2) { animation-delay: 0.2s; } .bouncing-loader > div:nth-child(3) { animation-delay: 0.4s; } ``` #### Explanation Note: `1rem` is usually `16px`. 1. `@keyframes` defines an animation that has two states, where the element changes `opacity` and is translated up on the 2D plane using `transform: translate3d()`. Using a single axis translation on `transform: translate3d()` improves the performance of the animation. 2. `.bouncing-loader` is the parent container of the bouncing circles and uses `display: flex` and `justify-content: center` to position them in the center. 3. `.bouncing-loader > div`, targets the three child `div`s of the parent to be styled. The `div`s are given a width and height of `1rem`, using `border-radius: 50%` to turn them from squares to circles. 4. `margin: 3rem 0.2rem` specifies that each circle has a top/bottom margin of `3rem` and left/right margin of `0.2rem` so that they do not directly touch each other, giving them some breathing room. 5. `animation` is a shorthand property for the various animation properties: `animation-name`, `animation-duration`, `animation-iteration-count`, `animation-direction` are used. 6. `nth-child(n)` targets the element which is the nth child of its parent. 7. `animation-delay` is used on the second and third `div` respectively, so that each element does not start the animation at the same time. #### Browser support 100.0% - https://caniuse.com/#feat=css-animation
[⬆ Back to top](#contents) ### Button border animation Creates a border animation on hover. ```html
``` ```css .button { background-color: #c47135; border: none; color: #ffffff; outline: none; padding: 12px 40px 10px; position: relative; } .button:before, .button:after { border: 0 solid transparent; transition: all 0.25s; content: ''; height: 24px; position: absolute; width: 24px; } .button:before { border-top: 2px solid #c47135; left: 0px; top: -5px; } .button:after { border-bottom: 2px solid #c47135; bottom: -5px; right: 0px; } .button:hover { background-color: #c47135; } .button:hover:before, .button:hover:after { height: 100%; width: 100%; } ``` #### Explanation - Use the `:before` and `:after` pseduo-elements as borders that animate on hover. #### Browser support 100.0%
[⬆ Back to top](#contents) ### Donut spinner Creates a donut spinner that can be used to indicate the loading of content. ```html
``` ```css @keyframes donut-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .donut { display: inline-block; border: 4px solid rgba(0, 0, 0, 0.1); border-left-color: #7983ff; border-radius: 50%; width: 30px; height: 30px; animation: donut-spin 1.2s linear infinite; } ``` #### Explanation - Use a semi-transparent `border` for the whole element, except one side that will serve as the loading indicator for the donut. Use `animation` to rotate the element. #### Browser support 100.0% ⚠️ Requires prefixes for full support. - https://caniuse.com/#feat=css-animation - https://caniuse.com/#feat=transforms2d
[⬆ Back to top](#contents) ### Easing variables Variables that can be reused for `transition-timing-function` properties, more powerful than the built-in `ease`, `ease-in`, `ease-out` and `ease-in-out`. ```html
Hover
``` ```css :root { /* Place variables in here to use globally */ } .easing-variables { --ease-in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53); --ease-in-cubic: cubic-bezier(0.55, 0.055, 0.675, 0.19); --ease-in-quart: cubic-bezier(0.895, 0.03, 0.685, 0.22); --ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); --ease-in-expo: cubic-bezier(0.95, 0.05, 0.795, 0.035); --ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.335); --ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94); --ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1); --ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1); --ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); --ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1); --ease-out-circ: cubic-bezier(0.075, 0.82, 0.165, 1); --ease-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955); --ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1); --ease-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1); --ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1); --ease-in-out-expo: cubic-bezier(1, 0, 0, 1); --ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.15, 0.86); display: inline-block; width: 75px; height: 75px; padding: 10px; color: white; line-height: 50px; text-align: center; background: #333; transition: transform 1s var(--ease-out-quart); } .easing-variables:hover { transform: rotate(45deg); } ``` #### Explanation - The variables are defined globally within the `:root` CSS pseudo-class which matches the root element of a tree representing the document. - In HTML, `:root` represents the `` element and is identical to the selector `html`, except that its specificity is higher. #### Browser support 96.5% - https://caniuse.com/#feat=css-variables
[⬆ Back to top](#contents) ### Height transition Transitions an element's height from `0` to `auto` when its height is unknown. ```html
Hover me to see a height transition.
content
``` ```css .el { transition: max-height 0.5s; overflow: hidden; max-height: 0; } .trigger:hover > .el { max-height: var(--max-height); } ``` ```js var el = document.querySelector('.el') var height = el.scrollHeight el.style.setProperty('--max-height', height + 'px') ``` #### Explanation 1. `transition: max-height: 0.5s cubic-bezier(...)` specifies that changes to `max-height` should be transitioned over 0.5 seconds, using an `ease-out-quint` timing function. 2. `overflow: hidden` prevents the contents of the hidden element from overflowing its container. 3. `max-height: 0` specifies that the element has no height initially. 4. `.target:hover > .el` specifies that when the parent is hovered over, target a child `.el` within it and use the `--max-height` variable which was defined by JavaScript. --- 1. `el.scrollHeight` is the height of the element including overflow, which will change dynamically based on the content of the element. 2. `el.style.setProperty(...)` sets the `--max-height` CSS variable which is used to specify the `max-height` of the element the target is hovered over, allowing it to transition smoothly from 0 to auto. #### Browser support 96.5%
Requires JavaScript
⚠️ Causes reflow on each animation frame, which will be laggy if there are a large number of elements beneath the element that is transitioning in height. - https://caniuse.com/#feat=css-variables - https://caniuse.com/#feat=css-transitions
[⬆ Back to top](#contents) ### Hover shadow box animation Creates a shadow box around the text when it is hovered. ```html

Box it!

``` ```css .hover-shadow-box-animation { display: inline-block; vertical-align: middle; transform: perspective(1px) translateZ(0); box-shadow: 0 0 1px transparent; margin: 10px; transition-duration: 0.3s; transition-property: box-shadow, transform; } .hover-shadow-box-animation:hover, .hover-shadow-box-animation:focus, .hover-shadow-box-animation:active { box-shadow: 1px 10px 10px -10px rgba(0, 0, 24, 0.5); transform: scale(1.2); } ``` #### Explanation 1. `display: inline-block` to set width and length for `p` element thus making it an `inline-block`. 2. Set `transform: perspective(1px)` to give element a 3D space by affecting the distance between the Z plane and the user and `translate(0)` to reposition the `p` element along z-axis in 3D space. 3. `box-shadow:` to set up the box. 4. `transparent` to make box transparent. 5. `transition-property` to enable transitions for both `box-shadow` and `transform`. 6. `:hover` to activate whole css when hovering is done until `active`. 7. `transform: scale(1.2)` to change the scale, magnifying the text. #### Browser support 100.0% - https://caniuse.com/#feat=transforms3d - https://caniuse.com/#feat=css-transitions
[⬆ Back to top](#contents) ### Hover underline animation Creates an animated underline effect when the text is hovered over. **Credit:** https://flatuicolors.com/ ```html

Hover this text to see the effect!

``` ```css .hover-underline-animation { display: inline-block; position: relative; color: #0087ca; } .hover-underline-animation::after { content: ''; position: absolute; width: 100%; transform: scaleX(0); height: 2px; bottom: 0; left: 0; background-color: #0087ca; transform-origin: bottom right; transition: transform 0.25s ease-out; } .hover-underline-animation:hover::after { transform: scaleX(1); transform-origin: bottom left; } ``` #### Explanation 1. `display: inline-block` makes the block `p` an `inline-block` to prevent the underline from spanning the entire parent width rather than just the content (text). 2. `position: relative` on the element establishes a Cartesian positioning context for pseudo-elements. 3. `::after` defines a pseudo-element. 4. `position: absolute` takes the pseudo element out of the flow of the document and positions it in relation to the parent. 5. `width: 100%` ensures the pseudo-element spans the entire width of the text block. 6. `transform: scaleX(0)` initially scales the pseudo element to 0 so it has no width and is not visible. 7. `bottom: 0` and `left: 0` position it to the bottom left of the block. 8. `transition: transform 0.25s ease-out` means changes to `transform` will be transitioned over 0.25 seconds with an `ease-out` timing function. 9. `transform-origin: bottom right` means the transform anchor point is positioned at the bottom right of the block. 10. `:hover::after` then uses `scaleX(1)` to transition the width to 100%, then changes the `transform-origin` to `bottom left` so that the anchor point is reversed, allowing it transition out in the other direction when hovered off. #### Browser support 100.0% - https://caniuse.com/#feat=transforms2d - https://caniuse.com/#feat=css-transitions
[⬆ Back to top](#contents) ### Pulse loader Creates a pulse effect loader animation using the `animation-delay` property. ```html
``` ```css .ripple-loader { position: relative; width: 64px; height: 64px; } .ripple-loader div { position: absolute; border: 4px solid #76ff03; border-radius: 50%; animation: ripple-loader 1s ease-out infinite; } .ripple-loader div:nth-child(2) { animation-delay: -0.5s; } @keyframes ripple-loader { 0% { top: 32px; left: 32px; width: 0; height: 0; opacity: 1; } 100% { top: 0; left: 0; width: 64px; height: 64px; opacity: 0; } } ``` #### Explanation - Use `@keyframes` to define an animation at two points in the cycle, start (`0%`), where the two `
` elements have no `width` or `height` and are positioned at the center and end (`100%`), where both `
` elements have increased `width` and `height`, but their `position` is reset to `0`. - Use `opacity` to transition from `1` to `0` when animating to give the `
` elements a disappearing effect as they expand. - `.ripple-loader`, which is the parent container, has a predefined `width` and `height`. It uses `position: relative` to position its children. - Use `animation-delay` on the second `
` element, so that each element starts its animation at a different time. #### Browser support 100.0% - https://caniuse.com/#feat=css-animation
[⬆ Back to top](#contents) --- ## Interactivity ### Disable selection Makes the content unselectable. ```html

You can select me.

You can't select me!

``` ```css .unselectable { user-select: none; } ``` #### Explanation - `user-select: none` specifies that the text cannot be selected. #### Browser support 97.5% ⚠️ Requires prefixes for full support.
⚠️ This is not a secure method to prevent users from copying content. - https://caniuse.com/#feat=user-select-none
[⬆ Back to top](#contents) ### Hamburguer Button This is a way to build simple hamburger button for menu bar. ```html ``` ```css .hb, .hb:before, .hb:after { position: relative; width: 30px; height: 5px; border: none; outline: none; background-color: #333; border-radius: 3px; transition: 0.5s; cursor: pointer; } .hb:before, .hb:after { content: ''; position: absolute; top: -7.5px; left: 0; } .hb:after { top: 7.5px; } .hb:hover { background-color: transparent; } .hb:hover:before, .hb:hover:after { top: 0; } .hb:hover::before { transform: rotate(45deg); } .hb:hover::after { transform: rotate(-45deg); } ``` #### Explanation - Use a `