Add tags
This commit is contained in:
File diff suppressed because one or more lines are too long
322
index.html
322
index.html
@ -18,28 +18,40 @@
|
||||
</span>
|
||||
</button>
|
||||
<div class="sidebar__links">
|
||||
<a class="sidebar__link" href="#box-sizing-reset">Box-sizing reset</a>
|
||||
<a class="sidebar__link" href="#clearfix">Clearfix</a>
|
||||
<a class="sidebar__link" href="#constant-width-to-height-ratio">Constant width to height ratio</a>
|
||||
<a class="sidebar__link" href="#custom-scrollbar">Custom scrollbar</a>
|
||||
<a class="sidebar__link" href="#custom-text-selection">Custom text selection</a>
|
||||
<a class="sidebar__link" href="#disable-selection">Disable selection</a>
|
||||
<a class="sidebar__link" href="#donut-spinner">Donut spinner</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="#evenly-distributed-children">Evenly distributed children</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="#hover-underline-animation">Hover underline animation</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>
|
||||
<section data-type="layout" class="sidebar__section">
|
||||
<h4 class="sidebar__section-heading">layout</h4>
|
||||
<a class="sidebar__link" href="#box-sizing-reset"><span>Box-sizing reset</span></a>
|
||||
<a class="sidebar__link" href="#clearfix"><span>Clearfix</span></a>
|
||||
<a class="sidebar__link" href="#constant-width-to-height-ratio"><span>Constant width to height ratio</span></a>
|
||||
<a class="sidebar__link" href="#evenly-distributed-children"><span>Evenly distributed children</span></a>
|
||||
<a class="sidebar__link" href="#horizontal-and-vertical-centering"><span>Horizontal and vertical centering</span></a>
|
||||
<a class="sidebar__link" href="#truncate-text"><span>Truncate text</span></a>
|
||||
</section>
|
||||
<section data-type="visual" class="sidebar__section">
|
||||
<h4 class="sidebar__section-heading">visual</h4>
|
||||
<a class="sidebar__link" href="#custom-scrollbar"><span>Custom scrollbar</span></a>
|
||||
<a class="sidebar__link" href="#custom-text-selection"><span>Custom text selection</span></a>
|
||||
<a class="sidebar__link" href="#etched-text"><span>Etched text</span></a>
|
||||
<a class="sidebar__link" href="#gradient-text"><span>Gradient text</span></a>
|
||||
<a class="sidebar__link" href="#hairline-border"><span>Hairline border</span></a>
|
||||
<a class="sidebar__link" href="#overflow-scroll-gradient"><span>Overflow scroll gradient</span></a>
|
||||
<a class="sidebar__link" href="#pretty-text-underline"><span>Pretty text underline</span></a>
|
||||
<a class="sidebar__link" href="#shape-separator"><span>Shape separator</span></a>
|
||||
<a class="sidebar__link" href="#system-font-stack"><span>System font stack</span></a>
|
||||
<a class="sidebar__link" href="#triangle"><span>Triangle</span></a>
|
||||
</section>
|
||||
<section data-type="animation" class="sidebar__section">
|
||||
<h4 class="sidebar__section-heading">animation</h4>
|
||||
<a class="sidebar__link" href="#donut-spinner"><span>Donut spinner</span></a>
|
||||
<a class="sidebar__link" href="#easing-variables"><span>Easing variables</span></a>
|
||||
<a class="sidebar__link" href="#hover-underline-animation"><span>Hover underline animation</span></a>
|
||||
</section>
|
||||
<section data-type="interactivity" class="sidebar__section">
|
||||
<h4 class="sidebar__section-heading">interactivity</h4>
|
||||
<a class="sidebar__link" href="#disable-selection"><span>Disable selection</span></a>
|
||||
<a class="sidebar__link" href="#mouse-cursor-gradient-tracking"><span>Mouse cursor gradient tracking</span></a>
|
||||
<a class="sidebar__link" href="#popout-menu"><span>Popout menu</span></a>
|
||||
</section>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="content-wrapper">
|
||||
@ -55,8 +67,20 @@
|
||||
</header>
|
||||
<main class="main" id="main">
|
||||
<div class="container">
|
||||
<nav class="tags" aria-label="Filter by tags">
|
||||
<button class="tags__tag is-large is-active" data-type="all">
|
||||
<i data-feather="check"></i>all</button>
|
||||
<button class="tags__tag is-large " data-type="layout">
|
||||
<i data-feather="layout"></i>layout</button>
|
||||
<button class="tags__tag is-large " data-type="visual">
|
||||
<i data-feather="eye"></i>visual</button>
|
||||
<button class="tags__tag is-large " data-type="animation">
|
||||
<i data-feather="loader"></i>animation</button>
|
||||
<button class="tags__tag is-large " data-type="interactivity">
|
||||
<i data-feather="edit-2"></i>interactivity</button>
|
||||
</nav>
|
||||
<div class="snippet">
|
||||
<h3 id="box-sizing-reset">Box-sizing reset</h3>
|
||||
<h3 id="box-sizing-reset"><span>Box-sizing reset</span><span class="tags__tag snippet__tag" data-type="layout"><i data-feather="layout"></i>layout</span></h3>
|
||||
<p>Resets the box-model so that <code>width</code>s and <code>height</code>s are not affected by their <code>border</code>s or <code>padding</code>.</p>
|
||||
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">html {
|
||||
box-sizing: border-box;
|
||||
@ -67,7 +91,7 @@
|
||||
box-sizing: inherit;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__box-sizing-reset">Demo</div>
|
||||
</div>
|
||||
@ -82,12 +106,12 @@
|
||||
border: 5px solid;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<ol>
|
||||
<li><code>box-sizing: border-box</code> makes the addition of <code>padding</code> or <code>border</code>s not affect an element's <code>width</code> or <code>height</code>.</li>
|
||||
<li><code>box-sizing: inherit</code> makes an element respect its parent's <code>box-sizing</code> rule.</li>
|
||||
</ol>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
98.2%
|
||||
@ -99,11 +123,13 @@
|
||||
<a href="https://caniuse.com/#feat=css3-boxsizing" target="_blank">https://caniuse.com/#feat=css3-boxsizing</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: layout -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="clearfix">Clearfix</h3>
|
||||
<h3 id="clearfix"><span>Clearfix</span><span class="tags__tag snippet__tag" data-type="layout"><i data-feather="layout"></i>layout</span></h3>
|
||||
<p>Ensures that an element self-clears its children.</p>
|
||||
<h6 data-type="Note: This is only useful if you are still using float to build layouts. Please consider using a modern approach with flexbox layout or grid layout.">Note: This is only useful if you are still using float to build layouts. Please consider using a modern approach with flexbox layout or grid layout.</h6>
|
||||
<h6>Note: This is only useful if you are still using float to build layouts. Please consider using a modern approach with flexbox layout or grid layout.</h6>
|
||||
<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>
|
||||
@ -111,7 +137,7 @@
|
||||
</div>
|
||||
</code></pre>
|
||||
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">.clearfix::after {
|
||||
content: "";
|
||||
content: '';
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
@ -119,7 +145,7 @@
|
||||
float: left;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__clearfix">
|
||||
<div class="snippet-demo__floated">float a</div>
|
||||
@ -137,22 +163,24 @@
|
||||
float: left;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
99+%
|
||||
</div>
|
||||
</div>
|
||||
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||
|
||||
<!-- tags: layout -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="constant-width-to-height-ratio">Constant width to height ratio</h3>
|
||||
<h3 id="constant-width-to-height-ratio"><span>Constant width to height ratio</span><span class="tags__tag snippet__tag" data-type="layout"><i data-feather="layout"></i>layout</span></h3>
|
||||
<p>Given an element of variable width, it will ensure its height remains proportionate in a responsive fashion (i.e., its width to height ratio remains constant).</p>
|
||||
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="constant-width-to-height-ratio"></div>
|
||||
</code></pre>
|
||||
@ -162,7 +190,7 @@
|
||||
padding-top: 50%;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<p>Resize your browser window to see the proportion of the element remain the same.</p>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__constant-width-to-height-ratio"></div>
|
||||
@ -174,19 +202,21 @@
|
||||
padding-top: 50%;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<p><code>padding-top</code> and <code>padding-bottom</code> can be used as an alternative to <code>height</code> such that the percentage value causes an element's height to become a percentage of its parent's width, i.e. <code>50%</code> means
|
||||
the height will be 50% of the parent element's width, which means it acts the same as <code>width</code>. This allows its proportion to remain constant.</p>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
99+%
|
||||
</div>
|
||||
</div>
|
||||
<p><span class="snippet__support-note">⚠️ <code>padding-top</code> pushes any content within the element to the bottom.</span></p>
|
||||
|
||||
<!-- tags: layout -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="custom-scrollbar">Custom scrollbar</h3>
|
||||
<h3 id="custom-scrollbar"><span>Custom scrollbar</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></h3>
|
||||
<p>Customizes the scrollbar style for the document and elements with scrollable overflow, on WebKit platforms.</p>
|
||||
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="custom-scrollbar">
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Iure id exercitationem nulla qui repellat laborum vitae, molestias tempora velit natus. Quas, assumenda nisi. Quisquam enim qui iure, consequatur velit sit?</p>
|
||||
@ -197,18 +227,18 @@
|
||||
width: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 10px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
/* Scrollable element */
|
||||
.some-element::webkit-scrollbar {
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__custom-scrollbar">
|
||||
<p>
|
||||
@ -236,7 +266,7 @@
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<ol>
|
||||
<li><code>::-webkit-scrollbar</code> targets the whole scrollbar element.</li>
|
||||
<li><code>::-webkit-scrollbar-track</code> targets only the scrollbar track.</li>
|
||||
@ -245,7 +275,7 @@
|
||||
<p>There are many other pseudo-elements that you can use to style scrollbars. For more info, visit the
|
||||
<a href="https://webkit.org/blog/363/styling-scrollbars/" target="_blank">WebKit Blog</a>
|
||||
</p>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
87.3%
|
||||
@ -257,9 +287,11 @@
|
||||
<a href="https://caniuse.com/#feat=css-scrollbar" target="_blank">https://caniuse.com/#feat=css-scrollbar</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="custom-text-selection">Custom text selection</h3>
|
||||
<h3 id="custom-text-selection"><span>Custom text selection</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></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>
|
||||
@ -272,7 +304,7 @@
|
||||
color: white;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<p class="snippet-demo__custom-text-selection">Select some of this text.</p>
|
||||
</div>
|
||||
@ -286,9 +318,9 @@
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<p><code>::selection</code> defines a pseudo selector on an element to style text within it when selected. Note that if you don't combine any other selector your style will be applied at document root level, to any selectable element.</p>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
84.6%
|
||||
@ -301,9 +333,11 @@ in any specification.</span></p>
|
||||
<a href="https://caniuse.com/#feat=css-selection" target="_blank">https://caniuse.com/#feat=css-selection</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="disable-selection">Disable selection</h3>
|
||||
<h3 id="disable-selection"><span>Disable selection</span><span class="tags__tag snippet__tag" data-type="interactivity"><i data-feather="edit-2"></i>interactivity</span></h3>
|
||||
<p>Makes the content unselectable.</p>
|
||||
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><p>You can select me.</p>
|
||||
<p class="unselectable">You can't select me!</p>
|
||||
@ -312,7 +346,7 @@ in any specification.</span></p>
|
||||
user-select: none;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<p>You can select me.</p>
|
||||
<p class="snippet-demo__disable-selection">You can't select me!</p>
|
||||
@ -322,9 +356,9 @@ in any specification.</span></p>
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<p><code>user-select: none</code> specifies that the text cannot be selected.</p>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
86.3%
|
||||
@ -336,15 +370,21 @@ in any specification.</span></p>
|
||||
<a href="https://caniuse.com/#feat=user-select-none" target="_blank">https://caniuse.com/#feat=user-select-none</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: interactivity -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="donut-spinner">Donut spinner</h3>
|
||||
<h3 id="donut-spinner"><span>Donut spinner</span><span class="tags__tag snippet__tag" data-type="animation"><i data-feather="loader"></i>animation</span></h3>
|
||||
<p>Creates a donut spinner that can be used to indicate the loading of content.</p>
|
||||
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="donut"></div>
|
||||
</code></pre>
|
||||
<h4 data-type="CSS">CSS</h4><pre><code class="lang-css">@keyframes donut-spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.donut {
|
||||
display: inline-block;
|
||||
@ -356,7 +396,7 @@ in any specification.</span></p>
|
||||
animation: donut-spin 1.2s linear infinite;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__donut-spinner"></div>
|
||||
</div>
|
||||
@ -379,9 +419,9 @@ in any specification.</span></p>
|
||||
animation: snippet-demo__donut-spin 1.2s linear infinite;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<p>Use a semi-transparent <code>border</code> for the whole element, except one side that will serve as the loading indicator for the donut. Use <code>animation</code> to rotate the element.</p>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
94.8%
|
||||
@ -396,9 +436,11 @@ in any specification.</span></p>
|
||||
<a href="https://caniuse.com/#feat=transforms2d" target="_blank">https://caniuse.com/#feat=transforms2d</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: animation -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="easing-variables">Easing variables</h3>
|
||||
<h3 id="easing-variables"><span>Easing variables</span><span class="tags__tag snippet__tag" data-type="animation"><i data-feather="loader"></i>animation</span></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>
|
||||
@ -432,7 +474,7 @@ in any specification.</span></p>
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__easing-variables">Hover</div>
|
||||
</div>
|
||||
@ -473,10 +515,10 @@ in any specification.</span></p>
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<p>The variables are defined globally within 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 <code>html</code>, except that its specificity is higher.</p>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
87.2%
|
||||
@ -488,9 +530,11 @@ in any specification.</span></p>
|
||||
<a href="https://caniuse.com/#feat=css-variables" target="_blank">https://caniuse.com/#feat=css-variables</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: animation -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="etched-text">Etched text</h3>
|
||||
<h3 id="etched-text"><span>Etched text</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></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>
|
||||
@ -501,7 +545,7 @@ in any specification.</span></p>
|
||||
color: #b8bec5;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<p class="snippet-demo__etched-text">I appear etched into the background.</p>
|
||||
</div>
|
||||
@ -513,11 +557,11 @@ in any specification.</span></p>
|
||||
text-shadow: 0 2px 0 white;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
97.9%
|
||||
@ -529,9 +573,11 @@ in any specification.</span></p>
|
||||
<a href="https://caniuse.com/#feat=css-textshadow" target="_blank">https://caniuse.com/#feat=css-textshadow</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="evenly-distributed-children">Evenly distributed children</h3>
|
||||
<h3 id="evenly-distributed-children"><span>Evenly distributed children</span><span class="tags__tag snippet__tag" data-type="layout"><i data-feather="layout"></i>layout</span></h3>
|
||||
<p>Evenly distributes child elements within a parent element.</p>
|
||||
<h4 data-type="HTML">HTML</h4><pre><code class="lang-html"><div class="evenly-distributed-children">
|
||||
<p>Item1</p>
|
||||
@ -544,7 +590,7 @@ in any specification.</span></p>
|
||||
justify-content: space-between;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__evenly-distributed-children">
|
||||
<p>Item1</p>
|
||||
@ -559,13 +605,13 @@ in any specification.</span></p>
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<ol>
|
||||
<li><code>display: flex</code> enables flexbox.</li>
|
||||
<li><code>justify-content: space-between</code> evenly distributes child elements horizontally. The first item is positioned at the left edge, while the last item is positioned at the right edge.</li>
|
||||
</ol>
|
||||
<p>Alternatively, use <code>justify-content: space-around</code> to distribute the children with space around them, rather than between them.</p>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
97.8%
|
||||
@ -577,9 +623,11 @@ in any specification.</span></p>
|
||||
<a href="https://caniuse.com/#feat=flexbox" target="_blank">https://caniuse.com/#feat=flexbox</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: layout -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="gradient-text">Gradient text</h3>
|
||||
<h3 id="gradient-text"><span>Gradient text</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></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>
|
||||
@ -589,7 +637,7 @@ in any specification.</span></p>
|
||||
-webkit-background-clip: text;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<p class="snippet-demo__gradient-text">
|
||||
Gradient text
|
||||
@ -605,13 +653,13 @@ in any specification.</span></p>
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
90.7%
|
||||
@ -623,9 +671,11 @@ in any specification.</span></p>
|
||||
<a href="https://caniuse.com/#feat=text-stroke" target="_blank">https://caniuse.com/#feat=text-stroke</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="hairline-border">Hairline border</h3>
|
||||
<h3 id="hairline-border"><span>Hairline border</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></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>
|
||||
@ -648,7 +698,7 @@ in any specification.</span></p>
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<p class="snippet-demo__hairline-border">Text with a hairline border around it.</p>
|
||||
</div>
|
||||
@ -672,12 +722,12 @@ in any specification.</span></p>
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<ol>
|
||||
<li><code>box-shadow</code>, when only using spread, adds a pseudo-border which can use subpixels*.</li>
|
||||
<li>Use <code>@media (min-resolution: ...)</code> to check the device pixel ratio (<code>1dppx</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>
|
||||
<h4>Browser Support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
95.0%
|
||||
@ -694,9 +744,11 @@ in any specification.</span></p>
|
||||
</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>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="horizontal-and-vertical-centering">Horizontal and vertical centering</h3>
|
||||
<h3 id="horizontal-and-vertical-centering"><span>Horizontal and vertical centering</span><span class="tags__tag snippet__tag" data-type="layout"><i data-feather="layout"></i>layout</span></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>
|
||||
@ -708,7 +760,7 @@ in any specification.</span></p>
|
||||
align-items: center;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>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>
|
||||
@ -722,13 +774,13 @@ in any specification.</span></p>
|
||||
height: 200px;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
97.8%
|
||||
@ -740,9 +792,11 @@ in any specification.</span></p>
|
||||
<a href="https://caniuse.com/#feat=flexbox" target="_blank">https://caniuse.com/#feat=flexbox</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: layout -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="hover-underline-animation">Hover underline animation</h3>
|
||||
<h3 id="hover-underline-animation"><span>Hover underline animation</span><span class="tags__tag snippet__tag" data-type="animation"><i data-feather="loader"></i>animation</span></h3>
|
||||
<p>Creates an animated underline effect when the text is hovered over.</p>
|
||||
<p>
|
||||
<small><strong>Credit:</strong>
|
||||
@ -773,7 +827,7 @@ in any specification.</span></p>
|
||||
transform-origin: bottom left;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<p class="snippet-demo__hover-underline-animation">Hover this text to see the effect!</p>
|
||||
</div>
|
||||
@ -800,7 +854,7 @@ in any specification.</span></p>
|
||||
transform-origin: bottom left;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<ol>
|
||||
<li><code>display: inline-block</code> makes the block <code>p</code> an <code>inline-block</code> to prevent the underline from spanning the entire parent width rather than just the content (text).</li>
|
||||
<li><code>position: relative</code> on the element establishes a Cartesian positioning context for pseudo-elements.</li>
|
||||
@ -814,7 +868,7 @@ in any specification.</span></p>
|
||||
<li><code>:hover::after</code> then uses <code>scaleX(1)</code> to transition the width to 100%, then changes the <code>transform-origin</code> to <code>bottom left</code> so that the anchor point is reversed, allowing it transition out in the
|
||||
other direction when hovered off.</li>
|
||||
</ol>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
94.9%
|
||||
@ -829,9 +883,11 @@ in any specification.</span></p>
|
||||
<a href="https://caniuse.com/#feat=css-transitions" target="_blank">https://caniuse.com/#feat=css-transitions</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: animation -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="mouse-cursor-gradient-tracking">Mouse cursor gradient tracking</h3>
|
||||
<h3 id="mouse-cursor-gradient-tracking"><span>Mouse cursor gradient tracking</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span><span class="tags__tag snippet__tag" data-type="interactivity"><i data-feather="edit-2"></i>interactivity</span></h3>
|
||||
<p>A hover effect where the gradient follows the mouse cursor.</p>
|
||||
<p>
|
||||
<small class="snippet__credit"><strong>Credit:</strong>
|
||||
@ -866,21 +922,21 @@ in any specification.</span></p>
|
||||
height: var(--size);
|
||||
background: radial-gradient(circle closest-side, pink, transparent);
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width .2s ease, height .2s ease;
|
||||
transition: width 0.2s ease, height 0.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) {
|
||||
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>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<button class="snippet-demo__mouse-cursor-gradient-tracking">
|
||||
<span>Hover me</span>
|
||||
@ -928,14 +984,14 @@ btn.onmousemove = function (e) {
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
87.2%
|
||||
@ -950,9 +1006,11 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<a href="https://caniuse.com/#feat=css-variables" target="_blank">https://caniuse.com/#feat=css-variables</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: visual, interactivity -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="overflow-scroll-gradient">Overflow scroll gradient</h3>
|
||||
<h3 id="overflow-scroll-gradient"><span>Overflow scroll gradient</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></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">
|
||||
@ -969,7 +1027,10 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
bottom: 0;
|
||||
width: 300px;
|
||||
height: 25px;
|
||||
background: linear-gradient(rgba(255, 255, 255, 0.001), white); /* transparent keyword is broken in Safari */
|
||||
background: linear-gradient(
|
||||
rgba(255, 255, 255, 0.001),
|
||||
white
|
||||
); /* transparent keyword is broken in Safari */
|
||||
pointer-events: none;
|
||||
}
|
||||
.overflow-scroll-gradient__scroller {
|
||||
@ -982,7 +1043,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
text-align: center;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__overflow-scroll-gradient">
|
||||
<div class="snippet-demo__overflow-scroll-gradient__scroller">
|
||||
@ -1016,7 +1077,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<script>
|
||||
document.querySelector('.snippet-demo__overflow-scroll-gradient__scroller').innerHTML = 'content '.repeat(200)
|
||||
</script>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<ol>
|
||||
<li><code>position: relative</code> on the parent establishes a Cartesian positioning context for pseudo-elements.</li>
|
||||
<li><code>::after</code> defines a pseudo element.</li>
|
||||
@ -1027,7 +1088,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<li><code>bottom: 0</code> positions the pseudo-element at the bottom of the parent.</li>
|
||||
<li><code>pointer-events: none</code> specifies that the pseudo-element cannot be a target of mouse events, allowing text behind it to still be selectable/interactive.</li>
|
||||
</ol>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
94.8%
|
||||
@ -1039,9 +1100,11 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<a href="https://caniuse.com/#feat=css-gradients" target="_blank">https://caniuse.com/#feat=css-gradients</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="popout-menu">Popout menu</h3>
|
||||
<h3 id="popout-menu"><span>Popout menu</span><span class="tags__tag snippet__tag" data-type="interactivity"><i data-feather="edit-2"></i>interactivity</span></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">
|
||||
@ -1061,7 +1124,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
visibility: visible;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__reference">
|
||||
<div class="snippet-demo__popout-menu">
|
||||
@ -1092,7 +1155,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
visibility: visible;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>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>
|
||||
@ -1101,16 +1164,18 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
99+%
|
||||
</div>
|
||||
</div>
|
||||
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||
|
||||
<!-- tags: interactivity -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="pretty-text-underline">Pretty text underline</h3>
|
||||
<h3 id="pretty-text-underline"><span>Pretty text underline</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></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>
|
||||
@ -1118,10 +1183,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
font-family: Arial, sans-serif;
|
||||
display: inline;
|
||||
font-size: 18px;
|
||||
text-shadow: 1px 1px 0 #f5f6f9,
|
||||
-1px 1px 0 #f5f6f9,
|
||||
-1px -1px 0 #f5f6f9,
|
||||
1px -1px 0 #f5f6f9;
|
||||
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 0.98em;
|
||||
background-repeat: repeat-x;
|
||||
@ -1136,7 +1198,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
text-shadow: none;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<p class="snippet-demo__pretty-text-underline">Pretty text underline without clipping descending letters.</p>
|
||||
</div>
|
||||
@ -1160,7 +1222,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
text-shadow: none;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>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>
|
||||
@ -1169,7 +1231,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
94.8%
|
||||
@ -1184,9 +1246,11 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<a href="https://caniuse.com/#feat=css-gradients" target="_blank">https://caniuse.com/#feat=css-gradients</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="shape-separator">Shape separator</h3>
|
||||
<h3 id="shape-separator"><span>Shape separator</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></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>
|
||||
@ -1203,7 +1267,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
bottom: 0;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo is-distinct">
|
||||
<div class="snippet-demo__shape-separator"></div>
|
||||
</div>
|
||||
@ -1222,7 +1286,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
bottom: 0;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>Explanation</h4>
|
||||
<ol>
|
||||
<li><code>position: relative</code> on the element establishes a Cartesian positioning context for pseudo elements.</li>
|
||||
<li><code>::after</code> defines a pseudo element.</li>
|
||||
@ -1233,7 +1297,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
98.0%
|
||||
@ -1245,17 +1309,20 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<a href="https://caniuse.com/#feat=svg" target="_blank">https://caniuse.com/#feat=svg</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="system-font-stack">System font stack</h3>
|
||||
<h3 id="system-font-stack"><span>System font stack</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></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;
|
||||
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>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<p class="snippet-demo__system-font-stack">This text uses the system font.</p>
|
||||
</div>
|
||||
@ -1264,7 +1331,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
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>
|
||||
<h4>Explanation</h4>
|
||||
<p>The browser looks for each successive font, preferring the first one if possible, and falls back to the next if 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>
|
||||
@ -1277,16 +1344,18 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
99+%
|
||||
</div>
|
||||
</div>
|
||||
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="triangle">Triangle</h3>
|
||||
<h3 id="triangle"><span>Triangle</span><span class="tags__tag snippet__tag" data-type="visual"><i data-feather="eye"></i>visual</span></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>
|
||||
@ -1298,7 +1367,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
border-right: 20px solid transparent;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<div class="snippet-demo__triangles">
|
||||
<div class="snippet-demo__triangle snippet-demo__triangle-1"></div>
|
||||
@ -1345,22 +1414,24 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
border-right: 15px solid transparent;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>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>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
99+%
|
||||
</div>
|
||||
</div>
|
||||
<p><span class="snippet__support-note">✅ No caveats.</span></p>
|
||||
|
||||
<!-- tags: visual -->
|
||||
</div>
|
||||
<div class="snippet">
|
||||
<h3 id="truncate-text">Truncate text</h3>
|
||||
<h3 id="truncate-text"><span>Truncate text</span><span class="tags__tag snippet__tag" data-type="layout"><i data-feather="layout"></i>layout</span></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>
|
||||
@ -1371,7 +1442,7 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
width: 200px;
|
||||
}
|
||||
</code></pre>
|
||||
<h4 data-type="Demo">Demo</h4>
|
||||
<h4>Demo</h4>
|
||||
<div class="snippet-demo">
|
||||
<p class="snippet-demo__truncate-text">
|
||||
This text will be truncated if it exceeds 200px in width.
|
||||
@ -1386,14 +1457,14 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<h4 data-type="Explanation">Explanation</h4>
|
||||
<h4>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>
|
||||
<li><code>width: 200px;</code> ensures the element has a dimension, to know when to get ellipsis</li>
|
||||
</ol>
|
||||
<h4 data-type="Browser support">Browser support</h4>
|
||||
<h4>Browser support</h4>
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
98.1%
|
||||
@ -1405,10 +1476,11 @@ var y = e.pageY - btn.offsetTop - btn.offsetParent.offsetTop
|
||||
<a href="https://caniuse.com/#feat=text-overflow" target="_blank">https://caniuse.com/#feat=text-overflow</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- tags: layout -->
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<footer class="footer"></footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
13
package-lock.json
generated
13
package-lock.json
generated
@ -1934,6 +1934,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"classnames": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.5.tgz",
|
||||
"integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0="
|
||||
},
|
||||
"cli-boxes": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
|
||||
@ -3107,6 +3112,14 @@
|
||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
|
||||
"dev": true
|
||||
},
|
||||
"feather-icons": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/feather-icons/-/feather-icons-4.7.0.tgz",
|
||||
"integrity": "sha512-/dKhEelpOazdN0MtcBZTgqo1tZHn35y40V0sGPi6FzzwNbQ5H6vzTqYWWMeRtKw5JePmog7RthR/PYPA1lYNFA==",
|
||||
"requires": {
|
||||
"classnames": "2.2.5"
|
||||
}
|
||||
},
|
||||
"filename-regex": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
|
||||
|
||||
@ -25,5 +25,8 @@
|
||||
"prettier": "^1.10.2",
|
||||
"pretty": "^2.0.0",
|
||||
"prismjs": "^1.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"feather-icons": "^4.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
137
scripts/build.js
137
scripts/build.js
@ -2,61 +2,82 @@ 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 { toKebabCase, createElement, template, dom } = require('../utils/utils.js')
|
||||
|
||||
const SNIPPETS_PATH = './snippets'
|
||||
const SNIPPET_CONTAINER_SELECTOR = '.main > .container'
|
||||
const TAGS = [
|
||||
{
|
||||
name: 'all',
|
||||
icon: 'check'
|
||||
},
|
||||
{
|
||||
name: 'layout',
|
||||
icon: 'layout'
|
||||
},
|
||||
{
|
||||
name: 'visual',
|
||||
icon: 'eye'
|
||||
},
|
||||
{
|
||||
name: 'animation',
|
||||
icon: 'loader'
|
||||
},
|
||||
{
|
||||
name: 'interactivity',
|
||||
icon: 'edit-2'
|
||||
}
|
||||
]
|
||||
|
||||
const createElement = str => {
|
||||
const el = document.createElement('div')
|
||||
el.innerHTML = str
|
||||
return el.firstElementChild
|
||||
const renderer = new marked.Renderer()
|
||||
renderer.heading = (text, level) => {
|
||||
if (level === 3) {
|
||||
return `<h${level} id="${toKebabCase(text)}"><span>${text}</span></h${level}>`
|
||||
} else {
|
||||
return ['HTML', 'CSS', 'JavaScript'].includes(text)
|
||||
? `<h${level} data-type="${text}">${text}</h${level}>`
|
||||
: `<h${level}>${text}</h${level}>`
|
||||
}
|
||||
}
|
||||
renderer.link = (url, _, text) => `<a href="${url}" target="_blank">${text || url}</a>`
|
||||
|
||||
const document = dom('./src/html/index.html')
|
||||
const components = {
|
||||
backToTopButton: dom('./src/html/components/back-to-top-button.html'),
|
||||
sidebar: dom('./src/html/components/sidebar.html'),
|
||||
header: dom('./src/html/components/header.html'),
|
||||
main: dom('./src/html/components/main.html'),
|
||||
tags: dom('./src/html/components/tags.html')
|
||||
}
|
||||
|
||||
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)
|
||||
const snippetContainer = components.main.querySelector('.container')
|
||||
const sidebarLinkContainer = components.sidebar.querySelector('.sidebar__links')
|
||||
TAGS.slice(1).forEach(tag => {
|
||||
sidebarLinkContainer.append(
|
||||
createElement(`
|
||||
<section data-type="${tag.name}" class="sidebar__section">
|
||||
<h4 class="sidebar__section-heading">${tag.name}</h4>
|
||||
</section>
|
||||
`)
|
||||
)
|
||||
})
|
||||
|
||||
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 snippetEl = createElement(`<div class="snippet">${markdown}</div>`)
|
||||
snippetContainer.append(snippetEl)
|
||||
|
||||
// browser support usage
|
||||
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(
|
||||
const browserSupportHeading = snippetEl.querySelector('h4:last-of-type')
|
||||
browserSupportHeading.after(
|
||||
createElement(`
|
||||
<div>
|
||||
<div class="snippet__browser-support">
|
||||
@ -65,8 +86,50 @@ for (const snippetFile of fs.readdirSync(SNIPPETS_PATH)) {
|
||||
</div>
|
||||
`)
|
||||
)
|
||||
|
||||
// sidebar link
|
||||
const link = createElement(
|
||||
`<a class="sidebar__link" href="#${snippetFile.replace('.md', '')}">${
|
||||
snippetEl.querySelector('h3').innerHTML
|
||||
}</a>`
|
||||
)
|
||||
|
||||
// tags
|
||||
const tags = (snippetData.match(/<!--\s*tags:\s*(.+?)-->/) || [, ''])[1]
|
||||
.split(/,\s*/)
|
||||
.forEach(tag => {
|
||||
tag = tag.trim().toLowerCase()
|
||||
snippetEl
|
||||
.querySelector('h3')
|
||||
.append(
|
||||
createElement(
|
||||
`<span class="tags__tag snippet__tag" data-type="${tag}"><i data-feather="${
|
||||
TAGS.find(t => t.name === tag).icon
|
||||
}"></i>${tag}</span>`
|
||||
)
|
||||
)
|
||||
|
||||
sidebarLinkContainer.querySelector(`section[data-type="${tag}"]`).append(link)
|
||||
})
|
||||
}
|
||||
|
||||
// build dom
|
||||
TAGS.forEach(tag =>
|
||||
components.tags.append(
|
||||
createElement(
|
||||
`<button class="tags__tag is-large ${tag.name === 'all' ? 'is-active' : ''}" data-type="${
|
||||
tag.name
|
||||
}"><i data-feather="${tag.icon}"></i>${tag.name}</button>`
|
||||
)
|
||||
)
|
||||
)
|
||||
const content = document.querySelector('.content-wrapper')
|
||||
content.before(components.backToTopButton)
|
||||
content.before(components.sidebar)
|
||||
content.append(components.header)
|
||||
content.append(components.main)
|
||||
components.main.querySelector('.container').prepend(components.tags)
|
||||
|
||||
// doctype declaration gets stripped, add it back in
|
||||
const html = `<!DOCTYPE html>
|
||||
${pretty(document.documentElement.outerHTML, { ocd: true })}
|
||||
|
||||
@ -44,3 +44,5 @@ html {
|
||||
<span class="snippet__support-note">✅ No caveats.</span>
|
||||
|
||||
* https://caniuse.com/#feat=css3-boxsizing
|
||||
|
||||
<!-- tags: layout -->
|
||||
|
||||
@ -18,7 +18,7 @@ Ensures that an element self-clears its children.
|
||||
|
||||
```css
|
||||
.clearfix::after {
|
||||
content: "";
|
||||
content: '';
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
@ -60,3 +60,5 @@ Ensures that an element self-clears its children.
|
||||
#### Browser support
|
||||
|
||||
<span class="snippet__support-note">✅ No caveats.</span>
|
||||
|
||||
<!-- tags: layout -->
|
||||
|
||||
@ -43,3 +43,5 @@ causes an element's height to become a percentage of its parent's width, i.e. `5
|
||||
#### Browser support
|
||||
|
||||
<span class="snippet__support-note">⚠️ `padding-top` pushes any content within the element to the bottom.</span>
|
||||
|
||||
<!-- tags: layout -->
|
||||
|
||||
@ -19,13 +19,13 @@ Customizes the scrollbar style for the document and elements with scrollable ove
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
/* Scrollable element */
|
||||
@ -80,3 +80,5 @@ There are many other pseudo-elements that you can use to style scrollbars. For m
|
||||
<span class="snippet__support-note">⚠️ Scrollbar styling doesn't appear to be on any standards track.</span>
|
||||
|
||||
* https://caniuse.com/#feat=css-scrollbar
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -48,3 +48,5 @@ Changes the styling of text selection.
|
||||
in any specification.</span>
|
||||
|
||||
* https://caniuse.com/#feat=css-selection
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -39,3 +39,5 @@ Makes the content unselectable.
|
||||
<span class="snippet__support-note">⚠️ Requires prefixes for full support.</span>
|
||||
|
||||
* https://caniuse.com/#feat=user-select-none
|
||||
|
||||
<!-- tags: interactivity -->
|
||||
|
||||
@ -12,8 +12,12 @@ Creates a donut spinner that can be used to indicate the loading of content.
|
||||
|
||||
```css
|
||||
@keyframes donut-spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.donut {
|
||||
display: inline-block;
|
||||
@ -59,3 +63,5 @@ serve as the loading indicator for the donut. Use `animation` to rotate the elem
|
||||
|
||||
* https://caniuse.com/#feat=css-animation
|
||||
* https://caniuse.com/#feat=transforms2d
|
||||
|
||||
<!-- tags: animation -->
|
||||
|
||||
@ -104,3 +104,5 @@ The variables are defined globally within the `:root` CSS pseudo-class which mat
|
||||
<span class="snippet__support-note">✅ No caveats.</span>
|
||||
|
||||
* https://caniuse.com/#feat=css-variables
|
||||
|
||||
<!-- tags: animation -->
|
||||
|
||||
@ -49,3 +49,5 @@ of the background.
|
||||
<span class="snippet__support-note">✅ No caveats.</span>
|
||||
|
||||
* https://caniuse.com/#feat=css-textshadow
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -51,3 +51,5 @@ Alternatively, use `justify-content: space-around` to distribute the children wi
|
||||
<span class="snippet__support-note">⚠️ Needs prefixes for full support.</span>
|
||||
|
||||
* https://caniuse.com/#feat=flexbox
|
||||
|
||||
<!-- tags: layout -->
|
||||
|
||||
@ -49,3 +49,5 @@ Gives text a gradient color.
|
||||
<span class="snippet__support-note">⚠️ Uses non-standard properties.</span>
|
||||
|
||||
* https://caniuse.com/#feat=text-stroke
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -81,3 +81,5 @@ very sharp and crisp.
|
||||
<hr>
|
||||
|
||||
\*Chrome does not support subpixel values on `border`. Safari does not support subpixel values on `box-shadow`. Firefox supports subpixel values on both.
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -48,3 +48,5 @@ Horizontally and vertically centers a child element within a parent element.
|
||||
<span class="snippet__support-note">⚠️ Needs prefixes for full support.</span>
|
||||
|
||||
* https://caniuse.com/#feat=flexbox
|
||||
|
||||
<!-- tags: layout -->
|
||||
|
||||
@ -69,7 +69,7 @@ Creates an animated underline effect when the text is hovered over.
|
||||
#### Explanation
|
||||
|
||||
1. `display: inline-block` makes the block `p` an `inline-block` to prevent the underline from
|
||||
spanning the entire parent width rather than just the content (text).
|
||||
spanning the entire parent width rather than just the content (text).
|
||||
2. `position: relative` on the element establishes a Cartesian positioning context for pseudo-elements.
|
||||
3. `::after` defines a pseudo-element.
|
||||
4. `position: absolute` takes the pseudo element out of the flow of the document and positions it in relation to the parent.
|
||||
@ -77,11 +77,11 @@ spanning the entire parent width rather than just the content (text).
|
||||
6. `transform: scaleX(0)` initially scales the pseudo element to 0 so it has no width and is not visible.
|
||||
7. `bottom: 0` and `left: 0` position it to the bottom left of the block.
|
||||
8. `transition: transform 0.25s ease-out` means changes to `transform` will be transitioned over 0.25 seconds
|
||||
with an `ease-out` timing function.
|
||||
with an `ease-out` timing function.
|
||||
9. `transform-origin: bottom right` means the transform anchor point is positioned at the bottom right of the block.
|
||||
10. `:hover::after` then uses `scaleX(1)` to transition the width to 100%, then changes the `transform-origin`
|
||||
to `bottom left` so that the anchor point is reversed, allowing it transition out in the other direction when
|
||||
hovered off.
|
||||
to `bottom left` so that the anchor point is reversed, allowing it transition out in the other direction when
|
||||
hovered off.
|
||||
|
||||
#### Browser support
|
||||
|
||||
@ -89,3 +89,5 @@ hovered off.
|
||||
|
||||
* https://caniuse.com/#feat=transforms2d
|
||||
* https://caniuse.com/#feat=css-transitions
|
||||
|
||||
<!-- tags: animation -->
|
||||
|
||||
@ -41,7 +41,7 @@ A hover effect where the gradient follows the mouse cursor.
|
||||
height: var(--size);
|
||||
background: radial-gradient(circle closest-side, pink, transparent);
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width .2s ease, height .2s ease;
|
||||
transition: width 0.2s ease, height 0.2s ease;
|
||||
}
|
||||
|
||||
.mouse-cursor-gradient-tracking:hover::before {
|
||||
@ -53,7 +53,7 @@ A hover effect where the gradient follows the mouse cursor.
|
||||
|
||||
```js
|
||||
var btn = document.querySelector('.mouse-cursor-gradient-tracking')
|
||||
btn.onmousemove = function (e) {
|
||||
btn.onmousemove = function(e) {
|
||||
var x = e.pageX - btn.offsetLeft
|
||||
var y = e.pageY - btn.offsetTop
|
||||
btn.style.setProperty('--x', x + 'px')
|
||||
@ -131,7 +131,10 @@ 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
|
||||
|
||||
<!-- tags: visual, interactivity -->
|
||||
|
||||
@ -24,7 +24,10 @@ Adds a fading gradient to an overflowing element to better indicate there is mor
|
||||
bottom: 0;
|
||||
width: 300px;
|
||||
height: 25px;
|
||||
background: linear-gradient(rgba(255, 255, 255, 0.001), white); /* transparent keyword is broken in Safari */
|
||||
background: linear-gradient(
|
||||
rgba(255, 255, 255, 0.001),
|
||||
white
|
||||
); /* transparent keyword is broken in Safari */
|
||||
pointer-events: none;
|
||||
}
|
||||
.overflow-scroll-gradient__scroller {
|
||||
@ -81,7 +84,7 @@ document.querySelector('.snippet-demo__overflow-scroll-gradient__scroller').inne
|
||||
1. `position: relative` on the parent establishes a Cartesian positioning context for pseudo-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).
|
||||
(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).
|
||||
@ -94,3 +97,5 @@ document.querySelector('.snippet-demo__overflow-scroll-gradient__scroller').inne
|
||||
<span class="snippet__support-note">✅ No caveats.</span>
|
||||
|
||||
* https://caniuse.com/#feat=css-gradients
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -75,3 +75,5 @@ Reveals an interactive popout menu on hover.
|
||||
#### Browser support
|
||||
|
||||
<span class="snippet__support-note">✅ No caveats.</span>
|
||||
|
||||
<!-- tags: interactivity -->
|
||||
|
||||
@ -16,10 +16,7 @@ Natively implemented as `text-decoration-skip-ink: auto` but it has less control
|
||||
font-family: Arial, sans-serif;
|
||||
display: inline;
|
||||
font-size: 18px;
|
||||
text-shadow: 1px 1px 0 #f5f6f9,
|
||||
-1px 1px 0 #f5f6f9,
|
||||
-1px -1px 0 #f5f6f9,
|
||||
1px -1px 0 #f5f6f9;
|
||||
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 0.98em;
|
||||
background-repeat: repeat-x;
|
||||
@ -84,3 +81,5 @@ Natively implemented as `text-decoration-skip-ink: auto` but it has less control
|
||||
|
||||
* https://caniuse.com/#feat=css-textshadow
|
||||
* https://caniuse.com/#feat=css-gradients
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -64,3 +64,5 @@ Uses an SVG shape to separate two different blocks to create more a interesting
|
||||
<span class="snippet__support-note">✅ No caveats.</span>
|
||||
|
||||
* https://caniuse.com/#feat=svg
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -12,7 +12,8 @@ Uses the native font of the operating system to get close to a native app feel.
|
||||
|
||||
```css
|
||||
.system-font-stack {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu,
|
||||
Cantarell, 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
```
|
||||
|
||||
@ -46,3 +47,5 @@ falls back to the next if it cannot find the font (on the system or defined in C
|
||||
#### Browser support
|
||||
|
||||
<span class="snippet__support-note">✅ No caveats.</span>
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -89,3 +89,5 @@ Experiment with the `px` values to change the proportion of the triangle.
|
||||
#### Browser support
|
||||
|
||||
<span class="snippet__support-note">✅ No caveats.</span>
|
||||
|
||||
<!-- tags: visual -->
|
||||
|
||||
@ -51,3 +51,5 @@ If the text is longer than one line, it will be truncated and end with an ellips
|
||||
<span class="snippet__support-note">⚠️ Only works for single line elements.</span>
|
||||
|
||||
* https://caniuse.com/#feat=text-overflow
|
||||
|
||||
<!-- tags: layout -->
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
max-height: 378px;
|
||||
margin-top: 44px;
|
||||
box-shadow: 0 0.25rem 0.5rem -0.1rem rgba(0, 32, 128, 0.2);
|
||||
padding-bottom: 1rem;
|
||||
|
||||
&.is-active {
|
||||
transform: rotateX(0);
|
||||
@ -59,6 +60,16 @@
|
||||
border-color: pink;
|
||||
}
|
||||
}
|
||||
|
||||
&__section {
|
||||
padding: 0 0.75rem;
|
||||
}
|
||||
|
||||
&__section-heading {
|
||||
text-transform: capitalize;
|
||||
color: #e3f5ff;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
|
||||
@ -14,6 +14,10 @@
|
||||
margin-bottom: 1.25rem;
|
||||
margin-top: 0;
|
||||
line-height: 1.3;
|
||||
|
||||
span:not(.snippet__tag) {
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
code:not([class*='lang']) {
|
||||
@ -42,16 +46,20 @@
|
||||
h4 {
|
||||
display: inline-block;
|
||||
margin: 1rem 0 0.5rem;
|
||||
font-size: 1.1rem;
|
||||
line-height: 2;
|
||||
|
||||
&[data-type] {
|
||||
background: #333;
|
||||
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;
|
||||
@ -107,6 +115,9 @@
|
||||
top: 1rem;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&__tag {
|
||||
}
|
||||
}
|
||||
|
||||
.snippet-demo {
|
||||
|
||||
83
src/css/components/tags.scss
Normal file
83
src/css/components/tags.scss
Normal file
@ -0,0 +1,83 @@
|
||||
.tags {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
&__tag {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
font-weight: bold;
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
color: #8385aa;
|
||||
white-space: nowrap;
|
||||
border: 1px solid lighten(#8385aa, 15);
|
||||
border-radius: 2px;
|
||||
vertical-align: middle;
|
||||
line-height: 2;
|
||||
padding: 0 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
transition: all 0.1s ease-out;
|
||||
outline: 0;
|
||||
|
||||
&.is-large {
|
||||
font-size: 0.95rem;
|
||||
border-radius: 0.2rem;
|
||||
|
||||
.feather {
|
||||
top: -2px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.feather {
|
||||
vertical-align: middle;
|
||||
margin-right: 0.25rem;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
button.tags__tag {
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
margin-bottom: 1rem;
|
||||
margin-right: 1rem;
|
||||
|
||||
&:hover {
|
||||
background: #8385aa;
|
||||
border-color: #8385aa;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 0.25rem transparentize(#8385aa, 0.5);
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: inset 0 0.1rem 0.1rem 0.1rem rgba(0, 0, 0, 0.2);
|
||||
background: darken(#8385aa, 10);
|
||||
border-color: darken(#8385aa, 10);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background: #7983ff;
|
||||
border-color: #7983ff;
|
||||
color: white;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 0.25rem transparentize(#7983ff, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 579px) {
|
||||
}
|
||||
@ -4,3 +4,4 @@
|
||||
@import './components/header.scss';
|
||||
@import './components/snippet.scss';
|
||||
@import './components/back-to-top-button.scss';
|
||||
@import './components/tags.scss';
|
||||
|
||||
1
src/html/components/back-to-top-button.html
Normal file
1
src/html/components/back-to-top-button.html
Normal file
@ -0,0 +1 @@
|
||||
<button class="back-to-top-button" aria-label="back to top">↑</button>
|
||||
1
src/html/components/footer.html
Normal file
1
src/html/components/footer.html
Normal file
@ -0,0 +1 @@
|
||||
<footer class="footer"></footer>
|
||||
10
src/html/components/header.html
Normal file
10
src/html/components/header.html
Normal file
@ -0,0 +1,10 @@
|
||||
<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>
|
||||
<a class="github-button header__github-button" href="https://github.com/atomiks/30-seconds-of-css" data-icon="octicon-star" data-size="large" data-show-count="true" aria-label="Star atomiks/30-seconds-of-css on GitHub">Star</a>
|
||||
</div>
|
||||
</header>
|
||||
4
src/html/components/main.html
Normal file
4
src/html/components/main.html
Normal file
@ -0,0 +1,4 @@
|
||||
<main class="main" id="main">
|
||||
<div class="container">
|
||||
</div>
|
||||
</main>
|
||||
9
src/html/components/sidebar.html
Normal file
9
src/html/components/sidebar.html
Normal file
@ -0,0 +1,9 @@
|
||||
<nav class="sidebar" aria-label="Table of Contents">
|
||||
<button class="hamburger hamburger--spin sidebar__menu" type="button" aria-label="Menu" aria-expanded="false">
|
||||
<span class="hamburger-box">
|
||||
<span class="hamburger-inner"></span>
|
||||
</span>
|
||||
</button>
|
||||
<div class="sidebar__links">
|
||||
</div>
|
||||
</nav>
|
||||
1
src/html/components/tags.html
Normal file
1
src/html/components/tags.html
Normal file
@ -0,0 +1 @@
|
||||
<nav class="tags" aria-label="Filter by tags"></nav>
|
||||
15
src/html/index.html
Normal file
15
src/html/index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>30 Seconds of CSS</title>
|
||||
<meta name="description" content="A curated collection of useful CSS snippets you can understand in 30 seconds or less. From foundational elements such as clearfix to gradient text color and gradient cursor tracking to CSS easing and far beyond.">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png">
|
||||
<script src="./src/js/index.js" defer=""></script>
|
||||
<script async="" defer="" src="https://buttons.github.io/buttons.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content-wrapper"></div>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,27 +1,23 @@
|
||||
import jump from '../deps/jump'
|
||||
import { select, selectAll, easeOutQuint } from '../deps/utils'
|
||||
|
||||
const menu = select('.hamburger')
|
||||
const links = select('.sidebar__links')
|
||||
const sections = selectAll('.sidebar__section')
|
||||
const ACTIVE_CLASS = 'is-active'
|
||||
|
||||
const toggle = () => {
|
||||
if (window.innerWidth <= 991) {
|
||||
const els = [menu, links]
|
||||
els.forEach(el => el.classList.toggle(ACTIVE_CLASS))
|
||||
menu.setAttribute('aria-expanded', menu.classList.contains(ACTIVE_CLASS) ? 'true' : 'false')
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
setTimeout(toggle, 100)
|
||||
}
|
||||
})
|
||||
|
||||
@ -35,4 +31,13 @@ document.addEventListener('click', e => {
|
||||
}
|
||||
})
|
||||
|
||||
EventHub.on('Tag.click', data => {
|
||||
sections.forEach(section => {
|
||||
section.style.display = 'block'
|
||||
if (section.dataset.type !== data.type && data.type !== 'all') {
|
||||
section.style.display = 'none'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
export default { toggle }
|
||||
13
src/js/components/Snippet.js
Normal file
13
src/js/components/Snippet.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { selectAll } from '../deps/utils'
|
||||
|
||||
const snippets = selectAll('.snippet')
|
||||
EventHub.on('Tag.click', data => {
|
||||
snippets.forEach(snippet => {
|
||||
snippet.style.display = 'block'
|
||||
if (data.type === 'all') return
|
||||
const tags = selectAll('.tags__tag', snippet)
|
||||
if (!selectAll('.tags__tag', snippet).some(el => el.dataset.type === data.type)) {
|
||||
snippet.style.display = 'none'
|
||||
}
|
||||
})
|
||||
})
|
||||
14
src/js/components/Tag.js
Normal file
14
src/js/components/Tag.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { select, selectAll, on } from '../deps/utils'
|
||||
|
||||
const tagButtons = selectAll('button.tags__tag')
|
||||
|
||||
const onClick = function() {
|
||||
tagButtons.forEach(button => button.classList.remove('is-active'))
|
||||
this.classList.add('is-active')
|
||||
|
||||
EventHub.emit('Tag.click', {
|
||||
type: this.dataset.type
|
||||
})
|
||||
}
|
||||
|
||||
tagButtons.forEach(button => on(button, 'click', onClick))
|
||||
@ -1,196 +0,0 @@
|
||||
;(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)
|
||||
}
|
||||
})()
|
||||
})
|
||||
@ -1,8 +1,34 @@
|
||||
export const select = s => document.querySelector(s)
|
||||
export const selectAll = s => [].slice.call(document.querySelectorAll(s))
|
||||
export const select = (s, parent = document) => parent.querySelector(s)
|
||||
|
||||
export const selectAll = (s, parent = document) => [].slice.call(parent.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
|
||||
|
||||
export const on = (el, evt, fn, opts = {}) => {
|
||||
const delegatorFn = e => e.target.matches(opts.target) && fn.call(e.target, e)
|
||||
el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false)
|
||||
if (opts.target) return delegatorFn
|
||||
}
|
||||
|
||||
export const createEventHub = () => ({
|
||||
hub: Object.create(null),
|
||||
emit(event, data) {
|
||||
;(this.hub[event] || []).forEach(handler => handler(data))
|
||||
},
|
||||
on(event, handler) {
|
||||
if (!this.hub[event]) this.hub[event] = []
|
||||
this.hub[event].push(handler)
|
||||
},
|
||||
off(event, handler) {
|
||||
const i = (this.hub[event] || []).findIndex(h => h === handler)
|
||||
if (i > -1) this.hub[event].splice(i, 1)
|
||||
}
|
||||
})
|
||||
|
||||
window.EventHub = createEventHub()
|
||||
|
||||
/*
|
||||
* Make iOS behave normally.
|
||||
*/
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
// Deps
|
||||
import 'normalize.css'
|
||||
import 'prismjs'
|
||||
import feather from 'feather-icons'
|
||||
feather.replace()
|
||||
|
||||
// CSS
|
||||
import '../css/deps/prism.css'
|
||||
@ -10,5 +12,7 @@ import '../css/index.scss'
|
||||
import './deps/polyfills'
|
||||
|
||||
// Components
|
||||
import Menu from './components/Menu'
|
||||
import Sidebar from './components/Sidebar'
|
||||
import BackToTopButton from './components/BackToTopButton'
|
||||
import Tag from './components/Tag'
|
||||
import Snippet from './components/Snippet'
|
||||
|
||||
@ -1,8 +1,20 @@
|
||||
const fs = require('fs')
|
||||
const { JSDOM } = require('jsdom')
|
||||
|
||||
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('-');
|
||||
.join('-')
|
||||
|
||||
exports.emptyHTML = (...els) => els.forEach(el => (el.innerHTML = ''))
|
||||
exports.dom = path => {
|
||||
const doc = new JSDOM(fs.readFileSync(path, 'utf8')).window.document
|
||||
return path.includes('component') ? doc.body.firstElementChild : doc
|
||||
}
|
||||
|
||||
exports.createElement = str => {
|
||||
const el = new JSDOM().window.document.createElement('div')
|
||||
el.innerHTML = str
|
||||
return el.firstElementChild
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user