Merge 30-seconds-of-css
This commit is contained in:
31
css/snippet-template.md
Normal file
31
css/snippet-template.md
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
title: Snippet Name
|
||||
type: snippet
|
||||
tags: [other]
|
||||
cover: image
|
||||
dateModified: 2021-06-13T05:00:00-04:00
|
||||
---
|
||||
|
||||
Explain briefly what the snippet does.
|
||||
|
||||
- Explain briefly how the snippet works.
|
||||
- Use bullet points for your snippet's explanation.
|
||||
- Try to explain everything briefly but clearly.
|
||||
|
||||
```html
|
||||
<div class="my-snippet"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.my-snippet {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
border-radius: 4px;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
console.log(
|
||||
"This is optional, if your snippet doesn't require JavaScript, be sure to delete this block!"
|
||||
)
|
||||
```
|
||||
38
css/snippets/aspect-ratio.md
Normal file
38
css/snippets/aspect-ratio.md
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
title: Aspect ratio
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
author: chalarangelo
|
||||
cover: digital-nomad-12
|
||||
dateModified: 2022-08-14T05:00:00-04:00
|
||||
---
|
||||
|
||||
Creates a responsive container with a specified aspect ratio.
|
||||
|
||||
- Use a CSS custom property, `--aspect-ratio` to define the desired aspect ratio.
|
||||
- Set the container element to `position: relative` and `height: 0`, calculating its height using the `calc()` function and the `--aspect-ratio` custom property.
|
||||
- Set the direct child of the container element to `position: absolute` and filling it parent, while giving it `object-fit: cover` to maintain the aspect ratio.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<img src="https://picsum.photos/id/119/800/450" />
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
--aspect-ratio: 16/9;
|
||||
position: relative;
|
||||
height: 0;
|
||||
padding-bottom: calc(100% / (var(--aspect-ratio)));
|
||||
}
|
||||
|
||||
.container > * {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
```
|
||||
44
css/snippets/border-with-top-triangle.md
Normal file
44
css/snippets/border-with-top-triangle.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
title: Border with top triangle
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: greek-coffee
|
||||
dateModified: 2021-01-07T23:52:15+02:00
|
||||
---
|
||||
|
||||
Creates a content container with a triangle at the top.
|
||||
|
||||
- Use the `::before` and `::after` pseudo-elements to create two triangles.
|
||||
- The colors of the two triangles should be the same as the container's `border-color` and the container's `background-color` respectively.
|
||||
- The `border-width` of the one triangle (`::before`) should be `1px` wider than the other one (`::after`), in order to act as the border.
|
||||
- The smaller triangle (`::after`) should be `1px` to the right of the larger triangle (`::before`) to allow for its left border to be shown.
|
||||
|
||||
```html
|
||||
<div class="container">Border with top triangle</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
padding: 15px;
|
||||
border: 1px solid #dddddd;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.container::before,
|
||||
.container::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: 19px;
|
||||
border: 11px solid transparent;
|
||||
border-bottom-color: #dddddd;
|
||||
}
|
||||
|
||||
.container::after {
|
||||
left: 20px;
|
||||
border: 10px solid transparent;
|
||||
border-bottom-color: #ffffff;
|
||||
}
|
||||
```
|
||||
54
css/snippets/bouncing-loader.md
Normal file
54
css/snippets/bouncing-loader.md
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
title: Bouncing loader
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: digital-nomad-12
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Creates a bouncing loader animation.
|
||||
|
||||
- Use `@keyframes` to define a bouncing animation, using the `opacity` and `transform` properties. Use a single axis translation on `transform: translate3d()` to achieve better animation performance.
|
||||
- Create a parent container, `.bouncing-loader`, for the bouncing circles. Use `display: flex` and `justify-content: center` to position them in the center.
|
||||
- Give the three bouncing circle `<div>` elements the same `width` and `height` and `border-radius: 50%` to make them circular.
|
||||
- Apply the `bouncing-loader` animation to each of the three bouncing circles.
|
||||
- Use a different `animation-delay` for each circle and `animation-direction: alternate` to create the appropriate effect.
|
||||
|
||||
```html
|
||||
<div class="bouncing-loader">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
@keyframes bouncing-loader {
|
||||
to {
|
||||
opacity: 0.1;
|
||||
transform: translate3d(0, -16px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.bouncing-loader {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.bouncing-loader > div {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 3rem 0.2rem;
|
||||
background: #8385aa;
|
||||
border-radius: 50%;
|
||||
animation: bouncing-loader 0.6s infinite alternate;
|
||||
}
|
||||
|
||||
.bouncing-loader > div:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.bouncing-loader > div:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
```
|
||||
45
css/snippets/box-sizing-reset.md
Normal file
45
css/snippets/box-sizing-reset.md
Normal file
@ -0,0 +1,45 @@
|
||||
---
|
||||
title: Box-sizing reset
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: interior
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Resets the box-model so that `width` and `height` are not affected by `border` or `padding`.
|
||||
|
||||
- Use `box-sizing: border-box` to include the width and height of `padding` and `border` when calculating the element's `width` and `height`.
|
||||
- Use `box-sizing: inherit` to pass down the `box-sizing` property from parent to child elements.
|
||||
|
||||
```html
|
||||
<div class="box">border-box</div>
|
||||
<div class="box content-box">content-box</div>
|
||||
```
|
||||
|
||||
```css
|
||||
div {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
padding: 8px;
|
||||
margin: 8px;
|
||||
background: #F24333;
|
||||
color: white;
|
||||
border: 1px solid #BA1B1D;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.content-box {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
```
|
||||
43
css/snippets/broken-image-fallback.md
Normal file
43
css/snippets/broken-image-fallback.md
Normal file
@ -0,0 +1,43 @@
|
||||
---
|
||||
title: Fallback for images that fail to load
|
||||
type: snippet
|
||||
shortTitle: Broken image fallback
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: building-facade
|
||||
dateModified: 2022-11-04T05:00:00-04:00
|
||||
---
|
||||
|
||||
Displays an error message when an image fails to load.
|
||||
|
||||
- Apply styles to the `img` element as if it was a text container.
|
||||
- Use the `::before` and `::after` pseudo-elements to display an error message and the image URL. These elements will only be displayed if the image fails to load.
|
||||
|
||||
```html
|
||||
<img src="https://nowhere.to.be/found.jpg" />
|
||||
```
|
||||
|
||||
```css
|
||||
img {
|
||||
display: block;
|
||||
font-family: sans-serif;
|
||||
font-weight: 300;
|
||||
height: auto;
|
||||
line-height: 2;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
img::before {
|
||||
content: "Sorry, this image is unavailable.";
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
img::after {
|
||||
content: "(url: " attr(src) ")";
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
```
|
||||
54
css/snippets/button-border-animation.md
Normal file
54
css/snippets/button-border-animation.md
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
title: Button border animation
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: highlands
|
||||
dateModified: 2021-05-24T15:28:52+03:00
|
||||
---
|
||||
|
||||
Creates a border animation on hover.
|
||||
|
||||
- Use the `::before` and `::after` pseudo-elements to create two boxes `24px` wide opposite each other above and below the box.
|
||||
- Use the `:hover` pseudo-class to extend the `width` of those elements to `100%` on hover and animate the change using `transition`.
|
||||
|
||||
```html
|
||||
<button class="animated-border-button">Submit</button>
|
||||
```
|
||||
|
||||
```css
|
||||
.animated-border-button {
|
||||
background-color: #263059;
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
outline: none;
|
||||
padding: 12px 40px 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.animated-border-button::before,
|
||||
.animated-border-button::after {
|
||||
border: 0 solid transparent;
|
||||
transition: all 0.3s;
|
||||
content: '';
|
||||
height: 0;
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.animated-border-button::before {
|
||||
border-top: 2px solid #263059;
|
||||
right: 0;
|
||||
top: -4px;
|
||||
}
|
||||
|
||||
.animated-border-button::after {
|
||||
border-bottom: 2px solid #263059;
|
||||
bottom: -4px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.animated-border-button:hover::before,
|
||||
.animated-border-button:hover::after {
|
||||
width: 100%;
|
||||
}
|
||||
```
|
||||
56
css/snippets/button-focus-swing-animation.md
Normal file
56
css/snippets/button-focus-swing-animation.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: Button swing animation
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
author: chalarangelo
|
||||
cover: painters-desk
|
||||
dateModified: 2021-05-24T15:28:52+03:00
|
||||
---
|
||||
|
||||
Creates a swing animation on focus.
|
||||
|
||||
- Use an appropriate `transition` to animate changes to the element.
|
||||
- Use the `:focus` pseudo-class to apply an `animation` that uses `transform` to make the element swing.
|
||||
- Use `animation-iteration-count` to only play the animation once.
|
||||
|
||||
```html
|
||||
<button class="button-swing">Submit</button>
|
||||
```
|
||||
|
||||
```css
|
||||
.button-swing {
|
||||
color: #65b5f6;
|
||||
background-color: transparent;
|
||||
border: 1px solid #65b5f6;
|
||||
border-radius: 4px;
|
||||
padding: 0 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.button-swing:focus {
|
||||
animation: swing 1s ease;
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
@keyframes swing {
|
||||
15% {
|
||||
transform: translateX(5px);
|
||||
}
|
||||
30% {
|
||||
transform: translateX(-5px);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
65% {
|
||||
transform: translateX(-3px);
|
||||
}
|
||||
80% {
|
||||
transform: translateX(2px);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
```
|
||||
32
css/snippets/button-hover-fill-animation.md
Normal file
32
css/snippets/button-hover-fill-animation.md
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
title: Button fill animation
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: beach-pineapple
|
||||
dateModified: 2021-04-02T21:34:43+03:00
|
||||
---
|
||||
|
||||
Creates a fill animation on hover.
|
||||
|
||||
- Set a `color` and `background` and use an appropriate `transition` to animate changes to the element.
|
||||
- Use the `:hover` pseudo-class to change the `background` and `color` of the element when the user hovers over it.
|
||||
|
||||
```html
|
||||
<button class="animated-fill-button">Submit</button>
|
||||
```
|
||||
|
||||
```css
|
||||
.animated-fill-button {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: 1px solid #000;
|
||||
cursor: pointer;
|
||||
transition: 0.3s all ease-in-out;
|
||||
}
|
||||
|
||||
.animated-fill-button:hover {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
```
|
||||
33
css/snippets/button-hover-grow-animation.md
Normal file
33
css/snippets/button-hover-grow-animation.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
title: Button grow animation
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
author: chalarangelo
|
||||
cover: white-laptop
|
||||
dateModified: 2021-05-24T15:28:52+03:00
|
||||
---
|
||||
|
||||
Creates a grow animation on hover.
|
||||
|
||||
- Use an appropriate `transition` to animate changes to the element.
|
||||
- Use the `:hover` pseudo-class to change the `transform` to `scale(1.1)`, growing the element when the user hovers over it.
|
||||
|
||||
```html
|
||||
<button class="button-grow">Submit</button>
|
||||
```
|
||||
|
||||
```css
|
||||
.button-grow {
|
||||
color: #65b5f6;
|
||||
background-color: transparent;
|
||||
border: 1px solid #65b5f6;
|
||||
border-radius: 4px;
|
||||
padding: 0 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.button-grow:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
```
|
||||
33
css/snippets/button-hover-shrink-animation.md
Normal file
33
css/snippets/button-hover-shrink-animation.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
title: Button shrink animation
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
author: chalarangelo
|
||||
cover: clay-pot-horizon
|
||||
dateModified: 2021-05-24T15:28:52+03:00
|
||||
---
|
||||
|
||||
Creates a shrink animation on hover.
|
||||
|
||||
- Use an appropriate `transition` to animate changes to the element.
|
||||
- Use the `:hover` pseudo-class to change the `transform` to `scale(0.8)`, shrinking the element when the user hovers over it.
|
||||
|
||||
```html
|
||||
<button class="button-shrink">Submit</button>
|
||||
```
|
||||
|
||||
```css
|
||||
.button-shrink {
|
||||
color: #65b5f6;
|
||||
background-color: transparent;
|
||||
border: 1px solid #65b5f6;
|
||||
border-radius: 4px;
|
||||
padding: 0 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.button-shrink:hover {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
```
|
||||
81
css/snippets/card-image-cutout.md
Normal file
81
css/snippets/card-image-cutout.md
Normal file
@ -0,0 +1,81 @@
|
||||
---
|
||||
title: Card with image cutout
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: radio-monstera
|
||||
dateModified: 2022-12-11T05:00:00-04:00
|
||||
---
|
||||
|
||||
Creates a card with an image cutout.
|
||||
|
||||
- Use `background` to add a colored background to a `.container` element.
|
||||
- Create a `.card` containing a `figure` with the appropriate image for the cutout and any other content you want.
|
||||
- Use the `::before` pseudo-element to add a `border` around the `figure` element, matching the `.container` element's `background` and creating the illusion of a cutout in the `.card`.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<figure>
|
||||
<img alt="" src="https://picsum.photos/id/447/400/400"/>
|
||||
</figure>
|
||||
<p class="content">Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
display: flex;
|
||||
padding: 96px 24px 48px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #f3f1fe;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 350px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
margin: 8px;
|
||||
box-shadow: 0 0 5px -2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card figure {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
margin-top: -60px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card figure::before {
|
||||
content: "";
|
||||
border-radius: inherit;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
border: 1rem solid #f3f1fe;
|
||||
box-shadow: 0 1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card figure img {
|
||||
border-radius: inherit;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.card .content {
|
||||
text-align: center;
|
||||
margin: 2rem;
|
||||
line-height: 1.5;
|
||||
color: #101010;
|
||||
}
|
||||
```
|
||||
44
css/snippets/checkerboard-pattern.md
Normal file
44
css/snippets/checkerboard-pattern.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
title: Checkerboard background pattern
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: digital-nomad-2
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates a checkerboard background pattern.
|
||||
|
||||
- Use `background-color` to set a white background.
|
||||
- Use `background-image` with two `linear-gradient()` values. Give each one a different angle to create the checkerboard pattern.
|
||||
- Use `background-size` to specify the pattern's size.
|
||||
- **Note:** The fixed `height` and `width` of the element is for demonstration purposes only.
|
||||
|
||||
```html
|
||||
<div class="checkerboard"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.checkerboard {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
background-color: #fff;
|
||||
background-image: linear-gradient(
|
||||
45deg,
|
||||
#000 25%,
|
||||
transparent 25%,
|
||||
transparent 75%,
|
||||
#000 75%,
|
||||
#000
|
||||
),
|
||||
linear-gradient(
|
||||
-45deg,
|
||||
#000 25%,
|
||||
transparent 25%,
|
||||
transparent 75%,
|
||||
#000 75%,
|
||||
#000
|
||||
);
|
||||
background-size: 60px 60px;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
```
|
||||
25
css/snippets/circle.md
Normal file
25
css/snippets/circle.md
Normal file
@ -0,0 +1,25 @@
|
||||
---
|
||||
title: Circle
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: oven-paddle
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Creates a circular shape with pure CSS.
|
||||
|
||||
- Use `border-radius: 50%` to curve the borders of the element to create a circle.
|
||||
- Since a circle has the same radius at any given point, the `width` and `height` must be the same. Differing values will create an ellipse.
|
||||
|
||||
```html
|
||||
<div class="circle"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.circle {
|
||||
border-radius: 50%;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: #9C27B0;
|
||||
}
|
||||
```
|
||||
35
css/snippets/clearfix.md
Normal file
35
css/snippets/clearfix.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Clearfix
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: memories-of-pineapple-3
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Ensures that an element self-clears its children.
|
||||
|
||||
- Use the `::after` pseudo-element and apply `content: ''` to allow it to affect layout.
|
||||
- Use `clear: both` to make the element clear past both left and right floats.
|
||||
- For this technique to work properly, make sure there are no non-floating children in the container and that there are no tall floats before the clearfixed container but in the same formatting context (e.g. floated columns).
|
||||
- **Note:** This is only useful if you are using `float` to build layouts. Consider using a more modern approach, such as the flexbox or grid layout.
|
||||
|
||||
```html
|
||||
<div class="clearfix">
|
||||
<div class="floated">float a</div>
|
||||
<div class="floated">float b</div>
|
||||
<div class="floated">float c</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.clearfix::after {
|
||||
content: '';
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.floated {
|
||||
float: left;
|
||||
padding: 4px;
|
||||
}
|
||||
```
|
||||
35
css/snippets/constant-width-to-height-ratio.md
Normal file
35
css/snippets/constant-width-to-height-ratio.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Constant width to height ratio
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: clutter
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Ensures that an element with variable `width` will retain a proportionate `height` value.
|
||||
|
||||
- Apply `padding-top` on the `::before` pseudo-element, making the `height` of the element equal to a percentage of its `width`.
|
||||
- The proportion of `height` to `width` can be altered as necessary. For example a `padding-top` of `100%` will create a responsive square (1:1 ratio).
|
||||
|
||||
```html
|
||||
<div class="constant-width-to-height-ratio"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.constant-width-to-height-ratio {
|
||||
background: #9C27B0;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.constant-width-to-height-ratio::before {
|
||||
content: '';
|
||||
padding-top: 100%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.constant-width-to-height-ratio::after {
|
||||
content: '';
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
```
|
||||
40
css/snippets/counter.md
Normal file
40
css/snippets/counter.md
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
title: Counter
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: laptop-plants
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Creates a custom list counter that accounts for nested list elements.
|
||||
|
||||
- Use `counter-reset` to initialize a variable counter (default `0`), the name of which is the value of the attribute (i.e. `counter`).
|
||||
- Use `counter-increment` on the variable counter for each countable element (i.e. each `<li>`).
|
||||
- Use `counters()` to display the value of each variable counter as part of the `content` of the `::before` pseudo-element for each countable element (i.e. each `<li>`). The second value passed to it (`'.'`) acts as the delimiter for nested counters.
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li>List item</li>
|
||||
<li>List item</li>
|
||||
<li>
|
||||
List item
|
||||
<ul>
|
||||
<li>List item</li>
|
||||
<li>List item</li>
|
||||
<li>List item</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
```css
|
||||
ul {
|
||||
counter-reset: counter;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
li::before {
|
||||
counter-increment: counter;
|
||||
content: counters(counter, '.') ' ';
|
||||
}
|
||||
```
|
||||
151
css/snippets/custom-checkbox.md
Normal file
151
css/snippets/custom-checkbox.md
Normal file
@ -0,0 +1,151 @@
|
||||
---
|
||||
title: Custom checkbox
|
||||
type: snippet
|
||||
tags: [visual,animation]
|
||||
author: chalarangelo
|
||||
cover: interior-8
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Creates a styled checkbox with animation on state change.
|
||||
|
||||
- Use an `<svg>` element to create the check `<symbol>` and insert it via the `<use>` element to create a reusable SVG icon.
|
||||
- Create a `.checkbox-container` and use flexbox to create the appropriate layout for the checkboxes.
|
||||
- Hide the `<input>` element and use the `label` associated with it to display a checkbox and the provided text.
|
||||
- Use `stroke-dashoffset` to animate the check symbol on state change.
|
||||
- Use `transform: scale(0.9)` via a CSS animation to create a zoom animation effect.
|
||||
|
||||
```html
|
||||
<svg class="checkbox-symbol">
|
||||
<symbol id="check" viewbox="0 0 12 10">
|
||||
<polyline
|
||||
points="1.5 6 4.5 9 10.5 1"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
></polyline>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
<div class="checkbox-container">
|
||||
<input class="checkbox-input" id="apples" type="checkbox" />
|
||||
<label class="checkbox" for="apples">
|
||||
<span>
|
||||
<svg width="12px" height="10px">
|
||||
<use xlink:href="#check"></use>
|
||||
</svg>
|
||||
</span>
|
||||
<span>Apples</span>
|
||||
</label>
|
||||
<input class="checkbox-input" id="oranges" type="checkbox" />
|
||||
<label class="checkbox" for="oranges">
|
||||
<span>
|
||||
<svg width="12px" height="10px">
|
||||
<use xlink:href="#check"></use>
|
||||
</svg>
|
||||
</span>
|
||||
<span>Oranges</span>
|
||||
</label>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.checkbox-symbol {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.checkbox-container {
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
color: #222;
|
||||
height: 64px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
.checkbox-container * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.checkbox-input {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
padding: 6px 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.checkbox:not(:last-child) {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.checkbox:hover {
|
||||
background: rgba(0, 119, 255, 0.06);
|
||||
}
|
||||
|
||||
.checkbox span {
|
||||
vertical-align: middle;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.checkbox span:first-child {
|
||||
position: relative;
|
||||
flex: 0 0 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 4px;
|
||||
transform: scale(1);
|
||||
border: 1px solid #cccfdb;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.checkbox span:first-child svg {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 2px;
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
stroke-dasharray: 16px;
|
||||
stroke-dashoffset: 16px;
|
||||
transition: all 0.3s ease;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.checkbox span:last-child {
|
||||
padding-left: 8px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.checkbox:hover span:first-child {
|
||||
border-color: #0077ff;
|
||||
}
|
||||
|
||||
.checkbox-input:checked + .checkbox span:first-child {
|
||||
background: #0077ff;
|
||||
border-color: #0077ff;
|
||||
animation: zoom-in-out 0.3s ease;
|
||||
}
|
||||
|
||||
.checkbox-input:checked + .checkbox span:first-child svg {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
@keyframes zoom-in-out {
|
||||
50% {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
```
|
||||
83
css/snippets/custom-radio.md
Normal file
83
css/snippets/custom-radio.md
Normal file
@ -0,0 +1,83 @@
|
||||
---
|
||||
title: Custom radio button
|
||||
type: snippet
|
||||
tags: [visual,animation]
|
||||
author: chalarangelo
|
||||
cover: messy-computer
|
||||
dateModified: 2022-11-16T05:00:00-04:00
|
||||
---
|
||||
|
||||
Creates a styled radio button with animation on state change.
|
||||
|
||||
- Create a `.radio-container` and use flexbox to create the appropriate layout for the radio buttons.
|
||||
- Reset the styles on the `<input>` and use it to create the outline and background of the radio button.
|
||||
- Use the `::before` element to create the inner circle of the radio button.
|
||||
- Use `transform: scale(1)` and a CSS transition to create an animation effect on state change.
|
||||
|
||||
```html
|
||||
<div class="radio-container">
|
||||
<input class="radio-input" id="apples" type="radio" name="fruit" />
|
||||
<label class="radio" for="apples">Apples</label>
|
||||
<input class="radio-input" id="oranges" type="radio" name="fruit" />
|
||||
<label class="radio" for="oranges">Oranges</label>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.radio-container {
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
color: #222;
|
||||
height: 64px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
.radio-container * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.radio-input {
|
||||
appearance: none;
|
||||
background-color: #ffffff;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid #cccfdb;
|
||||
margin: 0;
|
||||
border-radius: 50%;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.radio-input::before {
|
||||
content: "";
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
transform: scale(0);
|
||||
transition: 0.3s transform ease-in-out;
|
||||
box-shadow: inset 6px 6px #ffffff;
|
||||
}
|
||||
|
||||
.radio-input:checked {
|
||||
background: #0077ff;
|
||||
border-color: #0077ff;
|
||||
}
|
||||
|
||||
.radio-input:checked::before {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.radio {
|
||||
cursor: pointer;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
.radio:not(:last-child) {
|
||||
margin-right: 6px;
|
||||
}
|
||||
```
|
||||
46
css/snippets/custom-scrollbar.md
Normal file
46
css/snippets/custom-scrollbar.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: Custom scrollbar
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: sea-view
|
||||
dateModified: 2021-05-16T13:09:15+03:00
|
||||
---
|
||||
|
||||
Customizes the scrollbar style for elements with scrollable overflow.
|
||||
|
||||
- Use `::-webkit-scrollbar` to style the scrollbar element.
|
||||
- Use `::-webkit-scrollbar-track` to style the scrollbar track (the background of the scrollbar).
|
||||
- Use `::-webkit-scrollbar-thumb` to style the scrollbar thumb (the draggable element).
|
||||
- **Note:** Scrollbar styling doesn't appear to be on any standards track. This technique only works on WebKit-based browsers.
|
||||
|
||||
```html
|
||||
<div class="custom-scrollbar">
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.<br />
|
||||
Iure id exercitationem nulla qui repellat laborum vitae, <br />
|
||||
molestias tempora velit natus. Quas, assumenda nisi. <br />
|
||||
Quisquam enim qui iure, consequatur velit sit?
|
||||
</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.custom-scrollbar {
|
||||
height: 70px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: #1E3F20;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: #4A7856;
|
||||
border-radius: 12px;
|
||||
}
|
||||
```
|
||||
27
css/snippets/custom-text-selection.md
Normal file
27
css/snippets/custom-text-selection.md
Normal file
@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Custom text selection
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: digital-nomad
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Changes the styling of text selection.
|
||||
|
||||
- Use the `::selection` pseudo-selector to style text within it when selected.
|
||||
|
||||
```html
|
||||
<p class="custom-text-selection">Select some of this text.</p>
|
||||
```
|
||||
|
||||
```css
|
||||
::selection {
|
||||
background: aquamarine;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.custom-text-selection::selection {
|
||||
background: deeppink;
|
||||
color: white;
|
||||
}
|
||||
```
|
||||
23
css/snippets/disable-selection.md
Normal file
23
css/snippets/disable-selection.md
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
title: Disable selection
|
||||
type: snippet
|
||||
tags: [interactivity]
|
||||
cover: interior-9
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Makes the content unselectable.
|
||||
|
||||
- Use `user-select: none` to make the content of the element not selectable.
|
||||
- **Note:** This is not a secure method to prevent users from copying content.
|
||||
|
||||
```html
|
||||
<p>You can select me.</p>
|
||||
<p class="unselectable">You can't select me!</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.unselectable {
|
||||
user-select: none;
|
||||
}
|
||||
```
|
||||
24
css/snippets/display-empty-links.md
Normal file
24
css/snippets/display-empty-links.md
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
title: Style links with no text
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: metro-tunnel
|
||||
dateModified: 2022-11-11T05:00:00-04:00
|
||||
---
|
||||
|
||||
Displays the link URL for links with no text.
|
||||
|
||||
- Use the `:empty` pseudo-class to select links with no text.
|
||||
- Use the `:not` pseudo-class to exclude links with text.
|
||||
- Use the `content` property and the `attr()` function to display the link URL in the `::before` pseudo-element.
|
||||
|
||||
```html
|
||||
<a href="https://30secondsofcode.org"></a>
|
||||
```
|
||||
|
||||
```css
|
||||
a[href^="http"]:empty::before {
|
||||
content: attr(href);
|
||||
}
|
||||
```
|
||||
41
css/snippets/display-table-centering.md
Normal file
41
css/snippets/display-table-centering.md
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
title: Display table centering
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: malibu
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Vertically and horizontally centers a child element within its parent element, using `display: table`.
|
||||
|
||||
- Use `display: table` to make the `.center` element behave like a `<table>` element.
|
||||
- Set `height` and `width` to `100%` to make the element fill the available space within its parent element.
|
||||
- Use `display: table-cell` on the child element to make it behave like a `<td>` elements.
|
||||
- Use `text-align: center` and `vertical-align: middle` on the child element to center it horizontally and vertically.
|
||||
- The outer parent (`.container`) must have a fixed `width` and `height`.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<div class="center"><span>Centered content</span></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
border: 1px solid #9C27B0;
|
||||
height: 250px;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: table;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.center > span {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
```
|
||||
37
css/snippets/donut-spinner.md
Normal file
37
css/snippets/donut-spinner.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: Donut spinner
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: digital-nomad-3
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates a donut spinner that can be used to indicate the loading of content.
|
||||
|
||||
- Use a semi-transparent `border` for the whole element. Exclude one side that will serve as the loading indicator for the donut.
|
||||
- Define and use an appropriate animation, using `transform: rotate()` to rotate the element.
|
||||
|
||||
```html
|
||||
<div class="donut"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
@keyframes donut-spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.donut {
|
||||
display: inline-block;
|
||||
border: 4px solid rgba(0, 0, 0, 0.1);
|
||||
border-left-color: #7983ff;
|
||||
border-radius: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
animation: donut-spin 1.2s linear infinite;
|
||||
}
|
||||
```
|
||||
28
css/snippets/drop-cap.md
Normal file
28
css/snippets/drop-cap.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Drop cap
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: bamboo-lamp
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Makes the first letter of the first paragraph bigger than the rest of the text.
|
||||
|
||||
- Use the `:first-child` selector to select only the first paragraph.
|
||||
- Use the `::first-letter` pseudo-element to style the first element of the paragraph.
|
||||
|
||||
```html
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam commodo ligula quis tincidunt cursus. Integer consectetur tempor ex eget hendrerit. Cras facilisis sodales odio nec maximus. Pellentesque lacinia convallis libero, rhoncus tincidunt ante dictum at. Nullam facilisis lectus tellus, sit amet congue erat sodales commodo.</p>
|
||||
<p>Donec magna erat, imperdiet non odio sed, sodales tempus magna. Integer vitae orci lectus. Nullam consectetur orci at pellentesque efficitur.</p>
|
||||
```
|
||||
|
||||
```css
|
||||
p:first-child::first-letter {
|
||||
color: #5f79ff;
|
||||
float: left;
|
||||
margin: 0 8px 0 4px;
|
||||
font-size: 3rem;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
```
|
||||
40
css/snippets/dynamic-shadow.md
Normal file
40
css/snippets/dynamic-shadow.md
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
title: Dynamic shadow
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: couch-laptop
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Creates a shadow similar to `box-shadow` but based on the colors of the element itself.
|
||||
|
||||
- Use the `::after` pseudo-element with `position: absolute` and `width` and `height` equal to `100%` to fill the available space in the parent element.
|
||||
- Use `background: inherit` to inherit the `background` of the parent element.
|
||||
- Use `top` to slightly offset the pseudo-element, `filter: blur()` to create a shadow and `opacity` to make it semi-transparent.
|
||||
- Use `z-index: 1` on the parent and `z-index: -1` on the pseudo-element to position it behind its parent.
|
||||
|
||||
```html
|
||||
<div class="dynamic-shadow"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.dynamic-shadow {
|
||||
position: relative;
|
||||
width: 10rem;
|
||||
height: 10rem;
|
||||
background: linear-gradient(75deg, #6d78ff, #00ffb8);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.dynamic-shadow::after {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
background: inherit;
|
||||
top: 0.5rem;
|
||||
filter: blur(0.4rem);
|
||||
opacity: 0.7;
|
||||
z-index: -1;
|
||||
}
|
||||
```
|
||||
26
css/snippets/etched-text.md
Normal file
26
css/snippets/etched-text.md
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Etched text
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: memories-of-pineapple-2
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Creates an effect where text appears to be "etched" or engraved into the background.
|
||||
|
||||
- Use `text-shadow` to create 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.
|
||||
|
||||
```html
|
||||
<p class="etched-text">I appear etched into the background.</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.etched-text {
|
||||
text-shadow: 0 2px white;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: #b8bec5;
|
||||
}
|
||||
```
|
||||
28
css/snippets/evenly-distributed-children.md
Normal file
28
css/snippets/evenly-distributed-children.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Evenly distributed children
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: little-bird
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Evenly distributes child elements within a parent element.
|
||||
|
||||
- Use `display: flex` to use the flexbox layout.
|
||||
- Use `justify-content: space-between` to evenly distributes child elements horizontally. The first item is positioned at the left edge, while the last item is positioned at the right edge.
|
||||
- Alternatively, use `justify-content: space-around` to distribute the children with space around them, instead of between them.
|
||||
|
||||
```html
|
||||
<div class="evenly-distributed-children">
|
||||
<p>Item1</p>
|
||||
<p>Item2</p>
|
||||
<p>Item3</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.evenly-distributed-children {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
```
|
||||
37
css/snippets/fit-image-in-container.md
Normal file
37
css/snippets/fit-image-in-container.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: Fit image in container
|
||||
type: snippet
|
||||
tags: [layout,visual]
|
||||
cover: succulent-3
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Fits an positions an image appropriately inside its container while preserving its aspect ratio.
|
||||
|
||||
- Use `object-fit: contain` to fit the entire image within the container while preserving its aspect ratio.
|
||||
- Use `object-fit: cover` to fill the container with the image while preserving its aspect ratio.
|
||||
- Use `object-position: center` to position the image at the center of the container.
|
||||
|
||||
```html
|
||||
<img class="image image-contain" src="https://picsum.photos/600/200" />
|
||||
<img class="image image-cover" src="https://picsum.photos/600/200" />
|
||||
```
|
||||
|
||||
```css
|
||||
.image {
|
||||
background: #34495e;
|
||||
border: 1px solid #34495e;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.image-contain {
|
||||
object-fit: contain;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.image-cover {
|
||||
object-fit: cover;
|
||||
object-position: right top;
|
||||
}
|
||||
```
|
||||
28
css/snippets/flexbox-centering.md
Normal file
28
css/snippets/flexbox-centering.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Flexbox centering
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: basket-paper
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Horizontally and vertically centers a child element within a parent element using flexbox.
|
||||
|
||||
- Use `display: flex` to create a flexbox layout.
|
||||
- Use `justify-content: center` to center the child horizontally.
|
||||
- Use `align-items: center` to center the child vertically.
|
||||
|
||||
```html
|
||||
<div class="flexbox-centering">
|
||||
<div>Centered content.</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.flexbox-centering {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100px;
|
||||
}
|
||||
```
|
||||
105
css/snippets/floating-list-titles.md
Normal file
105
css/snippets/floating-list-titles.md
Normal file
@ -0,0 +1,105 @@
|
||||
---
|
||||
title: List with floating section headings
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: pop-of-green
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Creates a list with floating headings for each section.
|
||||
|
||||
- Use `overflow-y: auto` to allow the list container to overflow vertically.
|
||||
- Use `display: grid` on the inner container (`<dl>`) to create a layout with two columns.
|
||||
- Set headings (`<dt>`) to `grid-column: 1` and content (`<dd>`) to `grid-column: 2`.
|
||||
- Finally, apply `position: sticky` and `top: 0.5rem` to headings to create a floating effect.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<div class="floating-stack">
|
||||
<dl>
|
||||
<dt>A</dt>
|
||||
<dd>Algeria</dd>
|
||||
<dd>Angola</dd>
|
||||
|
||||
<dt>B</dt>
|
||||
<dd>Benin</dd>
|
||||
<dd>Botswana</dd>
|
||||
<dd>Burkina Faso</dd>
|
||||
<dd>Burundi</dd>
|
||||
|
||||
<dt>C</dt>
|
||||
<dd>Cabo Verde</dd>
|
||||
<dd>Cameroon</dd>
|
||||
<dd>Central African Republic</dd>
|
||||
<dd>Chad</dd>
|
||||
<dd>Comoros</dd>
|
||||
<dd>Congo, Democratic Republic of the</dd>
|
||||
<dd>Congo, Republic of the</dd>
|
||||
<dd>Cote d'Ivoire</dd>
|
||||
|
||||
<dt>D</dt>
|
||||
<dd>Djibouti</dd>
|
||||
|
||||
<dt>E</dt>
|
||||
<dd>Egypt</dd>
|
||||
<dd>Equatorial Guinea</dd>
|
||||
<dd>Eritrea</dd>
|
||||
<dd>Eswatini (formerly Swaziland)</dd>
|
||||
<dd>Ethiopia</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.floating-stack {
|
||||
background: #455A64;
|
||||
color: #fff;
|
||||
height: 80vh;
|
||||
width: 320px;
|
||||
border-radius: 1rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.floating-stack > dl {
|
||||
margin: 0 0 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: 2.5rem 1fr;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.floating-stack dt {
|
||||
position: sticky;
|
||||
top: 0.5rem;
|
||||
left: 0.5rem;
|
||||
font-weight: bold;
|
||||
background: #263238;
|
||||
color: #cfd8dc;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
border-radius: 50%;
|
||||
padding: 0.25rem 1rem;
|
||||
grid-column: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.floating-stack dd {
|
||||
grid-column: 2;
|
||||
margin: 0;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.floating-stack > dl:first-of-type > dd:first-of-type {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
```
|
||||
23
css/snippets/fluid-typography.md
Normal file
23
css/snippets/fluid-typography.md
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
title: Fluid typography
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: shell-focus
|
||||
dateModified: 2021-05-16T11:23:05+03:00
|
||||
---
|
||||
|
||||
Creates text that scales according to the viewport width.
|
||||
|
||||
- Use the `clamp()` CSS function to clamp the value of `font-size` between `1rem` and `3rem`.
|
||||
- Use the formula `8vw - 2rem` to calculate a responsive value for `font-size` (`1rem` at `600px`, `3rem` at `1000px`).
|
||||
|
||||
```html
|
||||
<p class="fluid-type">Hello World!</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.fluid-type {
|
||||
font-size: clamp(1rem, 8vw - 2rem, 3rem);
|
||||
}
|
||||
```
|
||||
42
css/snippets/focus-within.md
Normal file
42
css/snippets/focus-within.md
Normal file
@ -0,0 +1,42 @@
|
||||
---
|
||||
title: Focus Within
|
||||
type: snippet
|
||||
tags: [visual,interactivity]
|
||||
cover: boats
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Changes the appearance of a form if any of its children are focused.
|
||||
|
||||
- Use the pseudo-class `:focus-within` to apply styles to a parent element if any child element gets focused.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="username">Username:</label>
|
||||
<input id="username" type="text" />
|
||||
<br />
|
||||
<label for="password">Password:</label>
|
||||
<input id="password" type="text" />
|
||||
</form>
|
||||
```
|
||||
|
||||
```css
|
||||
form {
|
||||
border: 2px solid #52B882;
|
||||
padding: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
form:focus-within {
|
||||
background: #7CF0BD;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
width: 72px;
|
||||
}
|
||||
|
||||
input {
|
||||
margin: 4px 12px;
|
||||
}
|
||||
```
|
||||
58
css/snippets/full-width.md
Normal file
58
css/snippets/full-width.md
Normal file
@ -0,0 +1,58 @@
|
||||
---
|
||||
title: Full-width image
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
author: chalarangelo
|
||||
cover: yellow-white-mug-2
|
||||
dateModified: 2021-01-07T10:14:46+02:00
|
||||
---
|
||||
|
||||
Creates a full-width image.
|
||||
|
||||
- Use `left: 50%` and `right: 50%` to position the image in the middle of the parent element.
|
||||
- Use `margin-left: -50vw` and `margin-right: -50vw` to offset the image on both sides relative to the size of the viewport.
|
||||
- Use `width: 100vw` and `max-width: 100vw` to size the image relative to the viewport.
|
||||
|
||||
```html
|
||||
<main>
|
||||
<h4>Lorem ipsum dolor sit amet</h4>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris molestie
|
||||
lobortis sapien, sit amet iaculis est interdum tincidunt. Nunc egestas nibh
|
||||
ut metus elementum consequat. Integer elit orci, rhoncus efficitur lectus
|
||||
eu, faucibus interdum felis.
|
||||
</p>
|
||||
<p>
|
||||
<img class="full-width" src="https://picsum.photos/id/257/2560/1440.jpg" />
|
||||
</p>
|
||||
<p>
|
||||
Orci varius natoque penatibus et magnis dis parturient montes, nascetur
|
||||
ridiculus mus. Nullam pretium lectus sed ex efficitur, ac varius sapien
|
||||
gravida. Sed facilisis elit quis sem sollicitudin, ut aliquam neque
|
||||
eleifend. Maecenas sagittis neque sapien, ac tempus nulla tempus nec.
|
||||
Curabitur tellus est, convallis id dolor ut, porta hendrerit quam.
|
||||
</p>
|
||||
</main>
|
||||
```
|
||||
|
||||
```css
|
||||
main {
|
||||
margin: 0 auto;
|
||||
max-width: 640px;
|
||||
}
|
||||
|
||||
img {
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
position: relative;
|
||||
left: 50%;
|
||||
right: 50%;
|
||||
margin-left: -50vw;
|
||||
margin-right: -50vw;
|
||||
max-width: 100vw;
|
||||
width: 100vw;
|
||||
}
|
||||
```
|
||||
54
css/snippets/fullscreen.md
Normal file
54
css/snippets/fullscreen.md
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
title: Fullscreen
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: flower-portrait-3
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Applies styles to an element when in fullscreen mode.
|
||||
|
||||
- Use the `:fullscreen` CSS pseudo-element selector to select and style an element that is displayed in fullscreen mode.
|
||||
- Use a `<button>` and `Element.requestFullscreen()` to create a button that makes the element fullscreen for the purposes of previewing the style.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<p><em>Click the button below to enter the element into fullscreen mode. </em></p>
|
||||
<div class="element" id="element"><p>I change color in fullscreen mode!</p></div>
|
||||
<br />
|
||||
<button onclick="var el = document.getElementById('element'); el.requestFullscreen();">
|
||||
Go Full Screen!
|
||||
</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
margin: 40px auto;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.element {
|
||||
padding: 20px;
|
||||
height: 300px;
|
||||
width: 100%;
|
||||
background-color: skyblue;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.element p {
|
||||
text-align: center;
|
||||
color: white;
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
.element:-ms-fullscreen p {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.element:fullscreen {
|
||||
background-color: #e4708a;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
```
|
||||
26
css/snippets/gradient-text.md
Normal file
26
css/snippets/gradient-text.md
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Gradient text
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: red-berries
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Gives text a gradient color.
|
||||
|
||||
- Use `background` with a `linear-gradient()` value to give the text element a gradient background.
|
||||
- Use `webkit-text-fill-color: transparent` to fill the text with a transparent color.
|
||||
- Use `webkit-background-clip: text` to clip the background with the text, filling the text with the gradient background as the color.
|
||||
|
||||
```html
|
||||
<p class="gradient-text">Gradient text</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.gradient-text {
|
||||
background: linear-gradient(#70D6FF, #00072D);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
font-size: 32px;
|
||||
}
|
||||
```
|
||||
28
css/snippets/grid-centering.md
Normal file
28
css/snippets/grid-centering.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Grid centering
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: work-hard-computer
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Horizontally and vertically centers a child element within a parent element using `grid`.
|
||||
|
||||
- Use `display: grid` to create a grid layout.
|
||||
- Use `justify-content: center` to center the child horizontally.
|
||||
- Use `align-items: center` to center the child vertically.
|
||||
|
||||
```html
|
||||
<div class="grid-centering">
|
||||
<div class="child">Centered content.</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.grid-centering {
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100px;
|
||||
}
|
||||
```
|
||||
55
css/snippets/hamburger-button.md
Normal file
55
css/snippets/hamburger-button.md
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
title: Hamburger Button
|
||||
type: snippet
|
||||
tags: [interactivity]
|
||||
cover: volcano-sunset
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Displays a hamburger menu which transitions to a cross button on hover.
|
||||
|
||||
- Use a `.hamburger-menu` container `div` which contains the top, bottom, and middle bars.
|
||||
- Set the container to `display: flex` with `flex-flow: column wrap`.
|
||||
- Add distance between the bars using `justify-content: space-between`.
|
||||
- Use `transform: rotate()` to rotate the top and bottom bars by 45 degrees and `opacity: 0` to fade the middle bar on hover.
|
||||
- Use `transform-origin: left` so that the bars rotate around the left point.
|
||||
|
||||
```html
|
||||
<div class="hamburger-menu">
|
||||
<div class="bar top"></div>
|
||||
<div class="bar middle"></div>
|
||||
<div class="bar bottom"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.hamburger-menu {
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
justify-content: space-between;
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hamburger-menu .bar {
|
||||
height: 5px;
|
||||
background: black;
|
||||
border-radius: 5px;
|
||||
margin: 3px 0px;
|
||||
transform-origin: left;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.hamburger-menu:hover .top {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.hamburger-menu:hover .middle {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hamburger-menu:hover .bottom {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
```
|
||||
41
css/snippets/height-transition.md
Normal file
41
css/snippets/height-transition.md
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
title: Height transition
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: washed-ashore
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Transitions an element's height from `0` to `auto` when its height is unknown.
|
||||
|
||||
- Use `transition` to specify that changes to `max-height` should be transitioned over.
|
||||
- Use `overflow: hidden` to prevent the contents of the hidden element from overflowing its container.
|
||||
- Use `max-height` to specify an initial height of `0`.
|
||||
- Use the `:hover` pseudo-class to change the `max-height` to the value of the `--max-height` variable set by JavaScript.
|
||||
- Use `Element.scrollHeight` and `CSSStyleDeclaration.setProperty()` to set the value of `--max-height` to the current height of the element.
|
||||
- **Note:** Causes reflow on each animation frame, which will be laggy if there are a large number of elements beneath the element that is transitioning in height.
|
||||
|
||||
```html
|
||||
<div class="trigger">
|
||||
Hover me to see a height transition.
|
||||
<div class="el">Additional content</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.el {
|
||||
transition: max-height 0.3s;
|
||||
overflow: hidden;
|
||||
max-height: 0;
|
||||
}
|
||||
|
||||
.trigger:hover > .el {
|
||||
max-height: var(--max-height);
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
let el = document.querySelector('.el');
|
||||
let height = el.scrollHeight;
|
||||
el.style.setProperty('--max-height', height + 'px');
|
||||
```
|
||||
22
css/snippets/hide-empty-elements.md
Normal file
22
css/snippets/hide-empty-elements.md
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
title: Hide empty elements
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: metro-arrival
|
||||
dateModified: 2022-11-18T05:00:00-04:00
|
||||
---
|
||||
|
||||
Hides elements with no content.
|
||||
|
||||
- Use the `:empty` pseudo-class to select elements with no content.
|
||||
|
||||
```html
|
||||
<p>Lorem ipsum dolor sit amet. <button></button></p>
|
||||
```
|
||||
|
||||
```css
|
||||
:empty {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
36
css/snippets/hide-scrollbars.md
Normal file
36
css/snippets/hide-scrollbars.md
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
title: Hide scroll bars
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: by-the-lighthouse
|
||||
dateModified: 2022-05-13T05:00:00-04:00
|
||||
---
|
||||
|
||||
Hides scrollbars on an element, while still allowing it to be scrollable.
|
||||
|
||||
- Use `overflow: auto` to allow the element to be scrollable.
|
||||
- Use `scrollbar-width: none` to hide scrollbars on Firefox.
|
||||
- Use `display: none` on the `::-webkit-scrollbar` pseudo-element to hide scrollbars on WebKit browsers (Chrome, Edge, Safari).
|
||||
|
||||
```html
|
||||
<div class="no-scrollbars">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean interdum id leo a consectetur. Integer justo magna, ultricies vel enim vitae, egestas efficitur leo. Ut nulla orci, rutrum eu augue sed, tempus pellentesque quam.</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
div {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.no-scrollbars {
|
||||
overflow: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.no-scrollbars::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
124
css/snippets/horizontal-gallery.md
Normal file
124
css/snippets/horizontal-gallery.md
Normal file
@ -0,0 +1,124 @@
|
||||
---
|
||||
title: Image gallery with horizontal scroll
|
||||
type: snippet
|
||||
tags: [visual,interactivity]
|
||||
cover: flower-portrait-5
|
||||
dateModified: 2022-05-01T05:00:00-04:00
|
||||
---
|
||||
|
||||
Creates a horizontally scrollable image gallery.
|
||||
|
||||
- Position the `.thumbnails` at the bottom of the container using `position: absolute`.
|
||||
- Use `scroll-snap-type: x mandatory` and `overscroll-behavior-x: contain` to create a snap effect on horizontal scroll. Snap elements to the start of the container using `scroll-snap-align: start`.
|
||||
- Hide scrollbars using `scrollbar-width: none` and styling the pseudo-element `::-webkit-scrollbar` to `display: none`.
|
||||
- Use `Element.scrollTo()` to define a `scrollToElement` function, that scrolls the gallery to the given item.
|
||||
- Use `Array.prototype.map()` and `Array.prototype.join()` to populate the `.thumbnails` element. Give each thumbnail a `data-id` attribute with the index of the image.
|
||||
- Use `Document.querySelectorAll()` to get all the thumbnail elements. Use `Array.prototype.forEach()` to register a handler for the `'click'` event on each thumbnail, using `EventTarget.addEventListener()` and the `scrollToElement` function.
|
||||
- Use `Document.querySelector()` and `EventTarget.addEventListener()` to register a handler for the `'scroll'` event. Update the `.thumbnails` element to match the current scroll position, using the `highlightThumbnail` function.
|
||||
|
||||
```html
|
||||
<div class="gallery-container">
|
||||
<div class="thumbnails"></div>
|
||||
<div class="slides">
|
||||
<div><img src="https://picsum.photos/id/1067/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/122/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/188/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/249/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/257/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/259/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/283/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/288/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/299/540/720"></div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.gallery-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.thumbnails {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.thumbnails div {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
cursor: pointer;
|
||||
background: #aaa;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.thumbnails div.highlighted {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
.slides {
|
||||
margin: 0 16px;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
gap: 1rem;
|
||||
width: 540px;
|
||||
padding: 0 0.25rem;
|
||||
height: 720px;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior-x: contain;
|
||||
scroll-snap-type: x mandatory;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.slides > div {
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
|
||||
.slides img {
|
||||
width: 540px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.slides::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const slideGallery = document.querySelector('.slides');
|
||||
const slides = slideGallery.querySelectorAll('div');
|
||||
const thumbnailContainer = document.querySelector('.thumbnails');
|
||||
const slideCount = slides.length;
|
||||
const slideWidth = 540;
|
||||
|
||||
const highlightThumbnail = () => {
|
||||
thumbnailContainer
|
||||
.querySelectorAll('div.highlighted')
|
||||
.forEach(el => el.classList.remove('highlighted'));
|
||||
const index = Math.floor(slideGallery.scrollLeft / slideWidth);
|
||||
thumbnailContainer
|
||||
.querySelector(`div[data-id="${index}"]`)
|
||||
.classList.add('highlighted');
|
||||
};
|
||||
|
||||
const scrollToElement = el => {
|
||||
const index = parseInt(el.dataset.id, 10);
|
||||
slideGallery.scrollTo(index * slideWidth, 0);
|
||||
};
|
||||
|
||||
thumbnailContainer.innerHTML += [...slides]
|
||||
.map((slide, i) => `<div data-id="${i}"></div>`)
|
||||
.join('');
|
||||
|
||||
thumbnailContainer.querySelectorAll('div').forEach(el => {
|
||||
el.addEventListener('click', () => scrollToElement(el));
|
||||
});
|
||||
|
||||
slideGallery.addEventListener('scroll', e => highlightThumbnail());
|
||||
|
||||
highlightThumbnail();
|
||||
```
|
||||
53
css/snippets/horizontal-scroll-snap.md
Normal file
53
css/snippets/horizontal-scroll-snap.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Horizontal scroll snap
|
||||
type: snippet
|
||||
tags: [interactivity]
|
||||
cover: waves-from-above
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Creates a horizontally scrollable container that will snap on elements when scrolling.
|
||||
|
||||
- Use `display: grid` and `grid-auto-flow: column` to create a horizontal layout.
|
||||
- Use `scroll-snap-type: x mandatory` and `overscroll-behavior-x: contain` to create a snap effect on horizontal scroll.
|
||||
- Change `scroll-snap-align` to either `start`, `stop` or `center` to change the snap alignment.
|
||||
|
||||
```html
|
||||
<div class="horizontal-snap">
|
||||
<a href="#"><img src="https://picsum.photos/id/1067/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/122/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/188/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/249/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/257/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/259/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/283/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/288/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/299/640/640"></a>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.horizontal-snap {
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
gap: 1rem;
|
||||
height: calc(180px + 1rem);
|
||||
padding: 1rem;
|
||||
max-width: 480px;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior-x: contain;
|
||||
scroll-snap-type: x mandatory;
|
||||
}
|
||||
|
||||
.horizontal-snap > a {
|
||||
scroll-snap-align: center;
|
||||
}
|
||||
|
||||
.horizontal-snap img {
|
||||
width: 180px;
|
||||
max-width: none;
|
||||
object-fit: contain;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
```
|
||||
75
css/snippets/hover-additional-content.md
Normal file
75
css/snippets/hover-additional-content.md
Normal file
@ -0,0 +1,75 @@
|
||||
---
|
||||
title: Show additional content on hover
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: dark-leaves-5
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Creates a card that displays additional content on hover.
|
||||
|
||||
- Use `overflow: hidden` on the card to hide elements that overflow vertically.
|
||||
- Use the `:hover` and `:focus-within` pseudo-class selectors to change the card's styling if the element is hovered, focused or any of its descendants are focused.
|
||||
- Set `transition: 0.3s ease all` to create a transition effect on hover/focus.
|
||||
|
||||
|
||||
```html
|
||||
<div class="card">
|
||||
<img src="https://picsum.photos/id/404/367/267"/>
|
||||
<h3>Lorem ipsum</h3>
|
||||
<div class="focus-content">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.<br/> <a href="#">Link to source</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.card {
|
||||
width: 300px;
|
||||
height: 280px;
|
||||
padding: 0;
|
||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.1);
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card * {
|
||||
transition: 0.3s ease all;
|
||||
}
|
||||
|
||||
.card img {
|
||||
margin: 0;
|
||||
width: 300px;
|
||||
height: 224px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
margin: 0;
|
||||
padding: 12px 12px 48px;
|
||||
line-height: 32px;
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.card .focus-content {
|
||||
display: block;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.card p {
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.card:hover img, .card:focus-within img {
|
||||
margin-top: -80px;
|
||||
}
|
||||
|
||||
.card:hover h3, .card:focus-within h3 {
|
||||
padding: 8px 12px 0;
|
||||
}
|
||||
```
|
||||
53
css/snippets/hover-perspective.md
Normal file
53
css/snippets/hover-perspective.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Perspective transform on hover
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
author: chalarangelo
|
||||
cover: tropical-bike
|
||||
dateModified: 2021-05-17T13:58:04+03:00
|
||||
---
|
||||
|
||||
Applies a perspective transform with a hover animation to an element.
|
||||
|
||||
- Use `transform` with the `perspective()` and `rotateY()` functions to create a perspective for the element.
|
||||
- Use a `transition` to update the `transform` attribute's value on hover.
|
||||
- Change the `rotateY()` value to negative to mirror the perspective effect from left to right.
|
||||
|
||||
```html
|
||||
<div class="card-container">
|
||||
<div class="image-card perspective-left"></div>
|
||||
<div class="image-card perspective-right"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.image-card {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
margin: 1rem;
|
||||
width: 240px;
|
||||
height: 320px;
|
||||
padding: 8px;
|
||||
border-radius: 1rem;
|
||||
background: url("https://picsum.photos/id/1049/240/320");
|
||||
box-shadow: rgba(0, 0, 0, 0.25) 0px 25px 50px -12px;
|
||||
}
|
||||
|
||||
.perspective-left {
|
||||
transform: perspective(1500px) rotateY(15deg);
|
||||
transition: transform 1s ease 0s;
|
||||
}
|
||||
|
||||
.perspective-left:hover {
|
||||
transform: perspective(3000px) rotateY(5deg);
|
||||
}
|
||||
|
||||
.perspective-right {
|
||||
transform: perspective(1500px) rotateY(-15deg);
|
||||
transition: transform 1s ease 0s;
|
||||
}
|
||||
|
||||
.perspective-right:hover {
|
||||
transform: perspective(3000px) rotateY(-5deg);
|
||||
}
|
||||
```
|
||||
38
css/snippets/hover-shadow-box-animation.md
Normal file
38
css/snippets/hover-shadow-box-animation.md
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
title: Hover shadow box animation
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
unlisted: true
|
||||
cover: dark-cloud
|
||||
dateModified: 2021-01-04T12:30:40+02:00
|
||||
---
|
||||
|
||||
Creates a shadow box around the text when it is hovered.
|
||||
|
||||
- Set `transform: perspective(1px)` to give element a 3D space by affecting the distance between the Z plane and the user and `translate(0)` to reposition the `p` element along z-axis in 3D space.
|
||||
- Use `box-shadow` to make the box transparent.
|
||||
- Use `transition-property` to enable transitions for both `box-shadow` and `transform`.
|
||||
- Use the `:hover`, `:active` and `:focus` pseudo-class selectors to apply a new `box-shadow` and `transform: scale(1.2)` to change the scale of the text.
|
||||
|
||||
```html
|
||||
<p class="hover-shadow-box-animation">Box it!</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.hover-shadow-box-animation {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
transform: perspective(1px) translateZ(0);
|
||||
box-shadow: 0 0 1px transparent;
|
||||
margin: 10px;
|
||||
transition-duration: 0.3s;
|
||||
transition-property: box-shadow, transform;
|
||||
}
|
||||
|
||||
.hover-shadow-box-animation:hover,
|
||||
.hover-shadow-box-animation:focus,
|
||||
.hover-shadow-box-animation:active {
|
||||
box-shadow: 1px 10px 10px -10px rgba(0, 0, 24, 0.5);
|
||||
transform: scale(1.2);
|
||||
}
|
||||
```
|
||||
46
css/snippets/hover-underline-animation.md
Normal file
46
css/snippets/hover-underline-animation.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: Hover underline animation
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: coffee-phone-tray-2
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Creates an animated underline effect when the user hovers over the text.
|
||||
|
||||
- Use `display: inline-block` to make the underline span just the width of the text content.
|
||||
- Use the `::after` pseudo-element with `width: 100%` and `position: absolute` to place it below the content.
|
||||
- Use `transform: scaleX(0)` to initially hide the pseudo-element.
|
||||
- Use the `:hover` pseudo-class selector to apply `transform: scaleX(1)` and display the pseudo-element on hover.
|
||||
- Animate `transform` using `transform-origin: left` and an appropriate `transition`.
|
||||
- Remove the `transform-origin` property to make the transform originate from the center of the element.
|
||||
|
||||
```html
|
||||
<p class="hover-underline-animation">Hover this text to see the effect!</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.hover-underline-animation {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
color: #0087ca;
|
||||
}
|
||||
|
||||
.hover-underline-animation::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
transform: scaleX(0);
|
||||
height: 2px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: #0087ca;
|
||||
transform-origin: bottom right;
|
||||
transition: transform 0.25s ease-out;
|
||||
}
|
||||
|
||||
.hover-underline-animation:hover::after {
|
||||
transform: scaleX(1);
|
||||
transform-origin: bottom left;
|
||||
}
|
||||
```
|
||||
92
css/snippets/image-hover-menu.md
Normal file
92
css/snippets/image-hover-menu.md
Normal file
@ -0,0 +1,92 @@
|
||||
---
|
||||
title: Menu on image hover
|
||||
type: snippet
|
||||
tags: [layout,animation]
|
||||
cover: compass
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Displays a menu overlay when the user hovers over the image.
|
||||
|
||||
- Use a `<figure>` to wrap the `<img>` element and a `<div>` element that will contain the menu links.
|
||||
- Use the `opacity` and `right` attributes to animate the image on hover, creating a sliding effect.
|
||||
- Set the `left` attribute of the `<div>` to the negative of the element's `width`. Reset it to `0` when hovering over the parent element to slide in the menu.
|
||||
- Use `display: flex`, `flex-direction: column` and `justify-content: center` on the `<div>` to vertically center the menu items.
|
||||
|
||||
```html
|
||||
<figure class="hover-menu">
|
||||
<img src="https://picsum.photos/id/1060/800/480.jpg"/>
|
||||
<div>
|
||||
<a href="#">Home</a>
|
||||
<a href="#">Pricing</a>
|
||||
<a href="#">About</a>
|
||||
</div>
|
||||
</figure>
|
||||
```
|
||||
|
||||
```css
|
||||
.hover-menu {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin: 8px;
|
||||
min-width: 340px;
|
||||
max-width: 480px;
|
||||
max-height: 290px;
|
||||
width: 100%;
|
||||
background: #000;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hover-menu * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hover-menu img {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
top: 0;
|
||||
right: 0;
|
||||
opacity: 1;
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.hover-menu div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -120px;
|
||||
width: 120px;
|
||||
height: 100%;
|
||||
padding: 8px 4px;
|
||||
background: #000;
|
||||
transition: 0.3s ease-in-out;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hover-menu div a {
|
||||
display: block;
|
||||
line-height: 2;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
opacity: 0.8;
|
||||
padding: 5px 15px;
|
||||
position: relative;
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.hover-menu div a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.hover-menu:hover img {
|
||||
opacity: 0.5;
|
||||
right: -120px;
|
||||
}
|
||||
|
||||
.hover-menu:hover div {
|
||||
left: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
```
|
||||
38
css/snippets/image-hover-rotate.md
Normal file
38
css/snippets/image-hover-rotate.md
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
title: Image rotate on hover
|
||||
type: snippet
|
||||
tags: [animation,visual]
|
||||
cover: succulent-1
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Creates a rotate effect for the image on hover.
|
||||
|
||||
- Use the `scale()`, `rotate()` and `transition` properties when hovering over the parent element (a `<figure>`) to animate the image.
|
||||
- Use `overflow: hidden` on the parent element to hide the excess from the image transformation.
|
||||
|
||||
```html
|
||||
<figure class="hover-rotate">
|
||||
<img src="https://picsum.photos/id/669/600/800.jpg"/>
|
||||
</figure>
|
||||
```
|
||||
|
||||
```css
|
||||
.hover-rotate {
|
||||
overflow: hidden;
|
||||
margin: 8px;
|
||||
min-width: 240px;
|
||||
max-width: 320px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hover-rotate img {
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.hover-rotate:hover img {
|
||||
transform: scale(1.3) rotate(5deg);
|
||||
}
|
||||
```
|
||||
107
css/snippets/image-mosaic.md
Normal file
107
css/snippets/image-mosaic.md
Normal file
@ -0,0 +1,107 @@
|
||||
---
|
||||
title: Responsive image mosaic
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
author: chalarangelo
|
||||
cover: beach-riders
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Creates a responsive image mosaic.
|
||||
|
||||
- Use `display: grid` to create an appropriate responsive grid layout.
|
||||
- Use `grid-row: span 2 / auto` and `grid-column: span 2 / auto` to create items that span two rows or two columns respectively.
|
||||
- Wrap the previous styles into a media query to avoid applying on small screen sizes.
|
||||
|
||||
```html
|
||||
<div class="image-mosaic">
|
||||
<div
|
||||
class="card card-tall card-wide"
|
||||
style="background-image: url('https://picsum.photos/id/564/1200/800')"
|
||||
></div>
|
||||
<div
|
||||
class="card card-tall"
|
||||
style="background-image: url('https://picsum.photos/id/566/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
style="background-image: url('https://picsum.photos/id/575/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
style="background-image: url('https://picsum.photos/id/626/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
style="background-image: url('https://picsum.photos/id/667/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
style="background-image: url('https://picsum.photos/id/678/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card card-wide"
|
||||
style="background-image: url('https://picsum.photos/id/695/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
style="background-image: url('https://picsum.photos/id/683/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
style="background-image: url('https://picsum.photos/id/693/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
style="background-image: url('https://picsum.photos/id/715/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
style="background-image: url('https://picsum.photos/id/610/800/530')"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
style="background-image: url('https://picsum.photos/id/599/800/530')"
|
||||
></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.image-mosaic {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
grid-auto-rows: 240px;
|
||||
}
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #353535;
|
||||
font-size: 3rem;
|
||||
color: #fff;
|
||||
box-shadow: rgba(3, 8, 20, 0.1) 0px 0.15rem 0.5rem, rgba(2, 8, 20, 0.1) 0px 0.075rem 0.175rem;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
transition: all 500ms;
|
||||
overflow: hidden;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
.card-tall {
|
||||
grid-row: span 2 / auto;
|
||||
}
|
||||
|
||||
.card-wide {
|
||||
grid-column: span 2 / auto;
|
||||
}
|
||||
}
|
||||
```
|
||||
101
css/snippets/image-overlay-hover.md
Normal file
101
css/snippets/image-overlay-hover.md
Normal file
@ -0,0 +1,101 @@
|
||||
---
|
||||
title: Image overlay on hover
|
||||
type: snippet
|
||||
tags: [visual,animation]
|
||||
cover: architectural
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Displays an image overlay effect on hover.
|
||||
|
||||
- Use the `::before` and `::after` pseudo-elements for the top and bottom bars of the overlay respectively. Set their `opacity`, `transform` and `transition` to produce the desired effect.
|
||||
- Use the `<figcaption>` for the text of the overlay. Set `display: flex`, `flex-direction: column` and `justify-content: center` to center the text into the image.
|
||||
- Use the `:hover` pseudo-selector to update the `opacity` and `transform` of all the elements and display the overlay.
|
||||
|
||||
```html
|
||||
<figure class="hover-img">
|
||||
<img src="https://picsum.photos/id/200/440/320.jpg"/>
|
||||
<figcaption>
|
||||
<h3>Lorem <br/>Ipsum</h3>
|
||||
</figcaption>
|
||||
</figure>
|
||||
```
|
||||
|
||||
```css
|
||||
.hover-img {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
margin: 8px;
|
||||
max-width: 320px;
|
||||
min-width: 240px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hover-img * {
|
||||
box-sizing: border-box;
|
||||
transition: all 0.45s ease;
|
||||
}
|
||||
|
||||
.hover-img::before,
|
||||
.hover-img::after {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-top: 32px solid rgba(0, 0, 0, 0.5);
|
||||
border-bottom: 32px solid rgba(0, 0, 0, 0.5);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
content: '';
|
||||
transition: all 0.3s ease;
|
||||
z-index: 1;
|
||||
opacity: 0;
|
||||
transform: scaleY(2);
|
||||
}
|
||||
|
||||
.hover-img img {
|
||||
vertical-align: top;
|
||||
max-width: 100%;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.hover-img figcaption {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
align-items: center;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
line-height: 1.1em;
|
||||
opacity: 0;
|
||||
z-index: 2;
|
||||
transition-delay: 0.1s;
|
||||
font-size: 24px;
|
||||
font-family: sans-serif;
|
||||
font-weight: 400;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.hover-img:hover::before,
|
||||
.hover-img:hover::after {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hover-img:hover > img {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.hover-img:hover figcaption {
|
||||
opacity: 1;
|
||||
}
|
||||
```
|
||||
56
css/snippets/image-text-overlay.md
Normal file
56
css/snippets/image-text-overlay.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: Image with text overlay
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: icebreaker
|
||||
dateModified: 2023-01-29T05:00:00-04:00
|
||||
---
|
||||
|
||||
Displays an image with a text overlay.
|
||||
|
||||
- Use the `<figure>` and `<figcaption>` elements to display the image and the text overlay respectively.
|
||||
- Use a `linear-gradient` to create the overlay effect over the image.
|
||||
|
||||
```html
|
||||
<figure class="text-overlay-image">
|
||||
<img src="https://picsum.photos/id/971/400/400.jpg" />
|
||||
<figcaption>
|
||||
<h3>Business <br/>Pricing</h3>
|
||||
</figcaption>
|
||||
</figure>
|
||||
```
|
||||
|
||||
```css
|
||||
.text-overlay-image {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
margin: 8px;
|
||||
max-width: 400px;
|
||||
max-height: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text-overlay-image figcaption {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
background: linear-gradient(0deg, #00000088 30%, #ffffff44 100%);
|
||||
color: #fff;
|
||||
padding: 16px;
|
||||
font-family: sans-serif;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.text-overlay-image figcaption h3 {
|
||||
margin: 0;
|
||||
}
|
||||
```
|
||||
53
css/snippets/input-with-prefix.md
Normal file
53
css/snippets/input-with-prefix.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Input with prefix
|
||||
type: snippet
|
||||
tags: [interactivity,visual]
|
||||
cover: flower-portrait-4
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates an input with a visual, non-editable prefix.
|
||||
|
||||
- Use `display: flex` to create a container element.
|
||||
- Remove the border and outline from the `<input>` field. Apply them to the parent element instead to make it look like an input box.
|
||||
- Use the `:focus-within` pseudo-class selector to style the parent element accordingly, when the user interacts with the `<input>` field.
|
||||
|
||||
```html
|
||||
<div class="input-box">
|
||||
<span class="prefix">+30</span>
|
||||
<input type="tel" placeholder="210 123 4567"/>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.input-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 300px;
|
||||
background: #fff;
|
||||
border: 1px solid #a0a0a0;
|
||||
border-radius: 4px;
|
||||
padding-left: 0.5rem;
|
||||
overflow: hidden;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.input-box .prefix {
|
||||
font-weight: 300;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.input-box input {
|
||||
flex-grow: 1;
|
||||
font-size: 14px;
|
||||
background: #fff;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.input-box:focus-within {
|
||||
border-color: #777;
|
||||
}
|
||||
```
|
||||
39
css/snippets/isometric-card.md
Normal file
39
css/snippets/isometric-card.md
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Isometric card
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: guitar-living-room
|
||||
dateModified: 2021-05-17T14:04:52+03:00
|
||||
---
|
||||
|
||||
Creates an isometric card.
|
||||
|
||||
- Use `transform` with `rotateX()` and `rotateY()` as well as a `box-shadow` to create an isometric card.
|
||||
- Use `transition` to animate the card, creating a lift effect when the user hovers over it.
|
||||
|
||||
```html
|
||||
<div class="isometric-card"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.isometric-card {
|
||||
margin: 0 auto;
|
||||
transform: rotateX(51deg) rotateZ(43deg);
|
||||
transform-style: preserve-3d;
|
||||
background-color: #fcfcfc;
|
||||
will-change: transform;
|
||||
width: 240px;
|
||||
height: 320px;
|
||||
border-radius: 2rem;
|
||||
box-shadow: 1px 1px 0 1px #f9f9fb, -1px 0 28px 0 rgba(34, 33, 81, 0.01),
|
||||
28px 28px 28px 0 rgba(34, 33, 81, 0.25);
|
||||
transition: 0.4s ease-in-out transform, 0.3s ease-in-out box-shadow;
|
||||
}
|
||||
|
||||
.isometric-card:hover {
|
||||
transform: translate3d(0px, -16px, 0px) rotateX(51deg) rotateZ(43deg);
|
||||
box-shadow: 1px 1px 0 1px #f9f9fb, -1px 0 28px 0 rgba(34, 33, 81, 0.01),
|
||||
54px 54px 28px -10px rgba(34, 33, 81, 0.15);
|
||||
}
|
||||
```
|
||||
29
css/snippets/line-clamp.md
Normal file
29
css/snippets/line-clamp.md
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Trim multiline text
|
||||
type: snippet
|
||||
tags: [layout,visual]
|
||||
author: chalarangelo
|
||||
cover: pink-flower-tree
|
||||
dateModified: 2021-05-16T20:19:13+03:00
|
||||
---
|
||||
|
||||
Limit multiline text to a given number of lines.
|
||||
|
||||
- Use `-webkit-line-clamp` to set the maximum number of lines to be displayed.
|
||||
- Set `display` to `-webkit-box` and `-webkit-box-orient` to `vertical`, as they are required for `-webkit-line-clamp` to be applied.
|
||||
- Apply `overflow: hidden` to hide any overflow after the text is trimmed.
|
||||
|
||||
```html
|
||||
<p class="excerpt">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod enim eget ultricies sollicitudin. Nunc aliquam arcu arcu, non suscipit metus luctus id. Aliquam sodales turpis ipsum, in vehicula dui tempor sit amet. Nullam quis urna erat. Pellentesque mattis dolor purus. Aliquam nisl urna, tempor a euismod a, placerat in mauris. Phasellus neque quam, dapibus quis nunc at, feugiat suscipit tortor. Duis vel posuere dolor. Phasellus risus erat, lobortis et mi vel, viverra faucibus lectus. Etiam ut posuere sapien. Nulla ultrices dui turpis, interdum consectetur urna tempus at.
|
||||
</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.excerpt {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
```
|
||||
96
css/snippets/masonry-layout.md
Normal file
96
css/snippets/masonry-layout.md
Normal file
@ -0,0 +1,96 @@
|
||||
---
|
||||
title: Masonry Layout
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: interior-2
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates a masonry-style layout that is especially useful when working with images.
|
||||
|
||||
- Create a masonry-style layout that consists of "bricks" that fall into each other with either a fixed `width` (vertical layout) or a fixed `height` (horizontal layout), forming a perfect fit. Especially useful when working with images.
|
||||
- Define `.masonry-container` This is the container for the masonry layout and `.masonry-columns`, an inner container in which `.masonry-brick` elements will be placed.
|
||||
- Apply `display: block` to `.masonry-brick` elements to allow the layout to flow properly.
|
||||
- Use the `:first-child` pseudo-element selector to apply a different `margin` for the first element to account for its positioning.
|
||||
- Use CSS variables and media queries for greater flexibility and responsiveness.
|
||||
|
||||
```html
|
||||
<div class="masonry-container">
|
||||
<div class="masonry-columns">
|
||||
<img
|
||||
class="masonry-brick"
|
||||
src="https://picsum.photos/id/1016/384/256"
|
||||
alt="An image"
|
||||
/>
|
||||
<img
|
||||
class="masonry-brick"
|
||||
src="https://picsum.photos/id/1025/495/330"
|
||||
alt="Another image"
|
||||
/>
|
||||
<img
|
||||
class="masonry-brick"
|
||||
src="https://picsum.photos/id/1024/192/128"
|
||||
alt="Another image"
|
||||
/>
|
||||
<img
|
||||
class="masonry-brick"
|
||||
src="https://picsum.photos/id/1028/518/345"
|
||||
alt="One more image"
|
||||
/>
|
||||
<img
|
||||
class="masonry-brick"
|
||||
src="https://picsum.photos/id/1035/585/390"
|
||||
alt="And another one"
|
||||
/>
|
||||
<img
|
||||
class="masonry-brick"
|
||||
src="https://picsum.photos/id/1074/384/216"
|
||||
alt="Last one"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
/* Container */
|
||||
.masonry-container {
|
||||
--column-count-small: 1;
|
||||
--column-count-medium: 2;
|
||||
--column-count-large: 3;
|
||||
--column-gap: 0.125rem;
|
||||
padding: var(--column-gap);
|
||||
}
|
||||
|
||||
/* Columns */
|
||||
.masonry-columns {
|
||||
column-gap: var(--column-gap);
|
||||
column-count: var(--column-count-small);
|
||||
column-width: calc(1 / var(--column-count-small) * 100%);
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 640px) {
|
||||
.masonry-columns {
|
||||
column-count: var(--column-count-medium);
|
||||
column-width: calc(1 / var(--column-count-medium) * 100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 800px) {
|
||||
.masonry-columns {
|
||||
column-count: var(--column-count-large);
|
||||
column-width: calc(1 / var(--column-count-large) * 100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bricks */
|
||||
.masonry-brick {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin: var(--column-gap) 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.masonry-brick:first-child {
|
||||
margin: 0 0 var(--column-gap);
|
||||
}
|
||||
```
|
||||
67
css/snippets/mouse-cursor-gradient-tracking.md
Normal file
67
css/snippets/mouse-cursor-gradient-tracking.md
Normal file
@ -0,0 +1,67 @@
|
||||
---
|
||||
title: Mouse cursor gradient tracking
|
||||
type: snippet
|
||||
tags: [visual,interactivity]
|
||||
cover: tram-car
|
||||
dateModified: 2021-01-07T23:52:15+02:00
|
||||
---
|
||||
|
||||
A hover effect where the gradient follows the mouse cursor.
|
||||
|
||||
- Declare two CSS variables, `--x` and `--y`, used to track the position of the mouse on the button.
|
||||
- Declare a CSS variable, `--size`, used to modify the gradient's dimensions.
|
||||
- Use `background: radial-gradient(circle closest-side, pink, transparent)` to create the gradient at the correct position.
|
||||
- Use `Document.querySelector()` and `EventTarget.addEventListener()` to register a handler for the `'mousemove'` event.
|
||||
- Use `Element.getBoundingClientRect()` and `CSSStyleDeclaration.setProperty()` to update the values of the `--x` and `--y` CSS variables.
|
||||
|
||||
```html
|
||||
<button class="mouse-cursor-gradient-tracking">
|
||||
<span>Hover me</span>
|
||||
</button>
|
||||
```
|
||||
|
||||
```css
|
||||
.mouse-cursor-gradient-tracking {
|
||||
position: relative;
|
||||
background: #7983ff;
|
||||
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 0.2s ease, height 0.2s ease;
|
||||
}
|
||||
|
||||
.mouse-cursor-gradient-tracking:hover::before {
|
||||
--size: 200px;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
let btn = document.querySelector('.mouse-cursor-gradient-tracking');
|
||||
btn.addEventListener('mousemove', e => {
|
||||
let rect = e.target.getBoundingClientRect();
|
||||
let x = e.clientX - rect.left;
|
||||
let y = e.clientY - rect.top;
|
||||
btn.style.setProperty('--x', x + 'px');
|
||||
btn.style.setProperty('--y', y + 'px');
|
||||
});
|
||||
```
|
||||
64
css/snippets/navigation-list-item-hover-and-focus-effect.md
Normal file
64
css/snippets/navigation-list-item-hover-and-focus-effect.md
Normal file
@ -0,0 +1,64 @@
|
||||
---
|
||||
title: Navigation list item hover and focus effect
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: cloudy-rock-formation
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Creates a custom hover and focus effect for navigation items, using CSS transformations.
|
||||
|
||||
- Use the `::before` pseudo-element at the list item anchor to create a hover effect. Hide it using `transform: scale(0)`.
|
||||
- Use the `:hover` and `:focus` pseudo-class selectors to transition the pseudo-element to `transform: scale(1)` and show its colored background.
|
||||
- Prevent the pseudo-element from covering the anchor element by using `z-index`.
|
||||
|
||||
```html
|
||||
<nav class="hover-nav">
|
||||
<ul>
|
||||
<li><a href="#">Home</a></li>
|
||||
<li><a href="#">About</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
```
|
||||
|
||||
```css
|
||||
.hover-nav ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hover-nav li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.hover-nav li a {
|
||||
position: relative;
|
||||
display: block;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 8px 12px;
|
||||
text-decoration: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
li a::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: #2683f6;
|
||||
z-index: -1;
|
||||
transform: scale(0);
|
||||
transition: transform 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
li a:hover::before,
|
||||
li a:focus::before {
|
||||
transform: scale(1);
|
||||
}
|
||||
```
|
||||
34
css/snippets/offscreen.md
Normal file
34
css/snippets/offscreen.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
title: Offscreen
|
||||
type: snippet
|
||||
tags: [layout,visual]
|
||||
cover: succulent-2
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Hides an element completely (visually and positionally) in the DOM while still allowing it to be accessible.
|
||||
|
||||
- Remove all borders and padding and hide the element's overflow.
|
||||
- Use `clip` to define that no part of the element is shown.
|
||||
- Make the `height` and `width` of the element `1px` and negate them using `margin: -1px`.
|
||||
- Use `position: absolute` so that the element does not take up space in the DOM.
|
||||
- **Note:** This technique provides an accessible and layout-friendly alternative to `display: none` (not readable by screen readers) and `visibility: hidden` (takes up physical space in the DOM).
|
||||
|
||||
```html
|
||||
<a class="button" href="https://google.com">
|
||||
Learn More <span class="offscreen"> about pants</span>
|
||||
</a>
|
||||
```
|
||||
|
||||
```css
|
||||
.offscreen {
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
```
|
||||
53
css/snippets/overflow-scroll-gradient.md
Normal file
53
css/snippets/overflow-scroll-gradient.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Overflow scroll gradient
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: memories-of-pineapple-1
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Adds a fading gradient to an overflowing element to better indicate there is more content to be scrolled.
|
||||
|
||||
- Use the `::after` pseudo-element to create a `linear-gradient()` that fades from `transparent` to `white` (top to bottom).
|
||||
- Use `position: absolute`, `width` and `height` to place and size the pseudo-element in its parent.
|
||||
- Use `pointer-events: none` to exclude the pseudo-element from mouse events, allowing text behind it to still be selectable/interactive.
|
||||
|
||||
```html
|
||||
<div class="overflow-scroll-gradient">
|
||||
<div class="overflow-scroll-gradient-scroller">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. <br />
|
||||
Iure id exercitationem nulla qui repellat laborum vitae, <br />
|
||||
molestias tempora velit natus. Quas, assumenda nisi. <br />
|
||||
Quisquam enim qui iure, consequatur velit sit? <br />
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.<br />
|
||||
Iure id exercitationem nulla qui repellat laborum vitae, <br />
|
||||
molestias tempora velit natus. Quas, assumenda nisi. <br />
|
||||
Quisquam enim qui iure, consequatur velit sit?
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.overflow-scroll-gradient {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.overflow-scroll-gradient::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 250px;
|
||||
height: 25px;
|
||||
background: linear-gradient(transparent, white);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.overflow-scroll-gradient-scroller {
|
||||
overflow-y: scroll;
|
||||
background: white;
|
||||
width: 240px;
|
||||
height: 200px;
|
||||
padding: 15px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
```
|
||||
31
css/snippets/polka-dot-pattern.md
Normal file
31
css/snippets/polka-dot-pattern.md
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
title: Polka dot background pattern
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: bag-waiting
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates a polka dot background pattern.
|
||||
|
||||
- Use `background-color` to set a black background.
|
||||
- Use `background-image` with two `radial-gradient()` values to create two dots.
|
||||
- Use `background-size` to specify the pattern's size. Use `background-position` to appropriately place the two gradients.
|
||||
- **Note:** The fixed `height` and `width` of the element is for demonstration purposes only.
|
||||
|
||||
```html
|
||||
<div class="polka-dot"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.polka-dot {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
background-color: #000;
|
||||
background-image: radial-gradient(#fff 10%, transparent 11%),
|
||||
radial-gradient(#fff 10%, transparent 11%);
|
||||
background-size: 60px 60px;
|
||||
background-position: 0 0, 30px 30px;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
```
|
||||
43
css/snippets/popout-menu.md
Normal file
43
css/snippets/popout-menu.md
Normal file
@ -0,0 +1,43 @@
|
||||
---
|
||||
title: Popout menu
|
||||
type: snippet
|
||||
tags: [interactivity]
|
||||
cover: city-view
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Reveals an interactive popout menu on hover/focus.
|
||||
|
||||
- Use `left: 100%` to move the popout menu to the right of the parent.
|
||||
- Use `visibility: hidden` to hide the popout menu initially, allowing for transitions to be applied (unlike `display: none`).
|
||||
- Use the `:hover`, `:focus` and `:focus-within` pseudo-class selectors to apply `visibility: visible` to the popout menu, displaying it when the parent element is hovered/focused.
|
||||
|
||||
```html
|
||||
<div class="reference" tabindex="0">
|
||||
<div class="popout-menu">Popout menu</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.reference {
|
||||
position: relative;
|
||||
background: tomato;
|
||||
width: 100px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.popout-menu {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
left: 100%;
|
||||
background: #9C27B0;
|
||||
color: white;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.reference:hover > .popout-menu,
|
||||
.reference:focus > .popout-menu,
|
||||
.reference:focus-within > .popout-menu {
|
||||
visibility: visible;
|
||||
}
|
||||
```
|
||||
44
css/snippets/pretty-text-underline.md
Normal file
44
css/snippets/pretty-text-underline.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
title: Pretty text underline
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: flower-portrait-6
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Provides a nicer alternative to `text-decoration: underline` where descenders do not clip the underline.
|
||||
|
||||
- Use `text-shadow` to apply 4 values with offsets covering a 4x4 `px` area. This ensures the underline has a thick shadow that covers the line where descenders clip it. For best results, use a color that matches the `background` and adjust the `px` values for larger fonts.
|
||||
- Use `background-image` with `linear-gradient()` and `currentColor` to create a gradient that will act as the actual underline.
|
||||
- Set `background-position`, `background-repeat` and `background-size` to place the gradient in the correct position.
|
||||
- Use the `::selection` pseudo-class selector to ensure the text shadow does not interfere with text selection.
|
||||
- **Note:** This is natively implemented as `text-decoration-skip-ink: auto` but it has less control over the underline.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<p class="pretty-text-underline">Pretty text underline without clipping descenders.</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
background: #f5f6f9;
|
||||
color: #333;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.pretty-text-underline {
|
||||
display: inline;
|
||||
text-shadow: 1px 1px #f5f6f9, -1px 1px #f5f6f9, -1px -1px #f5f6f9,
|
||||
1px -1px #f5f6f9;
|
||||
background-image: linear-gradient(90deg, currentColor 100%, transparent 100%);
|
||||
background-position: bottom;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 1px;
|
||||
}
|
||||
|
||||
.pretty-text-underline::selection {
|
||||
background-color: rgba(0, 150, 255, 0.3);
|
||||
text-shadow: none;
|
||||
}
|
||||
```
|
||||
57
css/snippets/pulse-loader.md
Normal file
57
css/snippets/pulse-loader.md
Normal file
@ -0,0 +1,57 @@
|
||||
---
|
||||
title: Pulse loader
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: digital-nomad-8
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates a pulse effect loader animation using the `animation-delay` property.
|
||||
|
||||
- Use `@keyframes` to define an animation at two points in the cycle. At the start (`0%`), the two `<div>` elements have no `width` or `height` and are positioned at the center. At the end (`100%`), both `<div>` elements have increased `width` and `height`, but their `position` is reset to `0`.
|
||||
- Use `opacity` to transition from `1` to `0` when animating to give the `<div>` elements a disappearing effect as they expand.
|
||||
- Set a predefined `width` and `height` for the parent container, `.ripple-loader` and use `position: relative` to position its children.
|
||||
- Use `animation-delay` on the second `<div>` element, so that each element starts its animation at a different time.
|
||||
|
||||
```html
|
||||
<div class="ripple-loader">
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.ripple-loader {
|
||||
position: relative;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.ripple-loader div {
|
||||
position: absolute;
|
||||
border: 4px solid #454ADE;
|
||||
border-radius: 50%;
|
||||
animation: ripple-loader 1s ease-out infinite;
|
||||
}
|
||||
|
||||
.ripple-loader div:nth-child(2) {
|
||||
animation-delay: -0.5s;
|
||||
}
|
||||
|
||||
@keyframes ripple-loader {
|
||||
0% {
|
||||
top: 32px;
|
||||
left: 32px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
29
css/snippets/reset-all-styles.md
Normal file
29
css/snippets/reset-all-styles.md
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Reset all styles
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: rocky-beach-2
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Resets all styles to default values using only one property.
|
||||
|
||||
- Use the `all` property to reset all styles (inherited or not) to their default values.
|
||||
- **Note:** This will not affect `direction` and `unicode-bidi` properties.
|
||||
|
||||
```html
|
||||
<div class="reset-all-styles">
|
||||
<h5>Title</h5>
|
||||
<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>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.reset-all-styles {
|
||||
all: initial;
|
||||
}
|
||||
```
|
||||
46
css/snippets/responsive-layout-sidebar.md
Normal file
46
css/snippets/responsive-layout-sidebar.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: Responsive layout with sidebar
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
author: chalarangelo
|
||||
cover: red-petals
|
||||
dateModified: 2020-09-16T18:54:56+03:00
|
||||
---
|
||||
|
||||
Creates a responsive layout with a content area and a sidebar.
|
||||
|
||||
- Use `display: grid` on the parent container, to create a grid layout.
|
||||
- Use `minmax()` for the second column (sidebar) to allow it to take up between `150px` and `20%`.
|
||||
- Use `1fr` for the first column (main content) to take up the rest of the remaining space.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<main>
|
||||
This element is 1fr large.
|
||||
</main>
|
||||
<aside>
|
||||
Min: 150px / Max: 20%
|
||||
</aside>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr minmax(150px, 20%);
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
main, aside {
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
main {
|
||||
background: #d4f2c4;
|
||||
}
|
||||
|
||||
aside {
|
||||
background: #81cfd9;
|
||||
}
|
||||
```
|
||||
69
css/snippets/rotating-card.md
Normal file
69
css/snippets/rotating-card.md
Normal file
@ -0,0 +1,69 @@
|
||||
---
|
||||
title: Rotating Card
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: digital-nomad-11
|
||||
dateModified: 2021-03-30T15:24:01+03:00
|
||||
---
|
||||
|
||||
Creates a two sided card which rotates on hover.
|
||||
|
||||
- Set the `backface-visibility` of the cards to none.
|
||||
- Initially, set `rotateY()` for the back side of the card to `-180deg` and the front side to `0deg`.
|
||||
- Upon hover, set `rotateY()` for the front side to `180deg` and backside to `0deg`.
|
||||
- Set the appropriate `perspective` value to create the rotate effect.
|
||||
|
||||
```html
|
||||
<div class="card">
|
||||
<div class="card-side front">
|
||||
<div>Front Side</div>
|
||||
</div>
|
||||
<div class="card-side back">
|
||||
<div>Back Side</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.card {
|
||||
perspective: 150rem;
|
||||
position: relative;
|
||||
height: 40rem;
|
||||
max-width: 400px;
|
||||
margin: 2rem;
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.card-side {
|
||||
height: 35rem;
|
||||
border-radius: 15px;
|
||||
transition: all 0.8s ease;
|
||||
backface-visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 80%;
|
||||
padding: 2rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.card-side.back {
|
||||
transform: rotateY(-180deg);
|
||||
background-color: #4158D0;
|
||||
background-image: linear-gradient(43deg, #4158D0 0%,#C850C0 46%, #FFCC70 100%);
|
||||
}
|
||||
|
||||
.card-side.front {
|
||||
background-color: #0093E9;
|
||||
background-image: linear-gradient(160deg, #0093E9 0%, #80D0C7 100%);
|
||||
}
|
||||
|
||||
.card:hover .card-side.front {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.card:hover .card-side.back {
|
||||
transform: rotateY(0deg);
|
||||
}
|
||||
```
|
||||
44
css/snippets/scroll-progress-bar.md
Normal file
44
css/snippets/scroll-progress-bar.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
title: Scroll progress bar
|
||||
type: snippet
|
||||
tags: [animation,visual]
|
||||
author: chalarangelo
|
||||
cover: coworking-space
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates a progress bar indicating the scroll percentage of the page.
|
||||
|
||||
- Use `position: fixed` and a large `z-index` value to place the element at the top of the page and above any content.
|
||||
- Use `EventTarget.addEventListener()` and `Element.scrollTop` to determine the scroll percentage of the document and apply it to the `width` of the element.
|
||||
|
||||
```html
|
||||
<div id="scroll-progress"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
body {
|
||||
min-height: 200vh;
|
||||
}
|
||||
|
||||
#scroll-progress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 0%;
|
||||
height: 4px;
|
||||
background: #7983ff;
|
||||
z-index: 10000;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const scrollProgress = document.getElementById('scroll-progress');
|
||||
const height =
|
||||
document.documentElement.scrollHeight - document.documentElement.clientHeight;
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
const scrollTop =
|
||||
document.body.scrollTop || document.documentElement.scrollTop;
|
||||
scrollProgress.style.width = `${(scrollTop / height) * 100}%`;
|
||||
});
|
||||
```
|
||||
39
css/snippets/shake-invalid-input.md
Normal file
39
css/snippets/shake-invalid-input.md
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Shake on invalid input
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: perfect-timing
|
||||
dateModified: 2022-07-31T18:30:11+03:00
|
||||
---
|
||||
|
||||
Creates a shake animation on invalid input.
|
||||
|
||||
- Use the `pattern` attribute to define the regular expression which the input's value must match.
|
||||
- Use `@keyframes` to define a shake animation, using the `margin-left` property.
|
||||
- Use the `:invalid` pseudo-class to apply an `animation` to make the element shake.
|
||||
|
||||
```html
|
||||
<input type="text" placeholder="Letters only" pattern="[A-Za-z]*" />
|
||||
```
|
||||
|
||||
```css
|
||||
@keyframes shake {
|
||||
0% {
|
||||
margin-left: 0rem;
|
||||
}
|
||||
25% {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
75% {
|
||||
margin-left: -0.5rem;
|
||||
}
|
||||
100% {
|
||||
margin-left: 0rem;
|
||||
}
|
||||
}
|
||||
|
||||
input:invalid {
|
||||
animation: shake 0.2s ease-in-out 0s 2;
|
||||
box-shadow: 0 0 0.6rem #ff0000;
|
||||
}
|
||||
```
|
||||
35
css/snippets/shape-separator.md
Normal file
35
css/snippets/shape-separator.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Shape separator
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
unlisted: true
|
||||
cover: shapes
|
||||
dateModified: 2021-01-04T12:30:40+02:00
|
||||
---
|
||||
|
||||
Uses an SVG shape to create a separator between two different blocks.
|
||||
|
||||
- Use the `::after` pseudo-element to create the separator element.
|
||||
- Use `background-image` to add the SVG (a 24x12 triangle) shape via a data URI. The background image will repeat by default, covering the whole area of the pseudo-element.
|
||||
- Use the `background` of the parent element to set the desired color for the separator.
|
||||
|
||||
```html
|
||||
<div class="shape-separator"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.shape-separator {
|
||||
position: relative;
|
||||
height: 48px;
|
||||
background: #9C27B0;
|
||||
}
|
||||
|
||||
.shape-separator::after {
|
||||
content: '';
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 12'%3E%3Cpath d='m12 0l12 12h-24z' fill='transparent'/%3E%3C/svg%3E");
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 12px;
|
||||
bottom: 0;
|
||||
}
|
||||
```
|
||||
78
css/snippets/shifting-card.md
Normal file
78
css/snippets/shifting-card.md
Normal file
@ -0,0 +1,78 @@
|
||||
---
|
||||
title: Shifting Card
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
author: chalarangelo
|
||||
cover: clouds-n-mountains
|
||||
dateModified: 2022-12-14T05:00:00-04:00
|
||||
---
|
||||
|
||||
Creates a card that shifts on hover.
|
||||
|
||||
- Set the appropriate `perspective` on the `.container` element to allow for the shifting effect.
|
||||
- Add a `transition` for the `transform` property of the `.card` element.
|
||||
- Use `Document.querySelector()` to select the `.card` element and add event listeners for the `mousemove` and `mouseout` events.
|
||||
- Use `Element.getBoundingClientRect()` to get the `x`, `y`, `width`, and `height` of the `.card` element.
|
||||
- Calculate the relative distance as a value between `-1` and `1` for the `x` and `y` axes and apply it through the `transform` property.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<div class="shifting-card">
|
||||
<div class="content">
|
||||
<h3>Card</h3>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Corrupti repellat, consequuntur doloribus voluptate esse iure?</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
display: flex;
|
||||
padding: 24px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #f3f1fe;
|
||||
}
|
||||
|
||||
.shifting-card {
|
||||
width: 350px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
margin: 0.5rem;
|
||||
transition: transform 0.2s ease-out;
|
||||
box-shadow: 0 0 5px -2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.shifting-card .content {
|
||||
text-align: center;
|
||||
margin: 2rem;
|
||||
line-height: 1.5;
|
||||
color: #101010;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const card = document.querySelector('.shifting-card');
|
||||
const { x, y, width, height } = card.getBoundingClientRect();
|
||||
const cx = x + width / 2;
|
||||
const cy = y + height / 2;
|
||||
|
||||
const handleMove = e => {
|
||||
const { pageX, pageY } = e;
|
||||
const dx = (cx - pageX) / (width / 2);
|
||||
const dy = (cy - pageY) / (height / 2);
|
||||
e.target.style.transform =
|
||||
`rotateX(${10 * dy * -1}deg) rotateY(${10 * dx}deg)`;
|
||||
};
|
||||
|
||||
const handleOut = e => {
|
||||
e.target.style.transform = 'initial';
|
||||
};
|
||||
|
||||
card.addEventListener('mousemove', handleMove);
|
||||
card.addEventListener('mouseout', handleOut);
|
||||
```
|
||||
30
css/snippets/sibling-fade.md
Normal file
30
css/snippets/sibling-fade.md
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
title: Sibling fade
|
||||
type: snippet
|
||||
tags: [interactivity]
|
||||
cover: messy-papers
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Fades out the siblings of a hovered item.
|
||||
|
||||
- Use a `transition` to animate changes to `opacity`.
|
||||
- Use the `:hover` and `:not` pseudo-class selectors to change the `opacity` of all elements except for the one the mouse is over to `0.5`.
|
||||
|
||||
```html
|
||||
<div class="sibling-fade">
|
||||
<span>Item 1</span> <span>Item 2</span> <span>Item 3</span>
|
||||
<span>Item 4</span> <span>Item 5</span> <span>Item 6</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
span {
|
||||
padding: 0 16px;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.sibling-fade:hover span:not(:hover) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
```
|
||||
33
css/snippets/squiggle-link-hover-effect.md
Normal file
33
css/snippets/squiggle-link-hover-effect.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
title: Squiggle link hover effect
|
||||
type: snippet
|
||||
tags: [animation,visual]
|
||||
author: chalarangelo
|
||||
cover: dreamy-flowers
|
||||
dateModified: 2023-01-10T05:00:00-04:00
|
||||
---
|
||||
|
||||
Creates a squiggle effect when hovering over a link.
|
||||
|
||||
- Create a repeating background for the link using a `linear-gradient`.
|
||||
- Create a `:hover` state for the link with a `background-image` of a data URL containing an SVG with a squiggly path and an animation.
|
||||
|
||||
```html
|
||||
<p>The <a class="squiggle" href="#">magnificent octopus</a> swam along gracefully.</p>
|
||||
```
|
||||
|
||||
```css
|
||||
a.squiggle {
|
||||
background: linear-gradient(to bottom, #0087ca 0%, #0087ca 100%);
|
||||
background-position: 0 100%;
|
||||
background-repeat: repeat-x;
|
||||
background-size: 2px 2px;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.squiggle:hover {
|
||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 4'%3E%3Cstyle type='text/css'%3E.squiggle{animation:shift .3s linear infinite;}@keyframes shift {from {transform:translateX(0);}to {transform:translateX(-15px);}}%3C/style%3E%3Cpath fill='none' stroke='%230087ca' stroke-width='2' class='squiggle' d='M0,3.5 c 5,0,5,-3,10,-3 s 5,3,10,3 c 5,0,5,-3,10,-3 s 5,3,10,3'/%3E%3C/svg%3E");
|
||||
background-size: auto 4px;
|
||||
}
|
||||
```
|
||||
67
css/snippets/staggered-animation.md
Normal file
67
css/snippets/staggered-animation.md
Normal file
@ -0,0 +1,67 @@
|
||||
---
|
||||
title: Staggered animation
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: aerial-view-port
|
||||
dateModified: 2021-10-11T18:44:51+03:00
|
||||
---
|
||||
|
||||
Creates a staggered animation for the elements of a list.
|
||||
|
||||
- Set `opacity: 0` and `transform: translateX(100%)` to make list elements transparent and move them all the way to the right.
|
||||
- Specify the same `transition` properties for list elements, except `transition-delay`.
|
||||
- Use inline styles to specify a value for `--i` for each list element. This will in turn be used for `transition-delay` to create the stagger effect.
|
||||
- Use the `:checked` pseudo-class selector for the checkbox to style list elements. Set `opacity` to `1` and `transform` to `translateX(0)` to make them appear and slide into view.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<input type="checkbox" name="menu" id="menu" class="menu-toggler">
|
||||
<label for="menu" class="menu-toggler-label">Menu</label>
|
||||
<ul class="stagger-menu">
|
||||
<li style="--i: 0">Home</li>
|
||||
<li style="--i: 1">Pricing</li>
|
||||
<li style="--i: 2">Account</li>
|
||||
<li style="--i: 3">Support</li>
|
||||
<li style="--i: 4">About</li>
|
||||
</ul>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.menu-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu-toggler-label {
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stagger-menu {
|
||||
list-style-type: none;
|
||||
margin: 16px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.stagger-menu li {
|
||||
margin-bottom: 8px;
|
||||
font-size: 18px;
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
transition-property: opacity, transform;
|
||||
transition-duration: 0.3s;
|
||||
transition-timing-function: cubic-bezier(0.750, -0.015, 0.565, 1.055);
|
||||
}
|
||||
|
||||
.menu-toggler:checked ~ .stagger-menu li {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
transition-delay: calc(0.055s * var(--i));
|
||||
}
|
||||
```
|
||||
84
css/snippets/sticky-list-titles.md
Normal file
84
css/snippets/sticky-list-titles.md
Normal file
@ -0,0 +1,84 @@
|
||||
---
|
||||
title: List with sticky section headings
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: interior-7
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Creates a list with sticky headings for each section.
|
||||
|
||||
- Use `overflow-y: auto` to allow the list container (`<dl>`) to overflow vertically.
|
||||
- Set headings (`<dt>`) `position` to `sticky` and apply `top: 0` to stick to the top of the container.
|
||||
|
||||
```html
|
||||
<div class="container">
|
||||
<dl class="sticky-stack">
|
||||
<dt>A</dt>
|
||||
<dd>Algeria</dd>
|
||||
<dd>Angola</dd>
|
||||
|
||||
<dt>B</dt>
|
||||
<dd>Benin</dd>
|
||||
<dd>Botswana</dd>
|
||||
<dd>Burkina Faso</dd>
|
||||
<dd>Burundi</dd>
|
||||
|
||||
<dt>C</dt>
|
||||
<dd>Cabo Verde</dd>
|
||||
<dd>Cameroon</dd>
|
||||
<dd>Central African Republic</dd>
|
||||
<dd>Chad</dd>
|
||||
<dd>Comoros</dd>
|
||||
<dd>Congo, Democratic Republic of the</dd>
|
||||
<dd>Congo, Republic of the</dd>
|
||||
<dd>Cote d'Ivoire</dd>
|
||||
|
||||
<dt>D</dt>
|
||||
<dd>Djibouti</dd>
|
||||
|
||||
<dt>E</dt>
|
||||
<dd>Egypt</dd>
|
||||
<dd>Equatorial Guinea</dd>
|
||||
<dd>Eritrea</dd>
|
||||
<dd>Eswatini (formerly Swaziland)</dd>
|
||||
<dd>Ethiopia</dd>
|
||||
</dl>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.sticky-stack {
|
||||
background: #37474f;
|
||||
color: #fff;
|
||||
margin: 0;
|
||||
height: 320px;
|
||||
border-radius: 1rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sticky-stack dt {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
font-weight: bold;
|
||||
background: #263238;
|
||||
color: #cfd8dc;
|
||||
padding: 0.25rem 1rem;
|
||||
}
|
||||
|
||||
.sticky-stack dd {
|
||||
margin: 0;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.sticky-stack dd + dt {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
```
|
||||
29
css/snippets/stripes-pattern.md
Normal file
29
css/snippets/stripes-pattern.md
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Stripes background pattern
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: jars-on-shelf
|
||||
dateModified: 2021-01-11T09:51:43+02:00
|
||||
---
|
||||
|
||||
Creates a stripes background pattern.
|
||||
|
||||
- Use `background-color` to set a white background.
|
||||
- Use `background-image` with a `radial-gradient()` value to create a vertical stripe.
|
||||
- Use `background-size` to specify the pattern's size.
|
||||
- **Note:** The fixed `height` and `width` of the element is for demonstration purposes only.
|
||||
|
||||
```html
|
||||
<div class="stripes"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.stripes {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
background-color: #fff;
|
||||
background-image: linear-gradient(90deg, transparent 50%, #000 50%);
|
||||
background-size: 60px 60px;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
```
|
||||
24
css/snippets/stylized-quotation-marks.md
Normal file
24
css/snippets/stylized-quotation-marks.md
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
title: Stylized quotation marks
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: coffee-phone-tray
|
||||
dateModified: 2021-05-16T19:53:02+03:00
|
||||
---
|
||||
|
||||
Customizes the style of inline quotation marks.
|
||||
|
||||
- Use the `quotes` property to customize the characters used for the opening and closing quotes of a `<q>` element.
|
||||
|
||||
```html
|
||||
<p>
|
||||
<q>Do or do not, there is no try.</q> – Yoda
|
||||
</p>
|
||||
```
|
||||
|
||||
```css
|
||||
q {
|
||||
quotes: "“" "”";
|
||||
}
|
||||
```
|
||||
34
css/snippets/system-font-stack.md
Normal file
34
css/snippets/system-font-stack.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
title: System font stack
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: lavender-shelf
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Uses the native font of the operating system to get close to a native app feel.
|
||||
|
||||
- Define a list of fonts using `font-family`.
|
||||
- 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).
|
||||
- `-apple-system` is San Francisco, used on iOS and macOS (not Chrome however).
|
||||
- `BlinkMacSystemFont` is San Francisco, used on macOS Chrome.
|
||||
- `'Segoe UI'` is used on Windows 10.
|
||||
- `Roboto` is used on Android.
|
||||
- `Oxygen-Sans` is used on Linux with KDE.
|
||||
- `Ubuntu` is used on Ubuntu (all variants).
|
||||
- `Cantarell` is used on Linux with GNOME Shell.
|
||||
- `'Helvetica Neue'` and `Helvetica` is used on macOS 10.10 and below.
|
||||
- `Arial` is a font widely supported by all operating systems.
|
||||
- `sans-serif` is the fallback sans serif font if none of the other fonts are supported.
|
||||
|
||||
```html
|
||||
<p class="system-font-stack">This text uses the system font.</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.system-font-stack {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||
Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', Helvetica, Arial,
|
||||
sans-serif;
|
||||
}
|
||||
```
|
||||
36
css/snippets/text-backdrop-overlay.md
Normal file
36
css/snippets/text-backdrop-overlay.md
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
title: Image text overlay
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
author: chalarangelo
|
||||
cover: mountain-lake-cottage
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Displays a text on top of an image using an overlay.
|
||||
|
||||
- Use `backdrop-filter` to apply a `blur(14px)` and `brightness(80%)` effect. This makes text readable regardless of background image and color.
|
||||
|
||||
```html
|
||||
<div>
|
||||
<h3 class="text-overlay">Hello, World</h3>
|
||||
<img src="https://picsum.photos/id/1050/1200/800">
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
div {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.text-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 1rem;
|
||||
font-size: 2rem;
|
||||
font-weight: 300;
|
||||
color: white;
|
||||
backdrop-filter: blur(14px) brightness(80%);
|
||||
}
|
||||
```
|
||||
48
css/snippets/tile-layout-using-inline-block.md
Normal file
48
css/snippets/tile-layout-using-inline-block.md
Normal file
@ -0,0 +1,48 @@
|
||||
---
|
||||
title: 3-tile layout
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: godray-computer-mug
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Aligns items horizontally using `display: inline-block` to create a 3-tile layout.
|
||||
|
||||
- Use `display: inline-block` to create a tiled layout, without using `float`, `flex` or `grid`.
|
||||
- Use `width` in combination with `calc` to divide the width of the container evenly into 3 columns.
|
||||
- Set `font-size` for `.tiles` to `0` to avoid whitespace and to `20px` for `<h2>` elements to display the text.
|
||||
- **Note:** If you use relative units (e.g. `em`), using `font-size: 0` to fight whitespace between blocks might cause side effects.
|
||||
|
||||
```html
|
||||
<div class="tiles">
|
||||
<div class="tile">
|
||||
<img src="https://via.placeholder.com/200x150">
|
||||
<h2>30 Seconds of CSS</h2>
|
||||
</div>
|
||||
<div class="tile">
|
||||
<img src="https://via.placeholder.com/200x150">
|
||||
<h2>30 Seconds of CSS</h2>
|
||||
</div>
|
||||
<div class="tile">
|
||||
<img src="https://via.placeholder.com/200x150">
|
||||
<h2>30 Seconds of CSS</h2>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.tiles {
|
||||
width: 600px;
|
||||
font-size: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.tile {
|
||||
width: calc(600px / 3);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.tile h2 {
|
||||
font-size: 20px;
|
||||
}
|
||||
```
|
||||
56
css/snippets/toggle-switch.md
Normal file
56
css/snippets/toggle-switch.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: Toggle switch
|
||||
type: snippet
|
||||
tags: [visual,interactivity]
|
||||
cover: interior-5
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Creates a toggle switch with CSS only.
|
||||
|
||||
- Use the `for` attribute to associate the `<label>` with the checkbox `<input>` element.
|
||||
- Use the `::after` pseudo-element of the `<label>` to create a circular knob for the switch.
|
||||
- Use the `:checked` pseudo-class selector to change the position of the knob, using `transform: translateX(20px)` and the `background-color` of the switch.
|
||||
- Use `position: absolute` and `left: -9999px` to visually hide the `<input>` element.
|
||||
|
||||
```html
|
||||
<input type="checkbox" id="toggle" class="offscreen" />
|
||||
<label for="toggle" class="switch"></label>
|
||||
```
|
||||
|
||||
```css
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
border-radius: 20px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.switch::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 18px;
|
||||
background-color: white;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
input[type='checkbox']:checked + .switch::after {
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
input[type='checkbox']:checked + .switch {
|
||||
background-color: #7983ff;
|
||||
}
|
||||
|
||||
.offscreen {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
```
|
||||
37
css/snippets/transform-centering.md
Normal file
37
css/snippets/transform-centering.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: Transform centering
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: flower-camera
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Vertically and horizontally centers a child element within its parent element using CSS transforms.
|
||||
|
||||
- Set the `position` of the parent to `relative` and that of the child to `absolute` to place it in relation to its parent.
|
||||
- Use `left: 50%` and `top: 50%` to offset the child 50% from the left and top edge of the containing block.
|
||||
- Use `transform: translate(-50%, -50%)` to negate its position, so that it is vertically and horizontally centered.
|
||||
- **Note:** The fixed `height` and `width` of the parent element is for demonstration purposes only.
|
||||
|
||||
```html
|
||||
<div class="parent">
|
||||
<div class="child">Centered content</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.parent {
|
||||
border: 1px solid #9C27B0;
|
||||
height: 250px;
|
||||
position: relative;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.child {
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
}
|
||||
```
|
||||
28
css/snippets/triangle.md
Normal file
28
css/snippets/triangle.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Triangle
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: yellow-white-mug-1
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates a triangular shape with pure CSS.
|
||||
|
||||
- Use three borders to create a triangle shape.
|
||||
- All borders should have the same `border-width` (`20px`).
|
||||
- The opposite side of where the triangle points towards (i.e. top if the triangle points downwards) should have the desired `border-color`. The adjacent borders (i.e. left and right) should have a `border-color` of `transparent`.
|
||||
- Altering the `border-width` values will change the proportions of the triangle.
|
||||
|
||||
```html
|
||||
<div class="triangle"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.triangle {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 20px solid #9C27B0;
|
||||
border-left: 20px solid transparent;
|
||||
border-right: 20px solid transparent;
|
||||
}
|
||||
```
|
||||
47
css/snippets/truncate-text-multiline.md
Normal file
47
css/snippets/truncate-text-multiline.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
title: Truncate multiline text
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: blue-computer
|
||||
dateModified: 2021-01-07T23:52:15+02:00
|
||||
---
|
||||
|
||||
Truncates text that is longer than one line.
|
||||
|
||||
- Use `overflow: hidden` to prevent the text from overflowing its dimensions.
|
||||
- Set a fixed `width` to ensure the element has at least one constant dimension.
|
||||
- Set `height: 109.2px` as calculated from the `font-size`, using the formula `font-size * line-height * numberOfLines` (in this case `26 * 1.4 * 3 = 109.2`).
|
||||
- Set `height: 36.4px` as calculated for the gradient container, based on the formula `font-size * line-height` (in this case `26 * 1.4 = 36.4`).
|
||||
- Use `background` with `linear-gradient()` to create a gradient from `transparent` to the `background-color`.
|
||||
|
||||
```html
|
||||
<p class="truncate-text-multiline">
|
||||
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
|
||||
eirmod tempor invidunt ut labore et.
|
||||
</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.truncate-text-multiline {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
height: 109.2px;
|
||||
margin: 0 auto;
|
||||
font-size: 26px;
|
||||
line-height: 1.4;
|
||||
width: 400px;
|
||||
background: #f5f6f9;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.truncate-text-multiline::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 150px;
|
||||
height: 36.4px;
|
||||
background: linear-gradient(to right, rgba(0, 0, 0, 0), #f5f6f9 50%);
|
||||
}
|
||||
```
|
||||
28
css/snippets/truncate-text.md
Normal file
28
css/snippets/truncate-text.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Truncate text
|
||||
type: snippet
|
||||
tags: [layout]
|
||||
cover: houses-rock-sea
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Truncates text that is longer than one line, adding an ellipsis at the end (`…`).
|
||||
|
||||
- Use `overflow: hidden` to prevent the text from overflowing its dimensions.
|
||||
- Use `white-space: nowrap` to prevent the text from exceeding one line in height.
|
||||
- Use `text-overflow: ellipsis` to make it so that if the text exceeds its dimensions, it will end with an ellipsis.
|
||||
- Specify a fixed `width` for the element to know when to display an ellipsis.
|
||||
- Only works for single line elements.
|
||||
|
||||
```html
|
||||
<p class="truncate-text">If I exceed one line's width, I will be truncated.</p>
|
||||
```
|
||||
|
||||
```css
|
||||
.truncate-text {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
width: 200px;
|
||||
}
|
||||
```
|
||||
68
css/snippets/typewriter-effect.md
Normal file
68
css/snippets/typewriter-effect.md
Normal file
@ -0,0 +1,68 @@
|
||||
---
|
||||
title: Typewriter effect
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
author: chalarangelo
|
||||
cover: italian-horizon
|
||||
dateModified: 2021-05-24T16:03:40+03:00
|
||||
---
|
||||
|
||||
Creates a typewriter effect animation.
|
||||
|
||||
- Define two animations, `typing` to animate the characters and `blink` to animate the caret.
|
||||
- Use the `::after` pseudo-element to add the caret to the container element.
|
||||
- Use JavaScript to set the text for the inner element and set the `--characters` variable containing the character count. This variable is used to animate the text.
|
||||
- Use `white-space: nowrap` and `overflow: hidden` to make content invisible as necessary.
|
||||
|
||||
```html
|
||||
<div class="typewriter-effect">
|
||||
<div class="text" id="typewriter-text"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.typewriter-effect {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.typewriter-effect > .text {
|
||||
max-width: 0;
|
||||
animation: typing 3s steps(var(--characters)) infinite;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.typewriter-effect::after {
|
||||
content: " |";
|
||||
animation: blink 1s infinite;
|
||||
animation-timing-function: step-end;
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
75%,
|
||||
100% {
|
||||
max-width: calc(var(--characters) * 1ch);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0%,
|
||||
75%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
25% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const typeWriter = document.getElementById('typewriter-text');
|
||||
const text = 'Lorem ipsum dolor sit amet.';
|
||||
|
||||
typeWriter.innerHTML = text;
|
||||
typeWriter.style.setProperty('--characters', text.length);
|
||||
```
|
||||
132
css/snippets/vertical-gallery.md
Normal file
132
css/snippets/vertical-gallery.md
Normal file
@ -0,0 +1,132 @@
|
||||
---
|
||||
title: Image gallery with vertical scroll
|
||||
type: snippet
|
||||
tags: [visual,interactivity]
|
||||
cover: lake-loop
|
||||
dateModified: 2022-05-05T05:00:00-04:00
|
||||
---
|
||||
|
||||
Creates a horizontally scrollable image gallery.
|
||||
|
||||
- Use `display: flex` and `justify-content: center` to setup the layout for the container.
|
||||
- Use `display: flex` and `flex-direction: column` to setup the layout for the slides.
|
||||
- Use `scroll-snap-type: y mandatory` and `overscroll-behavior-y: contain` to create a snap effect on vertical scroll. Snap elements to the start of the container using `scroll-snap-align: start`.
|
||||
- Hide scrollbars using `scrollbar-width: none` and styling the pseudo-element `::-webkit-scrollbar` to `display: none`.
|
||||
- Use `Element.scrollTo()` to define a `scrollToElement` function, that scrolls the gallery to the given item.
|
||||
- Use `Array.prototype.map()` and `Array.prototype.join()` to populate the `.thumbnails` element. Give each thumbnail a `data-id` attribute with the index of the image.
|
||||
- Use `Document.querySelectorAll()` to get all the thumbnail elements. Use `Array.prototype.forEach()` to register a handler for the `'click'` event on each thumbnail, using `EventTarget.addEventListener()` and the `scrollToElement` function.
|
||||
- Use `Document.querySelector()` and `EventTarget.addEventListener()` to register a handler for the `'scroll'` event. Update the `.thumbnails` and `.scrollbar` elements to match the current scroll position, using the `scrollThumb` function.
|
||||
|
||||
```html
|
||||
<div class="gallery-container">
|
||||
<div class="thumbnails"></div>
|
||||
<div class="scrollbar">
|
||||
<div class="thumb"></div>
|
||||
</div>
|
||||
<div class="slides">
|
||||
<div><img src="https://picsum.photos/id/1067/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/122/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/188/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/249/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/257/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/259/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/283/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/288/540/720"></div>
|
||||
<div><img src="https://picsum.photos/id/299/540/720"></div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.gallery-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.thumbnails {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.thumbnails img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.scrollbar {
|
||||
width: 1px;
|
||||
height: 720px;
|
||||
background: #ccc;
|
||||
display: block;
|
||||
margin: 0 0 0 8px;
|
||||
}
|
||||
|
||||
.thumb {
|
||||
width: 1px;
|
||||
position: absolute;
|
||||
height: 0;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.slides {
|
||||
margin: 0 16px;
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
gap: 1rem;
|
||||
width: calc(540px + 1rem);
|
||||
padding: 0 0.25rem;
|
||||
height: 720px;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior-y: contain;
|
||||
scroll-snap-type: y mandatory;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.slides > div {
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
|
||||
.slides img {
|
||||
width: 540px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.slides::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const slideGallery = document.querySelector('.slides');
|
||||
const slides = slideGallery.querySelectorAll('div');
|
||||
const scrollbarThumb = document.querySelector('.thumb');
|
||||
const slideCount = slides.length;
|
||||
const slideHeight = 720;
|
||||
const marginTop = 16;
|
||||
|
||||
const scrollThumb = () => {
|
||||
const index = Math.floor(slideGallery.scrollTop / slideHeight);
|
||||
scrollbarThumb.style.height = `${((index + 1) / slideCount) * slideHeight}px`;
|
||||
};
|
||||
|
||||
const scrollToElement = el => {
|
||||
const index = parseInt(el.dataset.id, 10);
|
||||
slideGallery.scrollTo(0, index * slideHeight + marginTop);
|
||||
};
|
||||
|
||||
document.querySelector('.thumbnails').innerHTML += [...slides]
|
||||
.map(
|
||||
(slide, i) => `<img src="${slide.querySelector('img').src}" data-id="${i}">`
|
||||
)
|
||||
.join('');
|
||||
|
||||
document.querySelectorAll('.thumbnails img').forEach(el => {
|
||||
el.addEventListener('click', () => scrollToElement(el));
|
||||
});
|
||||
|
||||
slideGallery.addEventListener('scroll', e => scrollThumb());
|
||||
|
||||
scrollThumb();
|
||||
```
|
||||
52
css/snippets/vertical-scroll-snap.md
Normal file
52
css/snippets/vertical-scroll-snap.md
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
title: Vertical scroll snap
|
||||
type: snippet
|
||||
tags: [interactivity]
|
||||
cover: baloons-field
|
||||
dateModified: 2020-08-18T14:25:46+03:00
|
||||
---
|
||||
|
||||
Creates a scrollable container that will snap on elements when scrolling.
|
||||
|
||||
- Use `display: grid` and `grid-auto-flow: row` to create a vertical layout.
|
||||
- Use `scroll-snap-type: y mandatory` and `overscroll-behavior-y: contain` to create a snap effect on vertical scroll.
|
||||
- You can use `scroll-snap-align` with either `start`, `stop` or `center` to change the snap alignment.
|
||||
|
||||
```html
|
||||
<div class="vertical-snap">
|
||||
<a href="#"><img src="https://picsum.photos/id/1067/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/122/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/188/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/249/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/257/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/259/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/283/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/288/640/640"></a>
|
||||
<a href="#"><img src="https://picsum.photos/id/299/640/640"></a>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.vertical-snap {
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
gap: 1rem;
|
||||
width: calc(180px + 1rem);
|
||||
padding: 1rem;
|
||||
height: 480px;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior-y: contain;
|
||||
scroll-snap-type: y mandatory;
|
||||
}
|
||||
|
||||
.vertical-snap > a {
|
||||
scroll-snap-align: center;
|
||||
}
|
||||
|
||||
.vertical-snap img {
|
||||
width: 180px;
|
||||
object-fit: contain;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
```
|
||||
28
css/snippets/zebra-striped-list.md
Normal file
28
css/snippets/zebra-striped-list.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Zebra striped list
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: forest-balcony
|
||||
dateModified: 2020-12-30T15:37:37+02:00
|
||||
---
|
||||
|
||||
Creates a striped list with alternating background colors.
|
||||
|
||||
- Use the `:nth-child(odd)` or `:nth-child(even)` pseudo-class selectors to apply a different `background-color` to elements that match based on their position in a group of siblings.
|
||||
- **Note:** You can use it to apply different styles to other HTML elements like `<div>`, `<tr>`, `<p>`, `<ol>`, etc.
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li>Item 01</li>
|
||||
<li>Item 02</li>
|
||||
<li>Item 03</li>
|
||||
<li>Item 04</li>
|
||||
<li>Item 05</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
```css
|
||||
li:nth-child(odd) {
|
||||
background-color: #999;
|
||||
}
|
||||
```
|
||||
33
css/snippets/zig-zag-pattern.md
Normal file
33
css/snippets/zig-zag-pattern.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
title: Zig zag background pattern
|
||||
type: snippet
|
||||
tags: [visual]
|
||||
cover: blue-lake
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates a zig zag background pattern.
|
||||
|
||||
- Use `background-color` to set a white background.
|
||||
- Use `background-image` with four `linear-gradient()` values to create the parts of a zig zag pattern.
|
||||
- Use `background-size` to specify the pattern's size. Use `background-position` to place the parts of the pattern in the correct locations.
|
||||
- **Note:** The fixed `height` and `width` of the element is for demonstration purposes only.
|
||||
|
||||
```html
|
||||
<div class="zig-zag"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.zig-zag {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
background-color: #fff;
|
||||
background-image: linear-gradient(135deg, #000 25%, transparent 25%),
|
||||
linear-gradient(225deg, #000 25%, transparent 25%),
|
||||
linear-gradient(315deg, #000 25%, transparent 25%),
|
||||
linear-gradient(45deg, #000 25%, transparent 25%);
|
||||
background-position: -30px 0, -30px 0, 0 0, 0 0;
|
||||
background-size: 60px 60px;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
```
|
||||
39
css/snippets/zoomin-zoomout-animation.md
Normal file
39
css/snippets/zoomin-zoomout-animation.md
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Zoom in zoom out animation
|
||||
type: snippet
|
||||
tags: [animation]
|
||||
cover: travel-mug-2
|
||||
dateModified: 2021-10-13T19:29:39+02:00
|
||||
---
|
||||
|
||||
Creates a zoom in zoom out animation.
|
||||
|
||||
- Use `@keyframes` to define a three-step animation. At the start (`0%`) and end (`100%`), the element is its original size (`scale(1 ,1)`). Halfway through (`50%`) it's scaled up to 1.5 times its original size (`scale(1.5, 1.5)`).
|
||||
- Use `width` and `height` to give the element a specific size.
|
||||
- Use `animation` to set the appropriate values for the element to make it animated.
|
||||
|
||||
```html
|
||||
<div class="zoom-in-out-box"></div>
|
||||
```
|
||||
|
||||
```css
|
||||
.zoom-in-out-box {
|
||||
margin: 24px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: #f50057;
|
||||
animation: zoom-in-zoom-out 1s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes zoom-in-zoom-out {
|
||||
0% {
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.5, 1.5);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user