Init
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules/
|
||||||
|
.cache/
|
||||||
|
.DS_Store
|
||||||
44
CONTRIBUTING.md
Normal file
44
CONTRIBUTING.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
### Snippet name
|
||||||
|
|
||||||
|
Brief description
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<!-- You must create a `snippet-demo` parent block and use it as a namespace with BEM syntax. -->
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<some-element class="snippet-demo__snippet-name"></some-element>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Add your style rules here. -->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
<!-- Use a step-by-step (ordered) list if possible. Keep it concise. -->
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<!-- Use the checkmark or the warning emoji, see the existing snippets. -->
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
|
|
||||||
|
<!-- Whenever possible, link a `caniuse` feature which allows the browser support percentage to be displayed.
|
||||||
|
If no link is provided, it defaults to 99+%. -->
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=some-feature
|
||||||
12
README.md
Normal file
12
README.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# 30 Seconds of CSS
|
||||||
|
|
||||||
|
A curated collection of useful CSS snippets you can understand in 30 seconds or less.
|
||||||
|
Inspired by [30 seconds of code](https://github.com/Chalarangelo/30-seconds-of-code).
|
||||||
|
|
||||||
|
## View online
|
||||||
|
|
||||||
|
https://github.io/atomiks/30-seconds-of-css
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See CONTRIBUTING.md for the snippet template.
|
||||||
9
dist/4d4edbda57043aeeabeac31d2dd12d0d.css
vendored
Normal file
9
dist/4d4edbda57043aeeabeac31d2dd12d0d.css
vendored
Normal file
File diff suppressed because one or more lines are too long
19
dist/4d4edbda57043aeeabeac31d2dd12d0d.js
vendored
Normal file
19
dist/4d4edbda57043aeeabeac31d2dd12d0d.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
dist/76f3fcef6c36c4d7c29fc6fcd102dfe3.png
vendored
Normal file
BIN
dist/76f3fcef6c36c4d7c29fc6fcd102dfe3.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
BIN
dist/cf2ed1ce6be4ba59eed1079db594cc6e.png
vendored
Normal file
BIN
dist/cf2ed1ce6be4ba59eed1079db594cc6e.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
218
dist/index.html
vendored
Normal file
218
dist/index.html
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
favicon-32x32.png
Normal file
BIN
favicon-32x32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
BIN
favicon.ico
Normal file
BIN
favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
987
index.html
Normal file
987
index.html
Normal file
@ -0,0 +1,987 @@
|
|||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>30 Seconds of CSS</title>
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png">
|
||||||
|
<script src="./src/js/index.js" defer=""></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<button class="back-to-top-button">↑</button>
|
||||||
|
<aside class="sidebar">
|
||||||
|
<button class="hamburger hamburger--spin sidebar__menu" type="button">
|
||||||
|
<span class="hamburger-box">
|
||||||
|
<span class="hamburger-inner"></span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<div class="sidebar__links">
|
||||||
|
<a class="sidebar__link" href="#clearfix">Clearfix</a>
|
||||||
|
<a class="sidebar__link" href="#custom-text-selection">Custom text selection</a>
|
||||||
|
<a class="sidebar__link" href="#easing-variables">Easing variables</a>
|
||||||
|
<a class="sidebar__link" href="#etched-text">Etched text</a>
|
||||||
|
<a class="sidebar__link" href="#gradient-text">Gradient text</a>
|
||||||
|
<a class="sidebar__link" href="#hairline-border">Hairline border</a>
|
||||||
|
<a class="sidebar__link" href="#horizontal-and-vertical-centering">Horizontal and vertical centering</a>
|
||||||
|
<a class="sidebar__link" href="#mouse-cursor-gradient-tracking">Mouse cursor gradient tracking</a>
|
||||||
|
<a class="sidebar__link" href="#overflow-scroll-gradient">Overflow scroll gradient</a>
|
||||||
|
<a class="sidebar__link" href="#popout-menu">Popout menu</a>
|
||||||
|
<a class="sidebar__link" href="#pretty-text-underline">Pretty text underline</a>
|
||||||
|
<a class="sidebar__link" href="#shape-separator">Shape separator</a>
|
||||||
|
<a class="sidebar__link" href="#system-font-stack">System font stack</a>
|
||||||
|
<a class="sidebar__link" href="#triangle">Triangle</a>
|
||||||
|
<a class="sidebar__link" href="#truncate-text">Truncate text</a>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<header class="header">
|
||||||
|
<div class="container">
|
||||||
|
<img class="header__logo" draggable="false" src="./src/img/logo.png">
|
||||||
|
<h1 class="header__heading">30 Seconds of <strong class="header__css">CSS</strong></h1>
|
||||||
|
<p class="header__description">
|
||||||
|
A curated collection of useful CSS snippets you can understand in 30 seconds or less.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="main">
|
||||||
|
<div class="container">
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="clearfix">Clearfix</h3>
|
||||||
|
<p>Ensures that an element self-clears its children.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="clearfix">
|
||||||
|
<div class="floated">float a</div>
|
||||||
|
<div class="floated">float b</div>
|
||||||
|
<div class="floated">float c</div>
|
||||||
|
</div>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.clearfix::after {
|
||||||
|
content: '';
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.floated {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__clearfix">
|
||||||
|
<div class="snippet-demo__floated">float a</div>
|
||||||
|
<div class="snippet-demo__floated">float b</div>
|
||||||
|
<div class="snippet-demo__floated">float c</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__clearfix::after {
|
||||||
|
content: '';
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.snippet-demo__floated {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<ol>
|
||||||
|
<li><code>.clearfix::after</code> defines a pseudo element.</li>
|
||||||
|
<li><code>content: ''</code> allows the pseudo element to affect layout.</li>
|
||||||
|
<li><code>clear: both</code> indicates that the left, right or both sides of the element cannot be adjacent to earlier floated elements within the same block formatting context.</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
99+%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="custom-text-selection">Custom text selection</h3>
|
||||||
|
<p>Changes the styling of text selection.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><p class="custom-text-selection">Select some of this text.</p>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.text-selection::selection {
|
||||||
|
background: red;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__custom-text-selection">Select some of this text.</p>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__custom-text-selection::selection {
|
||||||
|
background: red;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<p><code>::selection</code> defines a pseudo selector on an element to style text within it when selected.</p>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
84.6%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">⚠️ Requires prefixes for full support.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=css-selection" target="_blank">https://caniuse.com/#feat=css-selection</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="easing-variables">Easing variables</h3>
|
||||||
|
<p>Variables that can be reused for <code>transition-timing-function</code> properties, more powerful than the built-in <code>ease</code>, <code>ease-in</code>, <code>ease-out</code> and <code>ease-in-out</code>.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="easing-variables"></div>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">:root {
|
||||||
|
--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);
|
||||||
|
}
|
||||||
|
.easing-variables {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background: #333;
|
||||||
|
transition: transform 1s var(--ease-out-quart);
|
||||||
|
}
|
||||||
|
.easing-variables:hover {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__easing-variables">Hover</div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--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);
|
||||||
|
}
|
||||||
|
.snippet-demo__easing-variables {
|
||||||
|
width: 75px;
|
||||||
|
height: 75px;
|
||||||
|
background: #333;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transition: transform 1s var(--ease-out-quart);
|
||||||
|
}
|
||||||
|
.snippet-demo__easing-variables:hover {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<p>The variables are defined globally with the <code>:root</code> CSS pseudo-class, which matches the root element of a tree representing the document. In HTML, <code>:root</code> represents the <code><html></code> element and is identical
|
||||||
|
to the selector html, except that its specificity is higher.</p>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
87.2%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=css-variables" target="_blank">https://caniuse.com/#feat=css-variables</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="etched-text">Etched text</h3>
|
||||||
|
<p>Creates an effect where text appears to be "etched" or engraved into the background.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><p class="etched-text">I appear etched into the background.</p>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.etched-text {
|
||||||
|
text-shadow: 0 2px white;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #b8bec5;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__etched-text">I appear etched into the background.</p>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__etched-text {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #b8bec5;
|
||||||
|
text-shadow: 0 2px 0 white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<p><code>text-shadow: 0 2px white</code> creates a white shadow offset <code>0px</code> horizontally and <code>2px</code> vertically from the origin position.</p>
|
||||||
|
<p>The background must be darker than the shadow for the effect to work.</p>
|
||||||
|
<p>The text color should be slightly faded to make it look like it's engraved/carved out of the background.</p>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
97.9%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=css-textshadow" target="_blank">https://caniuse.com/#feat=css-textshadow</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="gradient-text">Gradient text</h3>
|
||||||
|
<p>Gives text a gradient color.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><p class="gradient-text">Gradient text</p>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.gradient-text {
|
||||||
|
background: -webkit-linear-gradient(pink, red);
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__gradient-text">
|
||||||
|
Gradient text
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__gradient-text {
|
||||||
|
background: -webkit-linear-gradient(pink, red);
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<ol>
|
||||||
|
<li><code>background: -webkit-linear-gradient(...)</code> gives the text element a gradient background.</li>
|
||||||
|
<li><code>webkit-text-fill-color: transparent</code> fills the text with a transparent color.</li>
|
||||||
|
<li><code>webkit-background-clip: text</code> clips the background with the text, filling the text with the gradient background as the color.</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
90.7%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">⚠️ Uses non-standard properties.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=text-stroke" target="_blank">https://caniuse.com/#feat=text-stroke</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="hairline-border">Hairline border</h3>
|
||||||
|
<p>Gives an element a border equal to 1 native device pixel in width, which can look very sharp and crisp.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="hairline-border">text</div>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.hairline-border {
|
||||||
|
box-shadow: 0 0 0 1px;
|
||||||
|
}
|
||||||
|
@media (min-resolution: 2dppx) {
|
||||||
|
.hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-resolution: 3dppx) {
|
||||||
|
.hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.33333333px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-resolution: 4dppx) {
|
||||||
|
.hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__hairline-border">Text with a hairline border around it.</p>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__hairline-border {
|
||||||
|
box-shadow: 0 0 0 1px;
|
||||||
|
}
|
||||||
|
@media (min-resolution: 2dppx) {
|
||||||
|
.snippet-demo__hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-resolution: 3dppx) {
|
||||||
|
.snippet-demo__hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.33333333px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-resolution: 4dppx) {
|
||||||
|
.snippet-demo__hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<ol>
|
||||||
|
<li><code>box-shadow</code>, when only using spread, adds a psuedo-border which can use subpixels*.</li>
|
||||||
|
<li>Use <code>@media (min-resolution: ...)</code> to check the device pixel ratio (<code>1ddpx</code> equals 96 DPI), setting the spread of the <code>box-shadow</code> equal to <code>1 / dppx</code>.</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser Support">Browser Support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
95.0%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">⚠️ Needs alternate syntax and JavaScript user agent checking for full support.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=css-boxshadow" target="_blank">https://caniuse.com/#feat=css-boxshadow</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=css-media-resolution" target="_blank">https://caniuse.com/#feat=css-media-resolution</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr>
|
||||||
|
<p>*Chrome does not support subpixel values on <code>border</code>. Safari does not support subpixel values on <code>box-shadow</code>. Firefox supports subpixel values on both.</p>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="horizontal-and-vertical-centering">Horizontal and vertical centering</h3>
|
||||||
|
<p>Horizontally and vertically centers a child element within a parent element.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="horizontal-and-vertical-centering">
|
||||||
|
<div class="child"></div>
|
||||||
|
</div>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.horizontal-and-vertical-centering {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__horizontal-and-vertical-centering">
|
||||||
|
<p class="snippet-demo__horizontal-and-vertical-centering__child">Centered content.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__horizontal-and-vertical-centering {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<ol>
|
||||||
|
<li><code>display: flex</code> enables flexbox.</li>
|
||||||
|
<li><code>justify-content: center</code> centers the child horizontally.</li>
|
||||||
|
<li><code>align-items: center</code> centers the child vertically.</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
97.8%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">⚠️ Needs prefixes for full support.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=flexbox" target="_blank">https://caniuse.com/#feat=flexbox</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="mouse-cursor-gradient-tracking">Mouse cursor gradient tracking</h3>
|
||||||
|
<p>A hover effect where the gradient follows the mouse cursor.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><button class="mouse-cursor-gradient-tracking">
|
||||||
|
<span>Hover me</span>
|
||||||
|
</button>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.mouse-cursor-gradient-tracking {
|
||||||
|
position: relative;
|
||||||
|
background: #2379f7;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.mouse-cursor-gradient-tracking span {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.mouse-cursor-gradient-tracking::before {
|
||||||
|
--size: 0;
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: var(--x);
|
||||||
|
top: var(--y);
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
background: radial-gradient(circle closest-side, pink, transparent);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition: width .2s ease, height .2s ease;
|
||||||
|
}
|
||||||
|
.mouse-cursor-gradient-tracking:hover::before {
|
||||||
|
--size: 200px;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="JavaScript">JavaScript</h4><pre><code class="lang-js">var btn = document.querySelector('.mouse-cursor-gradient-tracking')
|
||||||
|
btn.onmousemove = function (e) {
|
||||||
|
var x = e.pageX - btn.offsetLeft
|
||||||
|
var y = e.pageY - btn.offsetTop
|
||||||
|
btn.style.setProperty('--x', x + 'px')
|
||||||
|
btn.style.setProperty('--y', y + 'px')
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<button class="snippet-demo__mouse-cursor-gradient-tracking">
|
||||||
|
<span>Hover me</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__mouse-cursor-gradient-tracking {
|
||||||
|
position: relative;
|
||||||
|
background: #2379f7;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.snippet-demo__mouse-cursor-gradient-tracking span {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.snippet-demo__mouse-cursor-gradient-tracking::before {
|
||||||
|
--size: 0;
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: var(--x);
|
||||||
|
top: var(--y);
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
background: radial-gradient(circle closest-side, aqua, rgba(0, 255, 255, 0.0001));
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition: width .2s ease, height .2s ease;
|
||||||
|
}
|
||||||
|
.snippet-demo__mouse-cursor-gradient-tracking:hover::before {
|
||||||
|
--size: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var btn = document.querySelector('.snippet-demo__mouse-cursor-gradient-tracking')
|
||||||
|
btn.onmousemove = function(e) {
|
||||||
|
var x = e.pageX - btn.offsetLeft - btn.offsetParent.offsetLeft
|
||||||
|
var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||||
|
btn.style.setProperty('--x', x + 'px')
|
||||||
|
btn.style.setProperty('--y', y + 'px')
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
</script>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<p><em>TODO</em></p>
|
||||||
|
<p><strong>Note!</strong></p>
|
||||||
|
<p>If the element's parent has a positioning context (<code>position: relative</code>), you will need to subtract its offsets as well.</p>
|
||||||
|
<pre><code class="lang-js">var x = e.pageX - btn.offsetLeft - btn.offsetParent.offsetLeft
|
||||||
|
var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
87.2%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
<div class="snippet__requires-javascript">Requires JavaScript</div>
|
||||||
|
<span class="snippet__support-note">⚠️ Requires JavaScript.</span>
|
||||||
|
<p></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=css-variables" target="_blank">https://caniuse.com/#feat=css-variables</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="overflow-scroll-gradient">Overflow scroll gradient</h3>
|
||||||
|
<p>Adds a fading gradient to an overflowing element to better indicate there is more content to be scrolled.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="overflow-scroll-gradient">
|
||||||
|
<div class="overflow-scroll-gradient__scroller">
|
||||||
|
Content to be scrolled
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.overflow-scroll-gradient {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.overflow-scroll-gradient::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 300px;
|
||||||
|
height: 25px;
|
||||||
|
background: linear-gradient(rgba(255, 255, 255, 0.001), white); /* transparent keyword is broken in Safari */
|
||||||
|
}
|
||||||
|
.overflow-scroll-gradient__scroller {
|
||||||
|
overflow-y: scroll;
|
||||||
|
background: white;
|
||||||
|
width: 300px;
|
||||||
|
height: 250px;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__overflow-scroll-gradient">
|
||||||
|
<div class="snippet-demo__overflow-scroll-gradient__scroller">
|
||||||
|
Content to be scrolled
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__overflow-scroll-gradient {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.snippet-demo__overflow-scroll-gradient::after {
|
||||||
|
content: '';
|
||||||
|
background: linear-gradient(rgba(255, 255, 255, 0.001), white);
|
||||||
|
position: absolute;
|
||||||
|
width: 300px;
|
||||||
|
height: 25px;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.snippet-demo__overflow-scroll-gradient__scroller {
|
||||||
|
overflow-y: scroll;
|
||||||
|
background: white;
|
||||||
|
width: 300px;
|
||||||
|
height: 250px;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
document.querySelector('.snippet-demo__overflow-scroll-gradient__scroller').innerHTML = 'content '.repeat(200)
|
||||||
|
</script>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<ol>
|
||||||
|
<li><code>position: relative</code> on the parent establishes a Cartesian positioning context for psuedo elements.</li>
|
||||||
|
<li><code>::after</code> defines a pseudo element.</li>
|
||||||
|
<li><code>background-image: linear-gradient(...)</code> adds a linear gradient that fades from transparent to white (top to bottom).</li>
|
||||||
|
<li><code>position: absolute</code> takes the pseudo element out of the flow of the document and positions it in relation to the parent.</li>
|
||||||
|
<li><code>width: 300px</code> matches the size of the scrolling element (which is a child of the parent that has the pseudo element).</li>
|
||||||
|
<li><code>height: 25px</code> is the height of the fading gradient psuedo element, which should be kept relatively small.</li>
|
||||||
|
<li><code>bottom: 0</code> positions the pseudo element at the bottom of the parent.</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
94.8%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=css-gradients" target="_blank">https://caniuse.com/#feat=css-gradients</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="popout-menu">Popout menu</h3>
|
||||||
|
<p>Reveals an interactive popout menu on hover.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="reference">
|
||||||
|
<div class="popout-menu">
|
||||||
|
Popout menu
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.reference {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.popout-menu {
|
||||||
|
position: absolute;
|
||||||
|
visibility: hidden;
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
.reference:hover > .popout-menu {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__reference">
|
||||||
|
<div class="snippet-demo__popout-menu">
|
||||||
|
Popout menu
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__reference {
|
||||||
|
background: linear-gradient(135deg, #ff4c9f, #ff7b74);
|
||||||
|
height: 75px;
|
||||||
|
width: 75px;
|
||||||
|
position: relative;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
.snippet-demo__popout-menu {
|
||||||
|
position: absolute;
|
||||||
|
visibility: hidden;
|
||||||
|
left: 100%;
|
||||||
|
background: #333;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.snippet-demo__reference:hover>.snippet-demo__popout-menu {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<ol>
|
||||||
|
<li><code>position: relative</code> on the reference parent establishes a Cartesian positioning context for its child.</li>
|
||||||
|
<li><code>position: absolute</code> takes the popout menu out of the flow of the document and positions it in relation to the parent.</li>
|
||||||
|
<li><code>left: 100%</code> moves the the popout menu 100% of its parent's width from the left.</li>
|
||||||
|
<li><code>visibility: hidden</code> hides the popout menu initially and allows for transitions (unlike <code>display: none</code>).</li>
|
||||||
|
<li><code>.reference:hover > .popout-menu</code> means that when <code>.reference</code> is hovered over, select immediate children with a class of <code>.popout-menu</code> and change their <code>visibility</code> to <code>visible</code>,
|
||||||
|
which shows the popout.</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
99+%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="pretty-text-underline">Pretty text underline</h3>
|
||||||
|
<p>A nicer alternative to <code>text-decoration: underline</code> where descenders do not clip the underline. Natively implemented as <code>text-decoration-skip-ink: auto</code> but it has less control over the underline.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><p class="pretty-text-underline">Pretty text underline without clipping descending letters.</p>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.pretty-text-underline {
|
||||||
|
display: inline;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
text-shadow: 1px 1px 0 #f5f6f9,
|
||||||
|
-1px 1px 0 #f5f6f9,
|
||||||
|
-1px -1px 0 #f5f6f9,
|
||||||
|
1px -1px 0 #f5f6f9;
|
||||||
|
background-image: linear-gradient(90deg, currentColor 100%, transparent 100%);
|
||||||
|
background-position: 0 1.04em;
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
background-size: 1px 1px;
|
||||||
|
}
|
||||||
|
.pretty-text-underline::selection {
|
||||||
|
background-color: rgba(0, 150, 255, 0.3);
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__pretty-text-underline">Pretty text underline without clipping descending letters.</p>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__pretty-text-underline {
|
||||||
|
display: inline;
|
||||||
|
font-size: 18px !important;
|
||||||
|
text-shadow: 1px 1px 0 #f5f6f9, -1px 1px 0 #f5f6f9, -1px -1px 0 #f5f6f9, 1px -1px 0 #f5f6f9;
|
||||||
|
background-image: linear-gradient(90deg, currentColor 100%, transparent 100%);
|
||||||
|
background-position: 0 1.04em;
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
background-size: 1px 1px;
|
||||||
|
}
|
||||||
|
.snippet-demo__pretty-text-underline::selection {
|
||||||
|
background-color: rgba(0, 150, 255, 0.3);
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<ol>
|
||||||
|
<li><code>text-shadow: ...</code> has 4 values with offsets that cover a 4x4 px area to ensure the underline has a "thick" shadow that covers the line where descenders clip it. Use a color that matches the background. For a larger font, use
|
||||||
|
a larger <code>px</code> size.</li>
|
||||||
|
<li><code>background-image: linear-gradient(...)</code> creates a 90deg gradient with the current text color (<code>currentColor</code>).</li>
|
||||||
|
<li>The <code>background-*</code> properties size the gradient as 1x1px at the bottom and repeats it along the x-axis.</li>
|
||||||
|
<li>The <code>::selection</code> pseudo selector ensures the text shadow does not interfere with text selection.
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
94.8%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=css-textshadow" target="_blank">https://caniuse.com/#feat=css-textshadow</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=css-gradients" target="_blank">https://caniuse.com/#feat=css-gradients</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="shape-separator">Shape separator</h3>
|
||||||
|
<p>Uses an SVG shape to separate two different blocks to create more a interesting visual appearance compared to standard horizontal separation.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="shape-separator"></div>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.shape-separator {
|
||||||
|
position: relative;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
.shape-separator::after {
|
||||||
|
content: '';
|
||||||
|
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxLjQxNCI+PHBhdGggZD0iTTEyIDEybDEyIDEySDBsMTItMTJ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 24px;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo is-distinct">
|
||||||
|
<div class="snippet-demo__shape-separator"></div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__shape-separator {
|
||||||
|
position: relative;
|
||||||
|
height: 48px;
|
||||||
|
margin: -0.75rem -1.25rem;
|
||||||
|
}
|
||||||
|
.snippet-demo__shape-separator::after {
|
||||||
|
content: '';
|
||||||
|
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxLjQxNCI+PHBhdGggZD0iTTEyIDEybDEyIDEySDBsMTItMTJ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 24px;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<ol>
|
||||||
|
<li><code>position: relative</code> on the element establishes a Cartesian positioning context for psuedo elements.</li>
|
||||||
|
<li><code>::after</code> defines a pseudo element.</li>
|
||||||
|
<li><code>background-image: url(...)</code> adds the SVG shape (a 24x24 triangle in base64 format) as the background image of the psuedo element, which repeats by default. It must be the same color as the block that is being separated.
|
||||||
|
</li>
|
||||||
|
<li><code>position: absolute</code> takes the pseudo element out of the flow of the document and positions it in relation to the parent.</li>
|
||||||
|
<li><code>width: 100%</code> ensures the element stretches the entire width of its parent.</li>
|
||||||
|
<li><code>height: 24px</code> is the same height as the shape.</li>
|
||||||
|
<li><code>bottom: 0</code> positions the pseudo element at the bottom of the parent.</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
98.0%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=svg" target="_blank">https://caniuse.com/#feat=svg</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="system-font-stack">System font stack</h3>
|
||||||
|
<p>Uses the native font of the operating system to get close to a native app feel.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><p class="system-font-stack">This text uses the system font.</p>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.system-font-stack {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__system-font-stack">This text uses the system font.</p>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__system-font-stack {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<p>The browser looks for each successive font, preferring the first one if possible, and falls back to the next of it cannot find the font (on the system or defined in CSS).</p>
|
||||||
|
<ol>
|
||||||
|
<li><code>-apple-system</code> is San Francisco, used on iOS and macOS (not Chrome however)</li>
|
||||||
|
<li><code>BlinkMacSystemFont</code> is San Francisco, used on macOS Chrome</li>
|
||||||
|
<li><code>Segoe UI</code> is used on Windows 10</li>
|
||||||
|
<li><code>Roboto</code> is used on Android</li>
|
||||||
|
<li><code>Oxygen-Sans</code> is used on GNU+Linux</li>
|
||||||
|
<li><code>Ubuntu</code> is used on Linux</li>
|
||||||
|
<li><code>"Helvetica Neue"</code> and <code>Helvetica</code> is used on macOS 10.10 and below (wrapped in quotes because it has a space)</li>
|
||||||
|
<li><code>Arial</code> is a font widely supported by all operating systems</li>
|
||||||
|
<li><code>sans-serif</code> is the fallback sans-serif font if none of the other fonts are supported</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
99+%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="triangle">Triangle</h3>
|
||||||
|
<p>Creates a triangle shape with pure CSS.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="triangle"></div>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.triangle {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top: 20px solid #333;
|
||||||
|
border-left: 20px solid transparent;
|
||||||
|
border-right: 20px solid transparent;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__triangles">
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-1"></div>
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-2"></div>
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-3"></div>
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-4"></div>
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-5"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__triangles {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.snippet-demo__triangle {
|
||||||
|
display: inline-block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
.snippet-demo__triangle-1 {
|
||||||
|
border-top: 20px solid #333;
|
||||||
|
border-left: 20px solid transparent;
|
||||||
|
border-right: 20px solid transparent;
|
||||||
|
}
|
||||||
|
.snippet-demo__triangle-2 {
|
||||||
|
border-bottom: 20px solid #333;
|
||||||
|
border-left: 20px solid transparent;
|
||||||
|
border-right: 20px solid transparent;
|
||||||
|
}
|
||||||
|
.snippet-demo__triangle-3 {
|
||||||
|
border-left: 20px solid #333;
|
||||||
|
border-top: 20px solid transparent;
|
||||||
|
border-bottom: 20px solid transparent;
|
||||||
|
}
|
||||||
|
.snippet-demo__triangle-4 {
|
||||||
|
border-right: 20px solid #333;
|
||||||
|
border-top: 20px solid transparent;
|
||||||
|
border-bottom: 20px solid transparent;
|
||||||
|
}
|
||||||
|
.snippet-demo__triangle-5 {
|
||||||
|
border-top: 40px solid #333;
|
||||||
|
border-left: 15px solid transparent;
|
||||||
|
border-right: 15px solid transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<p>
|
||||||
|
<a href="https://stackoverflow.com/q/7073484" target="_blank">View this link for a detailed explanation.</a>
|
||||||
|
</p>
|
||||||
|
<p>The color of the border is the color of the triangle. The side the triangle tip points corresponds to the opposite <code>border-*</code> property. For example, a color on <code>border-top</code> means the arrow points downward.</p>
|
||||||
|
<p>Experiment with the <code>px</code> values to change the proportion of the triangle.</p>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
99+%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="snippet">
|
||||||
|
<h3 id="truncate-text">Truncate text</h3>
|
||||||
|
<p>If the text is longer than one line, it will be truncated and end with an ellipsis <code>...</code>.</p>
|
||||||
|
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><p class="truncate-text">If I exceed one line's width, I will be truncated.</p>
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.truncate-text {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h4 data-type="Demo">Demo</h4>
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__truncate-text">
|
||||||
|
This text will be truncated if it exceeds 200px in width.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.snippet-demo__truncate-text {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 200px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h4 data-type="Explanation">Explanation</h4>
|
||||||
|
<ol>
|
||||||
|
<li><code>overflow: hidden</code> prevents the text from overflowing its dimensions (for a block, 100% width and auto height).</li>
|
||||||
|
<li><code>white-space: nowrap</code> prevents the text from exceeding one line in height.</li>
|
||||||
|
<li><code>text-overflow: ellipsis</code> makes it so that if the text exceeds its dimensions, it will end with an ellipsis.</li>
|
||||||
|
</ol>
|
||||||
|
<h4 data-type="Browser support">Browser support</h4>
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
98.1%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://caniuse.com/#feat=text-overflow" target="_blank">https://caniuse.com/#feat=text-overflow</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
<footer class="footer"></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
11210
package-lock.json
generated
Normal file
11210
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
package.json
Normal file
29
package.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "30-seconds-of-css",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "A curated collection of useful CSS snippets.",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "nodemon -e md,js ./scripts/build.js & parcel",
|
||||||
|
"build": "node ./scripts/build.js && npm run prettier && npm run parcel",
|
||||||
|
"parcel": "parcel build index.html --public-url ./",
|
||||||
|
"prettier": "prettier --single-quote --no-semi --print-width=100 ./js/index.js --write './src/**/*.js' './src/**/*.scss'"
|
||||||
|
},
|
||||||
|
"author": "atomiks",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-cli": "^6.26.0",
|
||||||
|
"babel-preset-env": "^1.6.1",
|
||||||
|
"babel-preset-stage-2": "^6.24.1",
|
||||||
|
"caniuse-db": "^1.0.30000810",
|
||||||
|
"jsdom": "^11.6.2",
|
||||||
|
"marked": "^0.3.16",
|
||||||
|
"node-sass": "^4.7.2",
|
||||||
|
"nodemon": "^1.15.1",
|
||||||
|
"normalize.css": "^8.0.0",
|
||||||
|
"parcel-bundler": "^1.6.2",
|
||||||
|
"prettier": "^1.10.2",
|
||||||
|
"pretty": "^2.0.0",
|
||||||
|
"prismjs": "^1.11.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
70
scripts/build.js
Normal file
70
scripts/build.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const marked = require('marked')
|
||||||
|
const pretty = require('pretty')
|
||||||
|
const { JSDOM } = require('jsdom')
|
||||||
|
const caniuseDb = require('caniuse-db/data.json')
|
||||||
|
const { toKebabCase, emptyHTML } = require('../utils/utils.js')
|
||||||
|
|
||||||
|
const renderer = new marked.Renderer()
|
||||||
|
renderer.heading = (text, level) =>
|
||||||
|
level === 3
|
||||||
|
? `<h${level} id="${toKebabCase(text)}">${text}</h${level}>`
|
||||||
|
: `<h${level} data-type="${text}">${text}</h${level}>`
|
||||||
|
renderer.link = (url, _, text) => `<a href="${url}" target="_blank">${text || url}</a>`
|
||||||
|
|
||||||
|
const SNIPPETS_PATH = './snippets'
|
||||||
|
const SNIPPET_CONTAINER_SELECTOR = '.main > .container'
|
||||||
|
|
||||||
|
const createElement = str => {
|
||||||
|
const el = document.createElement('div')
|
||||||
|
el.innerHTML = str
|
||||||
|
return el.firstElementChild
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = markdown => `
|
||||||
|
<div class="snippet">
|
||||||
|
${markdown}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
const document = new JSDOM(fs.readFileSync('./index.html', 'utf8')).window.document
|
||||||
|
const snippetContainer = document.querySelector('.main > .container')
|
||||||
|
const sidebarLinks = document.querySelector('.sidebar__links')
|
||||||
|
emptyHTML(snippetContainer, sidebarLinks)
|
||||||
|
|
||||||
|
for (const snippetFile of fs.readdirSync(SNIPPETS_PATH)) {
|
||||||
|
const snippetPath = path.join(SNIPPETS_PATH, snippetFile)
|
||||||
|
const snippetData = fs.readFileSync(snippetPath, 'utf8')
|
||||||
|
const markdown = marked(snippetData, { renderer })
|
||||||
|
const snippetTemplate = template(markdown)
|
||||||
|
const el = createElement(snippetTemplate)
|
||||||
|
snippetContainer.append(el)
|
||||||
|
|
||||||
|
sidebarLinks.append(
|
||||||
|
createElement(
|
||||||
|
`<a class="sidebar__link" href="#${snippetFile.replace('.md', '')}">${
|
||||||
|
el.querySelector('h3').innerHTML
|
||||||
|
}</a>`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const featUsageShares = (snippetData.match(/https?:\/\/caniuse\.com\/#feat=.*/g) || []).map(
|
||||||
|
feat => {
|
||||||
|
const featData = caniuseDb.data[feat.match(/#feat=(.*)/)[1]]
|
||||||
|
return featData ? Number(featData.usage_perc_y + featData.usage_perc_a) : 100
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
el.querySelector('h4:last-of-type').after(
|
||||||
|
createElement(`
|
||||||
|
<div>
|
||||||
|
<div class="snippet__browser-support">
|
||||||
|
${featUsageShares.length ? Math.min(...featUsageShares).toPrecision(3) : '99+'}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync('./index.html', pretty(document.documentElement.outerHTML, { ocd: true }))
|
||||||
60
snippets/clearfix.md
Normal file
60
snippets/clearfix.md
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
### Clearfix
|
||||||
|
|
||||||
|
Ensures that an element self-clears its children.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="floated">float a</div>
|
||||||
|
<div class="floated">float b</div>
|
||||||
|
<div class="floated">float c</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.clearfix::after {
|
||||||
|
content: '';
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floated {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__clearfix">
|
||||||
|
<div class="snippet-demo__floated">float a</div>
|
||||||
|
<div class="snippet-demo__floated">float b</div>
|
||||||
|
<div class="snippet-demo__floated">float c</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__clearfix::after {
|
||||||
|
content: '';
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__floated {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
1. `.clearfix::after` defines a pseudo element.
|
||||||
|
2. `content: ''` allows the pseudo element to affect layout.
|
||||||
|
3. `clear: both` indicates that the left, right or both sides of the element cannot be adjacent
|
||||||
|
to earlier floated elements within the same block formatting context.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
41
snippets/custom-text-selection.md
Normal file
41
snippets/custom-text-selection.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
### Custom text selection
|
||||||
|
|
||||||
|
Changes the styling of text selection.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="custom-text-selection">Select some of this text.</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.text-selection::selection {
|
||||||
|
background: red;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__custom-text-selection">Select some of this text.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__custom-text-selection::selection {
|
||||||
|
background: red;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
`::selection` defines a pseudo selector on an element to style text within it when selected.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">⚠️ Requires prefixes for full support.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=css-selection
|
||||||
106
snippets/easing-variables.md
Normal file
106
snippets/easing-variables.md
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
### 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
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="easing-variables"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
--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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.easing-variables {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background: #333;
|
||||||
|
transition: transform 1s var(--ease-out-quart);
|
||||||
|
}
|
||||||
|
|
||||||
|
.easing-variables:hover {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__easing-variables">Hover</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__easing-variables {
|
||||||
|
width: 75px;
|
||||||
|
height: 75px;
|
||||||
|
background: #333;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transition: transform 1s var(--ease-out-quart);
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__easing-variables:hover {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
The variables are defined globally with the `:root` CSS pseudo-class, which matches the root element of a tree representing the document. In HTML, `:root` represents the `<html>` element and is identical to the selector html, except that its specificity is higher.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=css-variables
|
||||||
51
snippets/etched-text.md
Normal file
51
snippets/etched-text.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
### Etched text
|
||||||
|
|
||||||
|
Creates an effect where text appears to be "etched" or engraved into the background.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="etched-text">I appear etched into the background.</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.etched-text {
|
||||||
|
text-shadow: 0 2px white;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #b8bec5;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__etched-text">I appear etched into the background.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__etched-text {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #b8bec5;
|
||||||
|
text-shadow: 0 2px 0 white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
`text-shadow: 0 2px white` creates a white shadow offset `0px` horizontally and `2px` vertically
|
||||||
|
from the origin position.
|
||||||
|
|
||||||
|
The background must be darker than the shadow for the effect to work.
|
||||||
|
|
||||||
|
The text color should be slightly faded to make it look like it's engraved/carved out
|
||||||
|
of the background.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=css-textshadow
|
||||||
51
snippets/gradient-text.md
Normal file
51
snippets/gradient-text.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
### Gradient text
|
||||||
|
|
||||||
|
Gives text a gradient color.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="gradient-text">Gradient text</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.gradient-text {
|
||||||
|
background: -webkit-linear-gradient(pink, red);
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__gradient-text">
|
||||||
|
Gradient text
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__gradient-text {
|
||||||
|
background: -webkit-linear-gradient(pink, red);
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
1. `background: -webkit-linear-gradient(...)` gives the text element a gradient background.
|
||||||
|
2. `webkit-text-fill-color: transparent` fills the text with a transparent color.
|
||||||
|
3. `webkit-background-clip: text` clips the background with the text, filling the text with
|
||||||
|
the gradient background as the color.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">⚠️ Uses non-standard properties.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=text-stroke
|
||||||
83
snippets/hairline-border.md
Normal file
83
snippets/hairline-border.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
### Hairline border
|
||||||
|
|
||||||
|
Gives an element a border equal to 1 native device pixel in width, which can look
|
||||||
|
very sharp and crisp.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="hairline-border">text</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.hairline-border {
|
||||||
|
box-shadow: 0 0 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-resolution: 2dppx) {
|
||||||
|
.hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-resolution: 3dppx) {
|
||||||
|
.hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.33333333px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-resolution: 4dppx) {
|
||||||
|
.hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__hairline-border">Text with a hairline border around it.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__hairline-border {
|
||||||
|
box-shadow: 0 0 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-resolution: 2dppx) {
|
||||||
|
.snippet-demo__hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-resolution: 3dppx) {
|
||||||
|
.snippet-demo__hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.33333333px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-resolution: 4dppx) {
|
||||||
|
.snippet-demo__hairline-border {
|
||||||
|
box-shadow: 0 0 0 0.25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
1. `box-shadow`, when only using spread, adds a psuedo-border which can use subpixels\*.
|
||||||
|
2. Use `@media (min-resolution: ...)` to check the device pixel ratio (`1ddpx` equals 96 DPI),
|
||||||
|
setting the spread of the `box-shadow` equal to `1 / dppx`.
|
||||||
|
|
||||||
|
#### Browser Support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">⚠️ Needs alternate syntax and JavaScript user agent checking for full support.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=css-boxshadow
|
||||||
|
* https://caniuse.com/#feat=css-media-resolution
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
\*Chrome does not support subpixel values on `border`. Safari does not support subpixel values on `box-shadow`. Firefox supports subpixel values on both.
|
||||||
50
snippets/horizontal-and-vertical-centering.md
Normal file
50
snippets/horizontal-and-vertical-centering.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
### Horizontal and vertical centering
|
||||||
|
|
||||||
|
Horizontally and vertically centers a child element within a parent element.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="horizontal-and-vertical-centering">
|
||||||
|
<div class="child"></div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.horizontal-and-vertical-centering {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__horizontal-and-vertical-centering">
|
||||||
|
<p class="snippet-demo__horizontal-and-vertical-centering__child">Centered content.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__horizontal-and-vertical-centering {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
1. `display: flex` enables flexbox.
|
||||||
|
2. `justify-content: center` centers the child horizontally.
|
||||||
|
3. `align-items: center` centers the child vertically.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">⚠️ Needs prefixes for full support.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=flexbox
|
||||||
135
snippets/mouse-cursor-gradient-tracking.md
Normal file
135
snippets/mouse-cursor-gradient-tracking.md
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
### Mouse cursor gradient tracking
|
||||||
|
|
||||||
|
A hover effect where the gradient follows the mouse cursor.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button class="mouse-cursor-gradient-tracking">
|
||||||
|
<span>Hover me</span>
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.mouse-cursor-gradient-tracking {
|
||||||
|
position: relative;
|
||||||
|
background: #2379f7;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mouse-cursor-gradient-tracking span {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mouse-cursor-gradient-tracking::before {
|
||||||
|
--size: 0;
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: var(--x);
|
||||||
|
top: var(--y);
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
background: radial-gradient(circle closest-side, pink, transparent);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition: width .2s ease, height .2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mouse-cursor-gradient-tracking:hover::before {
|
||||||
|
--size: 200px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### JavaScript
|
||||||
|
|
||||||
|
```js
|
||||||
|
var btn = document.querySelector('.mouse-cursor-gradient-tracking')
|
||||||
|
btn.onmousemove = function (e) {
|
||||||
|
var x = e.pageX - btn.offsetLeft
|
||||||
|
var y = e.pageY - btn.offsetTop
|
||||||
|
btn.style.setProperty('--x', x + 'px')
|
||||||
|
btn.style.setProperty('--y', y + 'px')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<button class="snippet-demo__mouse-cursor-gradient-tracking">
|
||||||
|
<span>Hover me</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__mouse-cursor-gradient-tracking {
|
||||||
|
position: relative;
|
||||||
|
background: #2379f7;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__mouse-cursor-gradient-tracking span {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__mouse-cursor-gradient-tracking::before {
|
||||||
|
--size: 0;
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: var(--x);
|
||||||
|
top: var(--y);
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
background: radial-gradient(circle closest-side, aqua, rgba(0,255,255,0.0001));
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition: width .2s ease, height .2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__mouse-cursor-gradient-tracking:hover::before {
|
||||||
|
--size: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var btn = document.querySelector('.snippet-demo__mouse-cursor-gradient-tracking')
|
||||||
|
btn.onmousemove = function (e) {
|
||||||
|
var x = e.pageX - btn.offsetLeft - btn.offsetParent.offsetLeft
|
||||||
|
var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||||
|
btn.style.setProperty('--x', x + 'px')
|
||||||
|
btn.style.setProperty('--y', y + 'px')
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
_TODO_
|
||||||
|
|
||||||
|
**Note!**
|
||||||
|
|
||||||
|
If the element's parent has a positioning context (`position: relative`), you will need to subtract
|
||||||
|
its offsets as well.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var x = e.pageX - btn.offsetLeft - btn.offsetParent.offsetLeft
|
||||||
|
var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
<div class="snippet__requires-javascript">Requires JavaScript</div>
|
||||||
|
<span class="snippet__support-note">⚠️ Requires JavaScript.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=css-variables
|
||||||
91
snippets/overflow-scroll-gradient.md
Normal file
91
snippets/overflow-scroll-gradient.md
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
### Overflow scroll gradient
|
||||||
|
|
||||||
|
Adds a fading gradient to an overflowing element to better indicate there is more content to be scrolled.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="overflow-scroll-gradient">
|
||||||
|
<div class="overflow-scroll-gradient__scroller">
|
||||||
|
Content to be scrolled
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.overflow-scroll-gradient {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.overflow-scroll-gradient::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 300px;
|
||||||
|
height: 25px;
|
||||||
|
background: linear-gradient(rgba(255, 255, 255, 0.001), white); /* transparent keyword is broken in Safari */
|
||||||
|
}
|
||||||
|
.overflow-scroll-gradient__scroller {
|
||||||
|
overflow-y: scroll;
|
||||||
|
background: white;
|
||||||
|
width: 300px;
|
||||||
|
height: 250px;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__overflow-scroll-gradient">
|
||||||
|
<div class="snippet-demo__overflow-scroll-gradient__scroller">
|
||||||
|
Content to be scrolled
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__overflow-scroll-gradient {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.snippet-demo__overflow-scroll-gradient::after {
|
||||||
|
content: '';
|
||||||
|
background: linear-gradient(rgba(255, 255, 255, 0.001), white);
|
||||||
|
position: absolute;
|
||||||
|
width: 300px;
|
||||||
|
height: 25px;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.snippet-demo__overflow-scroll-gradient__scroller {
|
||||||
|
overflow-y: scroll;
|
||||||
|
background: white;
|
||||||
|
width: 300px;
|
||||||
|
height: 250px;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.querySelector('.snippet-demo__overflow-scroll-gradient__scroller').innerHTML = 'content '.repeat(200)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
1. `position: relative` on the parent establishes a Cartesian positioning context for psuedo elements.
|
||||||
|
2. `::after` defines a pseudo element.
|
||||||
|
3. `background-image: linear-gradient(...)` adds a linear gradient that fades from transparent to white
|
||||||
|
(top to bottom).
|
||||||
|
4. `position: absolute` takes the pseudo element out of the flow of the document and positions it in relation to the parent.
|
||||||
|
5. `width: 300px` matches the size of the scrolling element (which is a child of the parent that has
|
||||||
|
the pseudo element).
|
||||||
|
6. `height: 25px` is the height of the fading gradient psuedo element, which should be kept relatively small.
|
||||||
|
7. `bottom: 0` positions the pseudo element at the bottom of the parent.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=css-gradients
|
||||||
77
snippets/popout-menu.md
Normal file
77
snippets/popout-menu.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
### Popout menu
|
||||||
|
|
||||||
|
Reveals an interactive popout menu on hover.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="reference">
|
||||||
|
<div class="popout-menu">
|
||||||
|
Popout menu
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.reference {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.popout-menu {
|
||||||
|
position: absolute;
|
||||||
|
visibility: hidden;
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
.reference:hover > .popout-menu {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__reference">
|
||||||
|
<div class="snippet-demo__popout-menu">
|
||||||
|
Popout menu
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__reference {
|
||||||
|
background: linear-gradient(135deg, #ff4c9f, #ff7b74);
|
||||||
|
height: 75px;
|
||||||
|
width: 75px;
|
||||||
|
position: relative;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
.snippet-demo__popout-menu {
|
||||||
|
position: absolute;
|
||||||
|
visibility: hidden;
|
||||||
|
left: 100%;
|
||||||
|
background: #333;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.snippet-demo__reference:hover > .snippet-demo__popout-menu {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
1. `position: relative` on the reference parent establishes a Cartesian positioning context for its child.
|
||||||
|
2. `position: absolute` takes the popout menu out of the flow of the document and positions it
|
||||||
|
in relation to the parent.
|
||||||
|
3. `left: 100%` moves the the popout menu 100% of its parent's width from the left.
|
||||||
|
4. `visibility: hidden` hides the popout menu initially and allows for transitions (unlike `display: none`).
|
||||||
|
5. `.reference:hover > .popout-menu` means that when `.reference` is hovered over, select immediate
|
||||||
|
children with a class of `.popout-menu` and change their `visibility` to `visible`, which shows the popout.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
75
snippets/pretty-text-underline.md
Normal file
75
snippets/pretty-text-underline.md
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
### Pretty text underline
|
||||||
|
|
||||||
|
A nicer alternative to `text-decoration: underline` where descenders do not clip the underline.
|
||||||
|
Natively implemented as `text-decoration-skip-ink: auto` but it has less control over the underline.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="pretty-text-underline">Pretty text underline without clipping descending letters.</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.pretty-text-underline {
|
||||||
|
display: inline;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
text-shadow: 1px 1px 0 #f5f6f9,
|
||||||
|
-1px 1px 0 #f5f6f9,
|
||||||
|
-1px -1px 0 #f5f6f9,
|
||||||
|
1px -1px 0 #f5f6f9;
|
||||||
|
background-image: linear-gradient(90deg, currentColor 100%, transparent 100%);
|
||||||
|
background-position: 0 1.04em;
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
background-size: 1px 1px;
|
||||||
|
}
|
||||||
|
.pretty-text-underline::selection {
|
||||||
|
background-color: rgba(0, 150, 255, 0.3);
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__pretty-text-underline">Pretty text underline without clipping descending letters.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__pretty-text-underline {
|
||||||
|
display: inline;
|
||||||
|
font-size: 18px !important;
|
||||||
|
text-shadow: 1px 1px 0 #f5f6f9,
|
||||||
|
-1px 1px 0 #f5f6f9,
|
||||||
|
-1px -1px 0 #f5f6f9,
|
||||||
|
1px -1px 0 #f5f6f9;
|
||||||
|
background-image: linear-gradient(90deg, currentColor 100%, transparent 100%);
|
||||||
|
background-position: 0 1.04em;
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
background-size: 1px 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__pretty-text-underline::selection {
|
||||||
|
background-color: rgba(0, 150, 255, 0.3);
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
1. `text-shadow: ...` has 4 values with offsets that cover a 4x4 px area to ensure the underline
|
||||||
|
has a "thick" shadow that covers the line where descenders clip it. Use a color
|
||||||
|
that matches the background. For a larger font, use a larger `px` size.
|
||||||
|
2. `background-image: linear-gradient(...)` creates a 90deg gradient with the current
|
||||||
|
text color (`currentColor`).
|
||||||
|
3. The `background-*` properties size the gradient as 1x1px at the bottom and repeats it along the x-axis.
|
||||||
|
4. The `::selection` pseudo selector ensures the text shadow does not interfere with text
|
||||||
|
selection.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=css-textshadow
|
||||||
|
* https://caniuse.com/#feat=css-gradients
|
||||||
66
snippets/shape-separator.md
Normal file
66
snippets/shape-separator.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
### Shape separator
|
||||||
|
|
||||||
|
Uses an SVG shape to separate two different blocks to create more a interesting visual appearance compared to standard horizontal separation.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="shape-separator"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.shape-separator {
|
||||||
|
position: relative;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
.shape-separator::after {
|
||||||
|
content: '';
|
||||||
|
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxLjQxNCI+PHBhdGggZD0iTTEyIDEybDEyIDEySDBsMTItMTJ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 24px;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo is-distinct">
|
||||||
|
<div class="snippet-demo__shape-separator"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__shape-separator {
|
||||||
|
position: relative;
|
||||||
|
height: 48px;
|
||||||
|
margin: -0.75rem -1.25rem;
|
||||||
|
}
|
||||||
|
.snippet-demo__shape-separator::after {
|
||||||
|
content: '';
|
||||||
|
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxLjQxNCI+PHBhdGggZD0iTTEyIDEybDEyIDEySDBsMTItMTJ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 24px;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
1. `position: relative` on the element establishes a Cartesian positioning context for psuedo elements.
|
||||||
|
2. `::after` defines a pseudo element.
|
||||||
|
3. `background-image: url(...)` adds the SVG shape (a 24x24 triangle in base64 format) as the background image
|
||||||
|
of the psuedo element, which repeats by default. It must be the same color as the block that is being
|
||||||
|
separated.
|
||||||
|
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 element stretches the entire width of its parent.
|
||||||
|
6. `height: 24px` is the same height as the shape.
|
||||||
|
7. `bottom: 0` positions the pseudo element at the bottom of the parent.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=svg
|
||||||
48
snippets/system-font-stack.md
Normal file
48
snippets/system-font-stack.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
### System font stack
|
||||||
|
|
||||||
|
Uses the native font of the operating system to get close to a native app feel.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="system-font-stack">This text uses the system font.</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.system-font-stack {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__system-font-stack">This text uses the system font.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__system-font-stack {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
The browser looks for each successive font, preferring the first one if possible, and
|
||||||
|
falls back to the next of it cannot find the font (on the system or defined in CSS).
|
||||||
|
|
||||||
|
1. `-apple-system` is San Francisco, used on iOS and macOS (not Chrome however)
|
||||||
|
2. `BlinkMacSystemFont` is San Francisco, used on macOS Chrome
|
||||||
|
3. `Segoe UI` is used on Windows 10
|
||||||
|
4. `Roboto` is used on Android
|
||||||
|
5. `Oxygen-Sans` is used on GNU+Linux
|
||||||
|
6. `Ubuntu` is used on Linux
|
||||||
|
7. `"Helvetica Neue"` and `Helvetica` is used on macOS 10.10 and below (wrapped in quotes because it has a space)
|
||||||
|
8. `Arial` is a font widely supported by all operating systems
|
||||||
|
9. `sans-serif` is the fallback sans-serif font if none of the other fonts are supported
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
91
snippets/triangle.md
Normal file
91
snippets/triangle.md
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
### Triangle
|
||||||
|
|
||||||
|
Creates a triangle shape with pure CSS.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="triangle"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.triangle {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top: 20px solid #333;
|
||||||
|
border-left: 20px solid transparent;
|
||||||
|
border-right: 20px solid transparent;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<div class="snippet-demo__triangles">
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-1"></div>
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-2"></div>
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-3"></div>
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-4"></div>
|
||||||
|
<div class="snippet-demo__triangle snippet-demo__triangle-5"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__triangles {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__triangle {
|
||||||
|
display: inline-block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__triangle-1 {
|
||||||
|
border-top: 20px solid #333;
|
||||||
|
border-left: 20px solid transparent;
|
||||||
|
border-right: 20px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__triangle-2 {
|
||||||
|
border-bottom: 20px solid #333;
|
||||||
|
border-left: 20px solid transparent;
|
||||||
|
border-right: 20px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__triangle-3 {
|
||||||
|
border-left: 20px solid #333;
|
||||||
|
border-top: 20px solid transparent;
|
||||||
|
border-bottom: 20px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__triangle-4 {
|
||||||
|
border-right: 20px solid #333;
|
||||||
|
border-top: 20px solid transparent;
|
||||||
|
border-bottom: 20px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo__triangle-5 {
|
||||||
|
border-top: 40px solid #333;
|
||||||
|
border-left: 15px solid transparent;
|
||||||
|
border-right: 15px solid transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
[View this link for a detailed explanation.](https://stackoverflow.com/q/7073484)
|
||||||
|
|
||||||
|
The color of the border is the color of the triangle. The side the triangle tip points
|
||||||
|
corresponds to the opposite `border-*` property. For example, a color on `border-top`
|
||||||
|
means the arrow points downward.
|
||||||
|
|
||||||
|
Experiment with the `px` values to change the proportion of the triangle.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
51
snippets/truncate-text.md
Normal file
51
snippets/truncate-text.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
### Truncate text
|
||||||
|
|
||||||
|
If the text is longer than one line, it will be truncated and end with an ellipsis `...`.
|
||||||
|
|
||||||
|
#### HTML
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="truncate-text">If I exceed one line's width, I will be truncated.</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
.truncate-text {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Demo
|
||||||
|
|
||||||
|
<div class="snippet-demo">
|
||||||
|
<p class="snippet-demo__truncate-text">
|
||||||
|
This text will be truncated if it exceeds 200px in width.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.snippet-demo__truncate-text {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 200px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
#### Explanation
|
||||||
|
|
||||||
|
1. `overflow: hidden` prevents the text from overflowing its dimensions
|
||||||
|
(for a block, 100% width and auto height).
|
||||||
|
2. `white-space: nowrap` prevents the text from exceeding one line in height.
|
||||||
|
3. `text-overflow: ellipsis` makes it so that if the text exceeds its dimensions, it
|
||||||
|
will end with an ellipsis.
|
||||||
|
|
||||||
|
#### Browser support
|
||||||
|
|
||||||
|
<span class="snippet__support-note">✅ No caveats.</span>
|
||||||
|
|
||||||
|
* https://caniuse.com/#feat=text-overflow
|
||||||
39
src/css/components/back-to-top-button.scss
Normal file
39
src/css/components/back-to-top-button.scss
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
.back-to-top-button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
background: white;
|
||||||
|
width: 4rem;
|
||||||
|
height: 4rem;
|
||||||
|
position: fixed;
|
||||||
|
right: 2rem;
|
||||||
|
bottom: 2rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
user-select: none;
|
||||||
|
box-shadow: 0 0.4rem 0.8rem -0.1rem rgba(0, 32, 128, 0.15);
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
z-index: 1;
|
||||||
|
border: 1px solid rgba(0, 32, 128, 0.1);
|
||||||
|
outline: 0;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
transform: scale(1.1);
|
||||||
|
box-shadow: 0 0.8rem 1.6rem -0.2rem rgba(0, 32, 128, 0.15);
|
||||||
|
color: #35a8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 0.8rem 1.6rem -0.2rem rgba(0, 32, 128, 0.15), 0 0 2px 2px #35a8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-visible {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/css/components/base.scss
Normal file
60
src/css/components/base.scss
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
html {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, Roboto, Segoe UI, 'Helvetica Neue', Helvetica,
|
||||||
|
Arial, sans-serif;
|
||||||
|
background: #f6f7fd;
|
||||||
|
color: rgb(50, 75, 100);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #157bda;
|
||||||
|
text-decoration: none;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #0090ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid rgba(0, 32, 128, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
padding-left: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1000px;
|
||||||
|
padding: 0 2%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main > .container {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 579px) {
|
||||||
|
.main > .container {
|
||||||
|
padding: 0 2%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
html {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.content-wrapper {
|
||||||
|
margin-left: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
927
src/css/components/hamburger.scss
Normal file
927
src/css/components/hamburger.scss
Normal file
@ -0,0 +1,927 @@
|
|||||||
|
/*!
|
||||||
|
* Hamburgers
|
||||||
|
* @description Tasty CSS-animated hamburgers
|
||||||
|
* @author Jonathan Suh @jonsuh
|
||||||
|
* @site https://jonsuh.com/hamburgers
|
||||||
|
* @link https://github.com/jonsuh/hamburgers
|
||||||
|
*/
|
||||||
|
.hamburger {
|
||||||
|
padding: 1rem;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
transition-property: opacity, filter;
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
text-transform: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: visible;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.hamburger:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-box {
|
||||||
|
width: 40px;
|
||||||
|
height: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-inner {
|
||||||
|
display: block;
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
.hamburger-inner,
|
||||||
|
.hamburger-inner::before,
|
||||||
|
.hamburger-inner::after {
|
||||||
|
width: 36px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #e3f5ff;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: absolute;
|
||||||
|
transition-property: transform;
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
transition-timing-function: ease;
|
||||||
|
}
|
||||||
|
.hamburger-inner::before,
|
||||||
|
.hamburger-inner::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.hamburger-inner::before {
|
||||||
|
top: -10px;
|
||||||
|
}
|
||||||
|
.hamburger-inner::after {
|
||||||
|
bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3DX
|
||||||
|
*/
|
||||||
|
.hamburger--3dx .hamburger-box {
|
||||||
|
perspective: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dx .hamburger-inner {
|
||||||
|
transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
|
||||||
|
background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--3dx .hamburger-inner::before,
|
||||||
|
.hamburger--3dx .hamburger-inner::after {
|
||||||
|
transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dx.is-active .hamburger-inner {
|
||||||
|
background-color: transparent;
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dx.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(45deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dx.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -10px, 0) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3DX Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--3dx-r .hamburger-box {
|
||||||
|
perspective: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dx-r .hamburger-inner {
|
||||||
|
transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
|
||||||
|
background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--3dx-r .hamburger-inner::before,
|
||||||
|
.hamburger--3dx-r .hamburger-inner::after {
|
||||||
|
transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dx-r.is-active .hamburger-inner {
|
||||||
|
background-color: transparent;
|
||||||
|
transform: rotateY(-180deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dx-r.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(45deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dx-r.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -10px, 0) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3DY
|
||||||
|
*/
|
||||||
|
.hamburger--3dy .hamburger-box {
|
||||||
|
perspective: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dy .hamburger-inner {
|
||||||
|
transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
|
||||||
|
background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--3dy .hamburger-inner::before,
|
||||||
|
.hamburger--3dy .hamburger-inner::after {
|
||||||
|
transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dy.is-active .hamburger-inner {
|
||||||
|
background-color: transparent;
|
||||||
|
transform: rotateX(-180deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dy.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(45deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dy.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -10px, 0) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3DY Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--3dy-r .hamburger-box {
|
||||||
|
perspective: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dy-r .hamburger-inner {
|
||||||
|
transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
|
||||||
|
background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--3dy-r .hamburger-inner::before,
|
||||||
|
.hamburger--3dy-r .hamburger-inner::after {
|
||||||
|
transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dy-r.is-active .hamburger-inner {
|
||||||
|
background-color: transparent;
|
||||||
|
transform: rotateX(180deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dy-r.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(45deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dy-r.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -10px, 0) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3DXY
|
||||||
|
*/
|
||||||
|
.hamburger--3dxy .hamburger-box {
|
||||||
|
perspective: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dxy .hamburger-inner {
|
||||||
|
transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
|
||||||
|
background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--3dxy .hamburger-inner::before,
|
||||||
|
.hamburger--3dxy .hamburger-inner::after {
|
||||||
|
transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dxy.is-active .hamburger-inner {
|
||||||
|
background-color: transparent;
|
||||||
|
transform: rotateX(180deg) rotateY(180deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dxy.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(45deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dxy.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -10px, 0) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3DXY Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--3dxy-r .hamburger-box {
|
||||||
|
perspective: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dxy-r .hamburger-inner {
|
||||||
|
transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
|
||||||
|
background-color 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--3dxy-r .hamburger-inner::before,
|
||||||
|
.hamburger--3dxy-r .hamburger-inner::after {
|
||||||
|
transition: transform 0s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--3dxy-r.is-active .hamburger-inner {
|
||||||
|
background-color: transparent;
|
||||||
|
transform: rotateX(180deg) rotateY(180deg) rotateZ(-180deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dxy-r.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(45deg);
|
||||||
|
}
|
||||||
|
.hamburger--3dxy-r.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -10px, 0) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arrow
|
||||||
|
*/
|
||||||
|
.hamburger--arrow.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(-8px, 0, 0) rotate(-45deg) scale(0.7, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--arrow.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(-8px, 0, 0) rotate(45deg) scale(0.7, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arrow Right
|
||||||
|
*/
|
||||||
|
.hamburger--arrow-r.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(8px, 0, 0) rotate(45deg) scale(0.7, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--arrow-r.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(8px, 0, 0) rotate(-45deg) scale(0.7, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arrow Alt
|
||||||
|
*/
|
||||||
|
.hamburger--arrowalt .hamburger-inner::before {
|
||||||
|
transition: top 0.1s 0.1s ease, transform 0.1s cubic-bezier(0.165, 0.84, 0.44, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--arrowalt .hamburger-inner::after {
|
||||||
|
transition: bottom 0.1s 0.1s ease, transform 0.1s cubic-bezier(0.165, 0.84, 0.44, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--arrowalt.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
transform: translate3d(-8px, -10px, 0) rotate(-45deg) scale(0.7, 1);
|
||||||
|
transition: top 0.1s ease, transform 0.1s 0.1s cubic-bezier(0.895, 0.03, 0.685, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--arrowalt.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: translate3d(-8px, 10px, 0) rotate(45deg) scale(0.7, 1);
|
||||||
|
transition: bottom 0.1s ease, transform 0.1s 0.1s cubic-bezier(0.895, 0.03, 0.685, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arrow Alt Right
|
||||||
|
*/
|
||||||
|
.hamburger--arrowalt-r .hamburger-inner::before {
|
||||||
|
transition: top 0.1s 0.1s ease, transform 0.1s cubic-bezier(0.165, 0.84, 0.44, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--arrowalt-r .hamburger-inner::after {
|
||||||
|
transition: bottom 0.1s 0.1s ease, transform 0.1s cubic-bezier(0.165, 0.84, 0.44, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--arrowalt-r.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
transform: translate3d(8px, -10px, 0) rotate(45deg) scale(0.7, 1);
|
||||||
|
transition: top 0.1s ease, transform 0.1s 0.1s cubic-bezier(0.895, 0.03, 0.685, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--arrowalt-r.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: translate3d(8px, 10px, 0) rotate(-45deg) scale(0.7, 1);
|
||||||
|
transition: bottom 0.1s ease, transform 0.1s 0.1s cubic-bezier(0.895, 0.03, 0.685, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arrow Turn
|
||||||
|
*/
|
||||||
|
.hamburger--arrowturn.is-active .hamburger-inner {
|
||||||
|
transform: rotate(-180deg);
|
||||||
|
}
|
||||||
|
.hamburger--arrowturn.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(8px, 0, 0) rotate(45deg) scale(0.7, 1);
|
||||||
|
}
|
||||||
|
.hamburger--arrowturn.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(8px, 0, 0) rotate(-45deg) scale(0.7, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arrow Turn Right
|
||||||
|
*/
|
||||||
|
.hamburger--arrowturn-r.is-active .hamburger-inner {
|
||||||
|
transform: rotate(-180deg);
|
||||||
|
}
|
||||||
|
.hamburger--arrowturn-r.is-active .hamburger-inner::before {
|
||||||
|
transform: translate3d(-8px, 0, 0) rotate(-45deg) scale(0.7, 1);
|
||||||
|
}
|
||||||
|
.hamburger--arrowturn-r.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(-8px, 0, 0) rotate(45deg) scale(0.7, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Boring
|
||||||
|
*/
|
||||||
|
.hamburger--boring .hamburger-inner,
|
||||||
|
.hamburger--boring .hamburger-inner::before,
|
||||||
|
.hamburger--boring .hamburger-inner::after {
|
||||||
|
transition-property: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--boring.is-active .hamburger-inner {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
.hamburger--boring.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.hamburger--boring.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Collapse
|
||||||
|
*/
|
||||||
|
.hamburger--collapse .hamburger-inner {
|
||||||
|
top: auto;
|
||||||
|
bottom: 0;
|
||||||
|
transition-duration: 0.13s;
|
||||||
|
transition-delay: 0.13s;
|
||||||
|
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--collapse .hamburger-inner::after {
|
||||||
|
top: -20px;
|
||||||
|
transition: top 0.2s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), opacity 0.1s linear;
|
||||||
|
}
|
||||||
|
.hamburger--collapse .hamburger-inner::before {
|
||||||
|
transition: top 0.12s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1),
|
||||||
|
transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--collapse.is-active .hamburger-inner {
|
||||||
|
transform: translate3d(0, -10px, 0) rotate(-45deg);
|
||||||
|
transition-delay: 0.22s;
|
||||||
|
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--collapse.is-active .hamburger-inner::after {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: top 0.2s cubic-bezier(0.33333, 0, 0.66667, 0.33333), opacity 0.1s 0.22s linear;
|
||||||
|
}
|
||||||
|
.hamburger--collapse.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
transition: top 0.1s 0.16s cubic-bezier(0.33333, 0, 0.66667, 0.33333),
|
||||||
|
transform 0.13s 0.25s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Collapse Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--collapse-r .hamburger-inner {
|
||||||
|
top: auto;
|
||||||
|
bottom: 0;
|
||||||
|
transition-duration: 0.13s;
|
||||||
|
transition-delay: 0.13s;
|
||||||
|
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--collapse-r .hamburger-inner::after {
|
||||||
|
top: -20px;
|
||||||
|
transition: top 0.2s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), opacity 0.1s linear;
|
||||||
|
}
|
||||||
|
.hamburger--collapse-r .hamburger-inner::before {
|
||||||
|
transition: top 0.12s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1),
|
||||||
|
transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--collapse-r.is-active .hamburger-inner {
|
||||||
|
transform: translate3d(0, -10px, 0) rotate(45deg);
|
||||||
|
transition-delay: 0.22s;
|
||||||
|
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--collapse-r.is-active .hamburger-inner::after {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: top 0.2s cubic-bezier(0.33333, 0, 0.66667, 0.33333), opacity 0.1s 0.22s linear;
|
||||||
|
}
|
||||||
|
.hamburger--collapse-r.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
transition: top 0.1s 0.16s cubic-bezier(0.33333, 0, 0.66667, 0.33333),
|
||||||
|
transform 0.13s 0.25s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Elastic
|
||||||
|
*/
|
||||||
|
.hamburger--elastic .hamburger-inner {
|
||||||
|
top: 2px;
|
||||||
|
transition-duration: 0.275s;
|
||||||
|
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||||
|
}
|
||||||
|
.hamburger--elastic .hamburger-inner::before {
|
||||||
|
top: 10px;
|
||||||
|
transition: opacity 0.125s 0.275s ease;
|
||||||
|
}
|
||||||
|
.hamburger--elastic .hamburger-inner::after {
|
||||||
|
top: 20px;
|
||||||
|
transition: transform 0.275s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--elastic.is-active .hamburger-inner {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(135deg);
|
||||||
|
transition-delay: 0.075s;
|
||||||
|
}
|
||||||
|
.hamburger--elastic.is-active .hamburger-inner::before {
|
||||||
|
transition-delay: 0s;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.hamburger--elastic.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -20px, 0) rotate(-270deg);
|
||||||
|
transition-delay: 0.075s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Elastic Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--elastic-r .hamburger-inner {
|
||||||
|
top: 2px;
|
||||||
|
transition-duration: 0.275s;
|
||||||
|
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||||
|
}
|
||||||
|
.hamburger--elastic-r .hamburger-inner::before {
|
||||||
|
top: 10px;
|
||||||
|
transition: opacity 0.125s 0.275s ease;
|
||||||
|
}
|
||||||
|
.hamburger--elastic-r .hamburger-inner::after {
|
||||||
|
top: 20px;
|
||||||
|
transition: transform 0.275s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--elastic-r.is-active .hamburger-inner {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(-135deg);
|
||||||
|
transition-delay: 0.075s;
|
||||||
|
}
|
||||||
|
.hamburger--elastic-r.is-active .hamburger-inner::before {
|
||||||
|
transition-delay: 0s;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.hamburger--elastic-r.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -20px, 0) rotate(270deg);
|
||||||
|
transition-delay: 0.075s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Emphatic
|
||||||
|
*/
|
||||||
|
.hamburger--emphatic {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic .hamburger-inner {
|
||||||
|
transition: background-color 0.125s 0.175s ease-in;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic .hamburger-inner::before {
|
||||||
|
left: 0;
|
||||||
|
transition: transform 0.125s cubic-bezier(0.6, 0.04, 0.98, 0.335), top 0.05s 0.125s linear,
|
||||||
|
left 0.125s 0.175s ease-in;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic .hamburger-inner::after {
|
||||||
|
top: 10px;
|
||||||
|
right: 0;
|
||||||
|
transition: transform 0.125s cubic-bezier(0.6, 0.04, 0.98, 0.335), top 0.05s 0.125s linear,
|
||||||
|
right 0.125s 0.175s ease-in;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic.is-active .hamburger-inner {
|
||||||
|
transition-delay: 0s;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic.is-active .hamburger-inner::before {
|
||||||
|
left: -80px;
|
||||||
|
top: -80px;
|
||||||
|
transform: translate3d(80px, 80px, 0) rotate(45deg);
|
||||||
|
transition: left 0.125s ease-out, top 0.05s 0.125s linear,
|
||||||
|
transform 0.125s 0.175s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||||
|
}
|
||||||
|
.hamburger--emphatic.is-active .hamburger-inner::after {
|
||||||
|
right: -80px;
|
||||||
|
top: -80px;
|
||||||
|
transform: translate3d(-80px, 80px, 0) rotate(-45deg);
|
||||||
|
transition: right 0.125s ease-out, top 0.05s 0.125s linear,
|
||||||
|
transform 0.125s 0.175s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Emphatic Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--emphatic-r {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic-r .hamburger-inner {
|
||||||
|
transition: background-color 0.125s 0.175s ease-in;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic-r .hamburger-inner::before {
|
||||||
|
left: 0;
|
||||||
|
transition: transform 0.125s cubic-bezier(0.6, 0.04, 0.98, 0.335), top 0.05s 0.125s linear,
|
||||||
|
left 0.125s 0.175s ease-in;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic-r .hamburger-inner::after {
|
||||||
|
top: 10px;
|
||||||
|
right: 0;
|
||||||
|
transition: transform 0.125s cubic-bezier(0.6, 0.04, 0.98, 0.335), top 0.05s 0.125s linear,
|
||||||
|
right 0.125s 0.175s ease-in;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic-r.is-active .hamburger-inner {
|
||||||
|
transition-delay: 0s;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.hamburger--emphatic-r.is-active .hamburger-inner::before {
|
||||||
|
left: -80px;
|
||||||
|
top: 80px;
|
||||||
|
transform: translate3d(80px, -80px, 0) rotate(-45deg);
|
||||||
|
transition: left 0.125s ease-out, top 0.05s 0.125s linear,
|
||||||
|
transform 0.125s 0.175s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||||
|
}
|
||||||
|
.hamburger--emphatic-r.is-active .hamburger-inner::after {
|
||||||
|
right: -80px;
|
||||||
|
top: 80px;
|
||||||
|
transform: translate3d(-80px, -80px, 0) rotate(45deg);
|
||||||
|
transition: right 0.125s ease-out, top 0.05s 0.125s linear,
|
||||||
|
transform 0.125s 0.175s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Minus
|
||||||
|
*/
|
||||||
|
.hamburger--minus .hamburger-inner::before,
|
||||||
|
.hamburger--minus .hamburger-inner::after {
|
||||||
|
transition: bottom 0.08s 0s ease-out, top 0.08s 0s ease-out, opacity 0s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--minus.is-active .hamburger-inner::before,
|
||||||
|
.hamburger--minus.is-active .hamburger-inner::after {
|
||||||
|
opacity: 0;
|
||||||
|
transition: bottom 0.08s ease-out, top 0.08s ease-out, opacity 0s 0.08s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--minus.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--minus.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Slider
|
||||||
|
*/
|
||||||
|
.hamburger--slider .hamburger-inner {
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
.hamburger--slider .hamburger-inner::before {
|
||||||
|
top: 10px;
|
||||||
|
transition-property: transform, opacity;
|
||||||
|
transition-timing-function: ease;
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
}
|
||||||
|
.hamburger--slider .hamburger-inner::after {
|
||||||
|
top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--slider.is-active .hamburger-inner {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(45deg);
|
||||||
|
}
|
||||||
|
.hamburger--slider.is-active .hamburger-inner::before {
|
||||||
|
transform: rotate(-45deg) translate3d(-5.71429px, -6px, 0);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.hamburger--slider.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -20px, 0) rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Slider Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--slider-r .hamburger-inner {
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
.hamburger--slider-r .hamburger-inner::before {
|
||||||
|
top: 10px;
|
||||||
|
transition-property: transform, opacity;
|
||||||
|
transition-timing-function: ease;
|
||||||
|
transition-duration: 0.15s;
|
||||||
|
}
|
||||||
|
.hamburger--slider-r .hamburger-inner::after {
|
||||||
|
top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--slider-r.is-active .hamburger-inner {
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(-45deg);
|
||||||
|
}
|
||||||
|
.hamburger--slider-r.is-active .hamburger-inner::before {
|
||||||
|
transform: rotate(45deg) translate3d(5.71429px, -6px, 0);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.hamburger--slider-r.is-active .hamburger-inner::after {
|
||||||
|
transform: translate3d(0, -20px, 0) rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spin
|
||||||
|
*/
|
||||||
|
.hamburger--spin .hamburger-inner {
|
||||||
|
transition-duration: 0.22s;
|
||||||
|
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--spin .hamburger-inner::before {
|
||||||
|
transition: top 0.1s 0.25s ease-in, opacity 0.1s ease-in;
|
||||||
|
}
|
||||||
|
.hamburger--spin .hamburger-inner::after {
|
||||||
|
transition: bottom 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--spin.is-active .hamburger-inner {
|
||||||
|
transform: rotate(225deg);
|
||||||
|
transition-delay: 0.12s;
|
||||||
|
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--spin.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: top 0.1s ease-out, opacity 0.1s 0.12s ease-out;
|
||||||
|
}
|
||||||
|
.hamburger--spin.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
transition: bottom 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spin Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--spin-r .hamburger-inner {
|
||||||
|
transition-duration: 0.22s;
|
||||||
|
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--spin-r .hamburger-inner::before {
|
||||||
|
transition: top 0.1s 0.25s ease-in, opacity 0.1s ease-in;
|
||||||
|
}
|
||||||
|
.hamburger--spin-r .hamburger-inner::after {
|
||||||
|
transition: bottom 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--spin-r.is-active .hamburger-inner {
|
||||||
|
transform: rotate(-225deg);
|
||||||
|
transition-delay: 0.12s;
|
||||||
|
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--spin-r.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: top 0.1s ease-out, opacity 0.1s 0.12s ease-out;
|
||||||
|
}
|
||||||
|
.hamburger--spin-r.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
transition: bottom 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spring
|
||||||
|
*/
|
||||||
|
.hamburger--spring .hamburger-inner {
|
||||||
|
top: 2px;
|
||||||
|
transition: background-color 0s 0.13s linear;
|
||||||
|
}
|
||||||
|
.hamburger--spring .hamburger-inner::before {
|
||||||
|
top: 10px;
|
||||||
|
transition: top 0.1s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1),
|
||||||
|
transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--spring .hamburger-inner::after {
|
||||||
|
top: 20px;
|
||||||
|
transition: top 0.2s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1),
|
||||||
|
transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--spring.is-active .hamburger-inner {
|
||||||
|
transition-delay: 0.22s;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.hamburger--spring.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
transition: top 0.1s 0.15s cubic-bezier(0.33333, 0, 0.66667, 0.33333),
|
||||||
|
transform 0.13s 0.22s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(45deg);
|
||||||
|
}
|
||||||
|
.hamburger--spring.is-active .hamburger-inner::after {
|
||||||
|
top: 0;
|
||||||
|
transition: top 0.2s cubic-bezier(0.33333, 0, 0.66667, 0.33333),
|
||||||
|
transform 0.13s 0.22s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
transform: translate3d(0, 10px, 0) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spring Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--spring-r .hamburger-inner {
|
||||||
|
top: auto;
|
||||||
|
bottom: 0;
|
||||||
|
transition-duration: 0.13s;
|
||||||
|
transition-delay: 0s;
|
||||||
|
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--spring-r .hamburger-inner::after {
|
||||||
|
top: -20px;
|
||||||
|
transition: top 0.2s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1), opacity 0s linear;
|
||||||
|
}
|
||||||
|
.hamburger--spring-r .hamburger-inner::before {
|
||||||
|
transition: top 0.1s 0.2s cubic-bezier(0.33333, 0.66667, 0.66667, 1),
|
||||||
|
transform 0.13s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--spring-r.is-active .hamburger-inner {
|
||||||
|
transform: translate3d(0, -10px, 0) rotate(-45deg);
|
||||||
|
transition-delay: 0.22s;
|
||||||
|
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--spring-r.is-active .hamburger-inner::after {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: top 0.2s cubic-bezier(0.33333, 0, 0.66667, 0.33333), opacity 0s 0.22s linear;
|
||||||
|
}
|
||||||
|
.hamburger--spring-r.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
transition: top 0.1s 0.15s cubic-bezier(0.33333, 0, 0.66667, 0.33333),
|
||||||
|
transform 0.13s 0.22s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stand
|
||||||
|
*/
|
||||||
|
.hamburger--stand .hamburger-inner {
|
||||||
|
transition: transform 0.075s 0.15s cubic-bezier(0.55, 0.055, 0.675, 0.19),
|
||||||
|
background-color 0s 0.075s linear;
|
||||||
|
}
|
||||||
|
.hamburger--stand .hamburger-inner::before {
|
||||||
|
transition: top 0.075s 0.075s ease-in, transform 0.075s 0s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--stand .hamburger-inner::after {
|
||||||
|
transition: bottom 0.075s 0.075s ease-in,
|
||||||
|
transform 0.075s 0s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--stand.is-active .hamburger-inner {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
background-color: transparent;
|
||||||
|
transition: transform 0.075s 0s cubic-bezier(0.215, 0.61, 0.355, 1),
|
||||||
|
background-color 0s 0.15s linear;
|
||||||
|
}
|
||||||
|
.hamburger--stand.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
transition: top 0.075s 0.1s ease-out, transform 0.075s 0.15s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--stand.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
transition: bottom 0.075s 0.1s ease-out,
|
||||||
|
transform 0.075s 0.15s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stand Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--stand-r .hamburger-inner {
|
||||||
|
transition: transform 0.075s 0.15s cubic-bezier(0.55, 0.055, 0.675, 0.19),
|
||||||
|
background-color 0s 0.075s linear;
|
||||||
|
}
|
||||||
|
.hamburger--stand-r .hamburger-inner::before {
|
||||||
|
transition: top 0.075s 0.075s ease-in, transform 0.075s 0s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--stand-r .hamburger-inner::after {
|
||||||
|
transition: bottom 0.075s 0.075s ease-in,
|
||||||
|
transform 0.075s 0s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--stand-r.is-active .hamburger-inner {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
background-color: transparent;
|
||||||
|
transition: transform 0.075s 0s cubic-bezier(0.215, 0.61, 0.355, 1),
|
||||||
|
background-color 0s 0.15s linear;
|
||||||
|
}
|
||||||
|
.hamburger--stand-r.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
transition: top 0.075s 0.1s ease-out, transform 0.075s 0.15s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--stand-r.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
transition: bottom 0.075s 0.1s ease-out,
|
||||||
|
transform 0.075s 0.15s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Squeeze
|
||||||
|
*/
|
||||||
|
.hamburger--squeeze .hamburger-inner {
|
||||||
|
transition-duration: 0.075s;
|
||||||
|
transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
.hamburger--squeeze .hamburger-inner::before {
|
||||||
|
transition: top 0.075s 0.12s ease, opacity 0.075s ease;
|
||||||
|
}
|
||||||
|
.hamburger--squeeze .hamburger-inner::after {
|
||||||
|
transition: bottom 0.075s 0.12s ease, transform 0.075s cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--squeeze.is-active .hamburger-inner {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
transition-delay: 0.12s;
|
||||||
|
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
.hamburger--squeeze.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: top 0.075s ease, opacity 0.075s 0.12s ease;
|
||||||
|
}
|
||||||
|
.hamburger--squeeze.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
transition: bottom 0.075s ease, transform 0.075s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vortex
|
||||||
|
*/
|
||||||
|
.hamburger--vortex .hamburger-inner {
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
|
||||||
|
}
|
||||||
|
.hamburger--vortex .hamburger-inner::before,
|
||||||
|
.hamburger--vortex .hamburger-inner::after {
|
||||||
|
transition-duration: 0s;
|
||||||
|
transition-delay: 0.1s;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
}
|
||||||
|
.hamburger--vortex .hamburger-inner::before {
|
||||||
|
transition-property: top, opacity;
|
||||||
|
}
|
||||||
|
.hamburger--vortex .hamburger-inner::after {
|
||||||
|
transition-property: bottom, transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--vortex.is-active .hamburger-inner {
|
||||||
|
transform: rotate(765deg);
|
||||||
|
transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
|
||||||
|
}
|
||||||
|
.hamburger--vortex.is-active .hamburger-inner::before,
|
||||||
|
.hamburger--vortex.is-active .hamburger-inner::after {
|
||||||
|
transition-delay: 0s;
|
||||||
|
}
|
||||||
|
.hamburger--vortex.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.hamburger--vortex.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vortex Reverse
|
||||||
|
*/
|
||||||
|
.hamburger--vortex-r .hamburger-inner {
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
|
||||||
|
}
|
||||||
|
.hamburger--vortex-r .hamburger-inner::before,
|
||||||
|
.hamburger--vortex-r .hamburger-inner::after {
|
||||||
|
transition-duration: 0s;
|
||||||
|
transition-delay: 0.1s;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
}
|
||||||
|
.hamburger--vortex-r .hamburger-inner::before {
|
||||||
|
transition-property: top, opacity;
|
||||||
|
}
|
||||||
|
.hamburger--vortex-r .hamburger-inner::after {
|
||||||
|
transition-property: bottom, transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger--vortex-r.is-active .hamburger-inner {
|
||||||
|
transform: rotate(-765deg);
|
||||||
|
transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
|
||||||
|
}
|
||||||
|
.hamburger--vortex-r.is-active .hamburger-inner::before,
|
||||||
|
.hamburger--vortex-r.is-active .hamburger-inner::after {
|
||||||
|
transition-delay: 0s;
|
||||||
|
}
|
||||||
|
.hamburger--vortex-r.is-active .hamburger-inner::before {
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.hamburger--vortex-r.is-active .hamburger-inner::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
76
src/css/components/header.scss
Normal file
76
src/css/components/header.scss
Normal file
File diff suppressed because one or more lines are too long
104
src/css/components/sidebar.scss
Normal file
104
src/css/components/sidebar.scss
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
.sidebar {
|
||||||
|
background: #202e4e;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 2;
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
box-shadow: 0 0.25rem 0.5rem -0.1rem rgba(0, 32, 128, 0.2);
|
||||||
|
|
||||||
|
&__menu {
|
||||||
|
position: absolute;
|
||||||
|
font-weight: bold;
|
||||||
|
border: none;
|
||||||
|
text-align: left;
|
||||||
|
text-transform: uppercase;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__menu-icon {
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__links {
|
||||||
|
background: #202e4e;
|
||||||
|
overflow-y: auto;
|
||||||
|
transition: transform 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
transform: rotateX(-90deg);
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 378px;
|
||||||
|
margin-top: 44px;
|
||||||
|
box-shadow: 0 0.25rem 0.5rem -0.1rem rgba(0, 32, 128, 0.2);
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
transform: rotateX(0);
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
display: block;
|
||||||
|
color: #e3f5ff;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
transition: all 0.1s ease-out;
|
||||||
|
border-left: 2px solid #576a85;
|
||||||
|
margin: 0.5rem;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #88f4ff;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-color: pink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.sidebar {
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 15%;
|
||||||
|
max-width: 250px;
|
||||||
|
min-width: 200px;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(-30deg, #2a3d67, #14264e);
|
||||||
|
box-shadow: 0.4rem 0.4rem 0.8rem rgba(0, 32, 64, 0.1);
|
||||||
|
overflow-y: auto;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 10px;
|
||||||
|
background-color: #4b6191;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #4b6191;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__links {
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
transform: rotateX(0);
|
||||||
|
margin-top: 0;
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__menu {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
128
src/css/components/snippet.scss
Normal file
128
src/css/components/snippet.scss
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
.snippet {
|
||||||
|
position: relative;
|
||||||
|
background: white;
|
||||||
|
padding: 2rem 5%;
|
||||||
|
box-shadow: 0 0.4rem 0.8rem -0.1rem rgba(0, 32, 128, 0.1), 0 0 0 1px #f0f2f7;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 2rem;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
border-bottom: 1px solid rgba(0, 32, 128, 0.1);
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
margin-top: 0;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
code:not([class*='lang']) {
|
||||||
|
background: #fcfaff;
|
||||||
|
border: 1px solid #e2ddff;
|
||||||
|
color: #4b00da;
|
||||||
|
border-radius: 0.15rem;
|
||||||
|
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0.2rem 0.4rem;
|
||||||
|
margin: 0 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol > li {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
> p {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 1rem 0 0.5rem;
|
||||||
|
line-height: 2;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background: #333;
|
||||||
|
border: 1px solid #c6d6ea;
|
||||||
|
border-bottom-color: darken(#c6d6ea, 5);
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0.25rem 0.5rem -0.1rem rgba(0, 32, 64, 0.15);
|
||||||
|
|
||||||
|
&[data-type='HTML'] {
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
background: linear-gradient(135deg, #ff4c9f, #ff7b74);
|
||||||
|
}
|
||||||
|
&[data-type='CSS'] {
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
background: linear-gradient(135deg, #7983ff, #5f9de9);
|
||||||
|
}
|
||||||
|
&[data-type='JavaScript'] {
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
background: linear-gradient(135deg, #ffb000, #f58818);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__browser-support {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 200;
|
||||||
|
line-height: 1;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subheading.is-html {
|
||||||
|
color: #e22f70;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subheading.is-css {
|
||||||
|
color: #0a91d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subheading.is-explanation {
|
||||||
|
color: #4b00da;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__support-note {
|
||||||
|
color: #9fa5b5;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__requires-javascript {
|
||||||
|
position: absolute;
|
||||||
|
background: red;
|
||||||
|
background: linear-gradient(145deg, #ff003b, #ff4b39);
|
||||||
|
color: white;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
transform: rotate(20deg);
|
||||||
|
font-weight: bold;
|
||||||
|
top: 1rem;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet-demo {
|
||||||
|
background: #f5f6f9;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
padding: 0.75rem 1.25rem;
|
||||||
|
|
||||||
|
&.is-distinct {
|
||||||
|
background: linear-gradient(135deg, #ff4c9f, #ff7b74);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.snippet {
|
||||||
|
&__requires-javascript {
|
||||||
|
right: -0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
146
src/css/deps/prism.css
Normal file
146
src/css/deps/prism.css
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
code[class*='language-'],
|
||||||
|
pre[class*='language-'] {
|
||||||
|
color: rgb(50, 75, 100);
|
||||||
|
background: none;
|
||||||
|
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
word-spacing: normal;
|
||||||
|
word-break: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
line-height: 2;
|
||||||
|
font-size: 1rem;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
|
||||||
|
-webkit-hyphens: none;
|
||||||
|
-moz-hyphens: none;
|
||||||
|
-ms-hyphens: none;
|
||||||
|
hyphens: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*='language-']::-moz-selection,
|
||||||
|
pre[class*='language-'] ::-moz-selection,
|
||||||
|
code[class*='language-']::-moz-selection,
|
||||||
|
code[class*='language-'] ::-moz-selection {
|
||||||
|
text-shadow: none;
|
||||||
|
background: #b3d4fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*='language-']::selection,
|
||||||
|
pre[class*='language-'] ::selection,
|
||||||
|
code[class*='language-']::selection,
|
||||||
|
code[class*='language-'] ::selection {
|
||||||
|
text-shadow: none;
|
||||||
|
background: #b3d4fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
code[class*='language-'],
|
||||||
|
pre[class*='language-'] {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code blocks */
|
||||||
|
pre[class*='language-'] {
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0.75rem 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.is-option {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(pre) > code[class*='language-'],
|
||||||
|
pre[class*='language-'] {
|
||||||
|
background: #f5f6f9;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
:not(pre) > code[class*='language-'] {
|
||||||
|
padding: 0.1em;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.comment,
|
||||||
|
.token.prolog,
|
||||||
|
.token.doctype,
|
||||||
|
.token.cdata {
|
||||||
|
color: #8ca2d3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.selector,
|
||||||
|
.token.attr-name {
|
||||||
|
color: #da7800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.punctuation {
|
||||||
|
color: #93a0c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.namespace {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.tag {
|
||||||
|
color: #e22f70;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.property,
|
||||||
|
.token.boolean,
|
||||||
|
.token.number,
|
||||||
|
.token.constant,
|
||||||
|
.token.symbol,
|
||||||
|
.token.deleted {
|
||||||
|
color: #0087ca;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.string,
|
||||||
|
.language-css .token.string,
|
||||||
|
.token.url,
|
||||||
|
.token.attr-value,
|
||||||
|
.token.char,
|
||||||
|
.token.builtin,
|
||||||
|
.token.inserted {
|
||||||
|
color: #008a7e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.operator,
|
||||||
|
.token.entity,
|
||||||
|
.style .token.string {
|
||||||
|
color: #f53737;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.important,
|
||||||
|
.token.atrule,
|
||||||
|
.token.keyword {
|
||||||
|
color: #7552ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.function {
|
||||||
|
color: #396dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.regex,
|
||||||
|
.token.variable {
|
||||||
|
color: #00a8d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.token.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.entity {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
6
src/css/index.scss
Normal file
6
src/css/index.scss
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
@import './components/base.scss';
|
||||||
|
@import './components/hamburger.scss';
|
||||||
|
@import './components/sidebar.scss';
|
||||||
|
@import './components/header.scss';
|
||||||
|
@import './components/snippet.scss';
|
||||||
|
@import './components/back-to-top-button.scss';
|
||||||
BIN
src/img/logo.png
Normal file
BIN
src/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
14
src/js/components/BackToTopButton.js
Normal file
14
src/js/components/BackToTopButton.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import jump from '../deps/jump'
|
||||||
|
import { select, scrollY, easeOutQuint } from '../deps/utils'
|
||||||
|
|
||||||
|
const backToTopButton = select('.back-to-top-button')
|
||||||
|
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
backToTopButton.classList[scrollY() > 500 ? 'add' : 'remove']('is-visible')
|
||||||
|
})
|
||||||
|
backToTopButton.onclick = () => {
|
||||||
|
jump('.header', {
|
||||||
|
duration: 750,
|
||||||
|
easing: easeOutQuint
|
||||||
|
})
|
||||||
|
}
|
||||||
34
src/js/components/Menu.js
Normal file
34
src/js/components/Menu.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import jump from '../deps/jump'
|
||||||
|
import { select, selectAll, easeOutQuint } from '../deps/utils'
|
||||||
|
|
||||||
|
const menu = select('.hamburger')
|
||||||
|
const links = select('.sidebar__links')
|
||||||
|
const ACTIVE_CLASS = 'is-active'
|
||||||
|
|
||||||
|
const toggle = () => [menu, links].forEach(el => el.classList.toggle(ACTIVE_CLASS))
|
||||||
|
|
||||||
|
menu.addEventListener('click', toggle)
|
||||||
|
|
||||||
|
links.addEventListener('click', e => {
|
||||||
|
setTimeout(toggle, 40)
|
||||||
|
if (e.target.classList.contains('sidebar__link')) {
|
||||||
|
e.preventDefault()
|
||||||
|
jump(e.target.getAttribute('href'), {
|
||||||
|
duration: 750,
|
||||||
|
offset: window.innerWidth <= 768 ? -64 : -32,
|
||||||
|
easing: easeOutQuint
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
document.addEventListener('click', e => {
|
||||||
|
if (
|
||||||
|
!e.target.closest('.sidebar__links') &&
|
||||||
|
!e.target.closest('.hamburger') &&
|
||||||
|
links.classList.contains(ACTIVE_CLASS)
|
||||||
|
) {
|
||||||
|
toggle()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default { toggle }
|
||||||
196
src/js/deps/jump.js
Normal file
196
src/js/deps/jump.js
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
;(function(global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined'
|
||||||
|
? (module.exports = factory())
|
||||||
|
: typeof define === 'function' && define.amd ? define(factory) : (global.Jump = factory())
|
||||||
|
})(this, function() {
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
// Robert Penner's easeInOutQuad
|
||||||
|
|
||||||
|
// find the rest of his easing functions here: http://robertpenner.com/easing/
|
||||||
|
// find them exported for ES6 consumption here: https://github.com/jaxgeller/ez.js
|
||||||
|
|
||||||
|
var easeInOutQuad = function easeInOutQuad(t, b, c, d) {
|
||||||
|
t /= d / 2
|
||||||
|
if (t < 1) return c / 2 * t * t + b
|
||||||
|
t--
|
||||||
|
return -c / 2 * (t * (t - 2) - 1) + b
|
||||||
|
}
|
||||||
|
|
||||||
|
var _typeof =
|
||||||
|
typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol'
|
||||||
|
? function(obj) {
|
||||||
|
return typeof obj
|
||||||
|
}
|
||||||
|
: function(obj) {
|
||||||
|
return obj &&
|
||||||
|
typeof Symbol === 'function' &&
|
||||||
|
obj.constructor === Symbol &&
|
||||||
|
obj !== Symbol.prototype
|
||||||
|
? 'symbol'
|
||||||
|
: typeof obj
|
||||||
|
}
|
||||||
|
|
||||||
|
var jumper = function jumper() {
|
||||||
|
// private variable cache
|
||||||
|
// no variables are created during a jump, preventing memory leaks
|
||||||
|
|
||||||
|
var element = void 0 // element to scroll to (node)
|
||||||
|
|
||||||
|
var start = void 0 // where scroll starts (px)
|
||||||
|
var stop = void 0 // where scroll stops (px)
|
||||||
|
|
||||||
|
var offset = void 0 // adjustment from the stop position (px)
|
||||||
|
var easing = void 0 // easing function (function)
|
||||||
|
var a11y = void 0 // accessibility support flag (boolean)
|
||||||
|
|
||||||
|
var distance = void 0 // distance of scroll (px)
|
||||||
|
var duration = void 0 // scroll duration (ms)
|
||||||
|
|
||||||
|
var timeStart = void 0 // time scroll started (ms)
|
||||||
|
var timeElapsed = void 0 // time spent scrolling thus far (ms)
|
||||||
|
|
||||||
|
var next = void 0 // next scroll position (px)
|
||||||
|
|
||||||
|
var callback = void 0 // to call when done scrolling (function)
|
||||||
|
|
||||||
|
// scroll position helper
|
||||||
|
|
||||||
|
function location() {
|
||||||
|
return window.scrollY || window.pageYOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
// element offset helper
|
||||||
|
|
||||||
|
function top(element) {
|
||||||
|
return element.getBoundingClientRect().top + start
|
||||||
|
}
|
||||||
|
|
||||||
|
// rAF loop helper
|
||||||
|
|
||||||
|
function loop(timeCurrent) {
|
||||||
|
// store time scroll started, if not started already
|
||||||
|
if (!timeStart) {
|
||||||
|
timeStart = timeCurrent
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine time spent scrolling so far
|
||||||
|
timeElapsed = timeCurrent - timeStart
|
||||||
|
|
||||||
|
// calculate next scroll position
|
||||||
|
next = easing(timeElapsed, start, distance, duration)
|
||||||
|
|
||||||
|
// scroll to it
|
||||||
|
window.scrollTo(0, next)
|
||||||
|
|
||||||
|
// check progress
|
||||||
|
timeElapsed < duration
|
||||||
|
? window.requestAnimationFrame(loop) // continue scroll loop
|
||||||
|
: done() // scrolling is done
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll finished helper
|
||||||
|
|
||||||
|
function done() {
|
||||||
|
// account for rAF time rounding inaccuracies
|
||||||
|
window.scrollTo(0, start + distance)
|
||||||
|
|
||||||
|
// if scrolling to an element, and accessibility is enabled
|
||||||
|
if (element && a11y) {
|
||||||
|
// add tabindex indicating programmatic focus
|
||||||
|
element.setAttribute('tabindex', '-1')
|
||||||
|
|
||||||
|
// focus the element
|
||||||
|
element.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it exists, fire the callback
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset time for next jump
|
||||||
|
timeStart = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
function jump(target) {
|
||||||
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}
|
||||||
|
|
||||||
|
// resolve options, or use defaults
|
||||||
|
duration = options.duration || 1000
|
||||||
|
offset = options.offset || 0
|
||||||
|
callback = options.callback // "undefined" is a suitable default, and won't be called
|
||||||
|
easing = options.easing || easeInOutQuad
|
||||||
|
a11y = options.a11y || false
|
||||||
|
|
||||||
|
// cache starting position
|
||||||
|
start = location()
|
||||||
|
|
||||||
|
// resolve target
|
||||||
|
switch (typeof target === 'undefined' ? 'undefined' : _typeof(target)) {
|
||||||
|
// scroll from current position
|
||||||
|
case 'number':
|
||||||
|
element = undefined // no element to scroll to
|
||||||
|
a11y = false // make sure accessibility is off
|
||||||
|
stop = start + target
|
||||||
|
break
|
||||||
|
|
||||||
|
// scroll to element (node)
|
||||||
|
// bounding rect is relative to the viewport
|
||||||
|
case 'object':
|
||||||
|
element = target
|
||||||
|
stop = top(element)
|
||||||
|
break
|
||||||
|
|
||||||
|
// scroll to element (selector)
|
||||||
|
// bounding rect is relative to the viewport
|
||||||
|
case 'string':
|
||||||
|
element = document.querySelector(target)
|
||||||
|
stop = top(element)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve scroll distance, accounting for offset
|
||||||
|
distance = stop - start + offset
|
||||||
|
|
||||||
|
// resolve duration
|
||||||
|
switch (_typeof(options.duration)) {
|
||||||
|
// number in ms
|
||||||
|
case 'number':
|
||||||
|
duration = options.duration
|
||||||
|
break
|
||||||
|
|
||||||
|
// function passed the distance of the scroll
|
||||||
|
case 'function':
|
||||||
|
duration = options.duration(distance)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the loop
|
||||||
|
window.requestAnimationFrame(loop)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expose only the jump method
|
||||||
|
return jump
|
||||||
|
}
|
||||||
|
|
||||||
|
// export singleton
|
||||||
|
|
||||||
|
var singleton = jumper()
|
||||||
|
|
||||||
|
return (() => {
|
||||||
|
let scrolling
|
||||||
|
const end = () => (scrolling = false)
|
||||||
|
return (to, options = {}) => {
|
||||||
|
if (scrolling) return
|
||||||
|
const scrollY = window.scrollY || window.pageYOffset
|
||||||
|
if (to !== '.header') location.hash = to
|
||||||
|
scroll(0, scrollY)
|
||||||
|
scrolling = true
|
||||||
|
setTimeout(end, options.duration || 0)
|
||||||
|
return singleton(to, options)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
})
|
||||||
16
src/js/deps/polyfills.js
Normal file
16
src/js/deps/polyfills.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const e = Element.prototype
|
||||||
|
if (!e.matches) {
|
||||||
|
e.matches =
|
||||||
|
e.matchesSelector || e.msMatchesSelector || e.webkitMatchesSelector || e.mozMatchesSelector
|
||||||
|
}
|
||||||
|
if (!e.closest) {
|
||||||
|
e.closest = function(s) {
|
||||||
|
var el = this
|
||||||
|
if (!document.documentElement.contains(el)) return null
|
||||||
|
do {
|
||||||
|
if (el.matches(s)) return el
|
||||||
|
el = el.parentElement || el.parentNode
|
||||||
|
} while (el !== null && el.nodeType === 1)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/js/deps/utils.js
Normal file
40
src/js/deps/utils.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
export const select = s => document.querySelector(s)
|
||||||
|
export const selectAll = s => [].slice.call(document.querySelectorAll(s))
|
||||||
|
export const scrollY = () => window.scrollY || window.pageYOffset
|
||||||
|
export const easeOutQuint = (t, b, c, d) => c * ((t = t / d - 1) * t ** 4 + 1) + b
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A small utility to fix the letter kerning on macOS Chrome and Firefox when using the system font
|
||||||
|
* (San Francisco). It is now fixed in the text rendering engine in FF 58 and Chrome 64.
|
||||||
|
* UPDATE: It appears the applied fix doesn't work when the font is in italics. New fix has been added.
|
||||||
|
* Must be applied to all browsers for now.
|
||||||
|
*/
|
||||||
|
;(() => {
|
||||||
|
const ua = navigator.userAgent
|
||||||
|
|
||||||
|
// macOS 10.11 (El Capitan) came with San Francisco. Previous versions used Helvetica
|
||||||
|
const isRelevantMacOS =
|
||||||
|
/Mac/.test(navigator.platform) && (ua.match(/OS X 10[._](\d{1,2})/) || [])[1] >= 11
|
||||||
|
|
||||||
|
// Chrome v64 and FF v58 fix the issue
|
||||||
|
const isAffectedBrowser =
|
||||||
|
(ua.match(/Chrome\/(\d+)\./) || [])[1] < 64 || (ua.match(/Firefox\/(\d+)\./) || [])[1] < 58
|
||||||
|
|
||||||
|
const allEls = [].slice.call(document.querySelectorAll('*'))
|
||||||
|
|
||||||
|
if (isRelevantMacOS && isAffectedBrowser) {
|
||||||
|
document.documentElement.style.letterSpacing = '-0.3px'
|
||||||
|
allEls.forEach(el => {
|
||||||
|
const fontSize = parseFloat(getComputedStyle(el).fontSize)
|
||||||
|
if (fontSize >= 20) el.style.letterSpacing = '0.3px'
|
||||||
|
})
|
||||||
|
} else if (isRelevantMacOS && !isAffectedBrowser) {
|
||||||
|
// Italics fix
|
||||||
|
allEls.forEach(el => {
|
||||||
|
const { fontSize, fontStyle } = getComputedStyle(el)
|
||||||
|
if (fontStyle === 'italic') {
|
||||||
|
el.style.letterSpacing = parseFloat(fontSize) >= 20 ? '0.3px' : '-0.3px'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})()
|
||||||
14
src/js/index.js
Normal file
14
src/js/index.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Deps
|
||||||
|
import 'normalize.css'
|
||||||
|
import 'prismjs'
|
||||||
|
|
||||||
|
// CSS
|
||||||
|
import '../css/deps/prism.css'
|
||||||
|
import '../css/index.scss'
|
||||||
|
|
||||||
|
// Polyfills
|
||||||
|
import './deps/polyfills'
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import Menu from './components/Menu'
|
||||||
|
import BackToTopButton from './components/BackToTopButton'
|
||||||
8
utils/utils.js
Normal file
8
utils/utils.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
exports.toKebabCase = str =>
|
||||||
|
str &&
|
||||||
|
str
|
||||||
|
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
|
||||||
|
.map(x => x.toLowerCase())
|
||||||
|
.join('-');
|
||||||
|
|
||||||
|
exports.emptyHTML = (...els) => els.forEach(el => (el.innerHTML = ''))
|
||||||
Reference in New Issue
Block a user