CSS Components Notes
Utilities
Resizable Class
// bottom-right:
new_width = element_original_width + (mouseX - original_mouseX)
new_height = element_original_height + (mouseY - original_mouseY)
// bottom-left:
new_width = element_original_width - (mouseX - original_mouseX)
new_height = element_original_height + (mouseY - original_mouseY)
new_x = element_original_x - (mouseX - original_mouseX)
// top-right:
new_width = element_original_width + (mouseX - original_mouseX)
new_height = element_original_height - (mouseY - original_mouseY)
new_y = element_original_y + (mouseY - original_mouseY)
// top-left:
new_width = element_original_width - (mouseX - original_mouseX)
new_height = element_original_height - (mouseY - original_mouseY)
new_x = element_original_x + (mouseX - original_mouseX)
new_y = element_original_y + (mouseY - original_mouseY)
Hidden Class
display: none
: 元素不在 DOM 流.visibility: hidden
: 元素在 DOM 流, 隐藏不可见, 不可触发事件.opacity: 0
: 元素在 DOM 流, 透明度为 0, 可触发事件.
.hidden-overflow {
max-height: 0;
overflow: hidden;
}
.hidden-opacity {
position: absolute;
filter: opacity(0%);
opacity: 0;
}
.hidden-stacking {
position: relative;
z-index: -1;
}
.hidden-clip {
position: absolute;
clip: rect(0 0 0 0);
}
.hidden-visibility {
position: absolute;
visibility: hidden; /* visibility 具有继承性 */
}
.hidden-display {
display: none;
}
Typography
Flexible Heading
h1 {
display: flex;
align-items: center;
width: 100%;
}
h1::before,
h1::after {
flex: 1;
height: 0.1em;
margin: 0.2em;
content: '';
background-color: gray;
}
Text Preset
.text-primary {
font-family: sans-serif;
font-size: 12px;
font-weight: 400;
line-height: 100px;
color: black;
text-decoration: none;
text-transform: uppercase;
letter-spacing: 1.3px;
font-display: swap;
}
Landing Page
Jumbotron Background Image
h1 {
background-image: url('bg.jpg');
background-clip: text;
}
.jumbotron {
min-height: 100%;
background-image: url('');
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
opacity: 0.8;
}
Muted Video
.fullscreen-video {
position: absolute;
top: 0;
left: 0;
z-index: -100;
width: 100%;
height: 100vh;
overflow: hidden;
background-size: cover;
}
.fullscreen-video video {
min-width: 100%;
min-height: 100%;
}
Search Light Effect
:root::before {
position: fixed;
z-index: 1000;
display: block;
width: 100%;
height: 100%;
pointer-events: none;
content: '';
background: radial-gradient(
circle 16vmax at var(--cursor-x) var(--cursor-y),
rgb(0 0 0 / 0%) 0%,
rgb(0 0 0 / 50%) 80%,
rgb(0 0 0 / 80%) 100%
);
}
Navigation
Float Navigation
list-style-type
: 改变ul
/ol
前标记类型.list-style-image
: 改变ul
/ol
前标记类型.- 设置
<a href="#">
样式.
ul {
/* 垂直菜单设置宽度, 水平菜单不设置宽度 */
list-style: none;
}
/* 水平菜单 */
li {
float: left;
}
a {
display: inline-block;
text-decoration: none;
cursor: pointer;
}
Inline Block Navigation
ul {
text-align: right;
}
li {
display: inline-block;
}
Dropdown Navigation
.anchor {
display: none;
}
.content {
max-height: 0;
overflow: hidden;
opacity: 0;
transition:
max-height 0.3s,
opacity 0.3s;
}
.anchor:target ~ .content {
max-height: 100%;
opacity: 1;
}
Tab Navigation
.tab > a {
position: relative;
display: inline-block;
padding: 0.3em 1em 0;
}
.tab > a::before {
position: absolute;
inset: 0;
z-index: -1;
background: #ccc;
background-image: linear-gradient(hsl(0deg 0% 100% / 60%), hsl(0deg 0% 100% / 0%));
border: 1px solid rgb(0 0 0 / 40%);
border-bottom: none;
border-radius: 0.5em 0.5em 0 0;
box-shadow: 0 0.15em white inset;
transform: perspective(0.5em) rotateX(5deg);
transform-origin: bottom;
}
Footer
Sticky Footer
- 如果页面内容不足够长时, 页脚固定在浏览器窗口的底部.
- 如果内容足够长时, 页脚固定在页面的最底部.
Negative Margin Sticky Footer
Negative bottom margin
content-wrapper with fixed height
footer:
<body>
<main class="wrapper">
content
<div class="push"></div>
</main>
<footer class="footer"></footer>
</body>
<style>
html,
body {
height: 100%;
margin: 0;
}
.wrapper {
min-height: 100%;
/* Equal to height of footer */
/* But also accounting for potential margin-bottom of last child */
margin-bottom: -50px;
}
.footer,
.push {
height: 50px;
}
</style>
Negative top margin
on fixed height
footer:
<body>
<main class="content">
<section class="content-inside">content</section>
</main>
<footer class="footer"></footer>
</body>
<style>
html,
body {
height: 100%;
margin: 0;
}
.content {
min-height: 100%;
}
.content-inside {
padding: 20px;
padding-bottom: 50px;
}
.footer {
height: 50px;
margin-top: -50px;
}
</style>
Calculation Sticky Footer
calc
on fixed height footer:
<body>
<main class="content">content</main>
<footer class="footer"></footer>
</body>
<style>
.content {
min-height: calc(100vh - 70px);
}
.footer {
height: 50px;
}
</style>
Flex Sticky Footer
Use flex
on body
:
<body>
<main class="content">content</main>
<footer class="footer"></footer>
</body>
<style>
html,
body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.content {
flex: 1 0 auto;
}
.footer {
flex-shrink: 0;
}
</style>
Grid Sticky Footer
Use grid
on body
:
<body>
<main class="content">content</main>
<footer class="footer"></footer>
</body>
<style>
html {
height: 100%;
}
body {
display: grid;
grid-template-rows: 1fr auto;
min-height: 100%;
}
.footer {
grid-row: 2 / 3;
}
</style>
Use gird
with min-content
:
<body>
<div class="grid">
<header>
<!-- ... -->
</header>
<main>
<!-- ... -->
</main>
<footer>
<!-- ... -->
</footer>
</div>
</body>
<style>
.grid {
display: grid;
grid-template-rows: min-content auto min-content;
height: 100vh;
}
</style>
Link
Styled Link
a {
padding: 2px 1px 0;
text-decoration: none;
outline: none;
}
a:link {
color: #265301;
}
a:visited {
color: #437a16;
}
a:focus {
background: #bae498;
border-bottom: 1px solid;
}
a:hover {
background: #cdfeaa;
border-bottom: 1px solid;
}
a:active {
color: #cdfeaa;
background: #265301;
}
a[href^='http'] {
padding-right: 19px;
background: url('external-link-52.png') no-repeat 100% 0;
background-size: 16px 16px;
}
Hidden Link
a {
text-decoration: none;
pointer-events: none;
cursor: default;
opacity: 0;
}
Animated Link
Change bottom border:
a {
position: relative;
padding-bottom: 5px;
color: #008080;
text-decoration: none;
}
a::after {
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 3px;
content: '';
background-color: #22313f;
transform-origin: bottom-center;
}
a:hover,
a:focus {
color: #22313f;
}
a:hover::after,
a:focus::after {
width: 100%;
}
GitHub Link
<a href="https://github.com/Trevald/WhatTheTag.com" class="github-corner" aria-label="View source on GitHub">
<svg
width="80"
height="80"
viewBox="0 0 250 250"
style="position: absolute; top: 0; right: 0; color: #2d3748; border: 0; fill: #718096"
aria-hidden="true"
>
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" />
<path
d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
fill="currentColor"
style="transform-origin: 130px 106px"
class="octo-arm"
/>
<path
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="currentColor"
class="octo-body"
/>
</svg>
</a>
.github-corner:focus .octo-arm,
.github-corner:hover .octo-arm {
animation: none;
}
@media (prefers-reduced-motion: no-preference) {
.github-corner:focus .octo-arm,
.github-corner:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
}
@keyframes octocat-wave {
0%,
100% {
transform: rotate(0);
}
20%,
60% {
transform: rotate(-25deg);
}
40%,
80% {
transform: rotate(10deg);
}
}
Button
Link Button
a.btn-custom {
padding: 10px 40px;
line-height: 100px;
text-align: center;
background-color: #000;
border-radius: 0;
}
Gradient Button
Linear Gradient Button
.btn {
display: inline-block;
padding: 5px;
color: #333;
text-decoration: none;
background-image: linear-gradient(to top, #333 50%, #fff 50%);
background-size: 100% 200%;
transition: all 0.3s;
}
.btn:hover,
.btn:focus {
color: #fff;
background-position: 0 100%;
}
.btn-1 {
background-image: linear-gradient(to right, #f6d365 0%, #fda085 51%, #f6d365 100%);
}
.btn-2 {
background-image: linear-gradient(to right, #fbc2eb 0%, #a6c1ee 51%, #fbc2eb 100%);
}
.btn-3 {
background-image: linear-gradient(to right, #84fab0 0%, #8fd3f4 51%, #84fab0 100%);
}
.btn-4 {
background-image: linear-gradient(to right, #a1c4fd 0%, #c2e9fb 51%, #a1c4fd 100%);
}
.btn-5 {
background-image: linear-gradient(to right, #ffecd2 0%, #fcb69f 51%, #ffecd2 100%);
}
.btn:hover,
.btn:focus {
background-position: right center; /* change the direction of the change here */
}
Radial Gradient Button
.ripple-button {
color: #fff;
background-color: #2a80eb;
}
.ripple-button:active {
background-image: radial-gradient(160% 100% at 50% 0%, hsl(0deg 0% 100% / 30%) 50%, hsl(0deg 0% 100% / 0%) 52%);
}
.colorful-button {
color: #fff;
background-color: #2a80eb;
background-image: radial-gradient(farthest-side at bottom left, rgb(255 0 255/ 50%), transparent),
radial-gradient(farthest-corner at bottom right, rgb(255 255 50/ 50%), transparent);
}
3D Shadow Button
.shadow-3d-button {
width: 100px;
height: 36px;
background-color: #f0f3f9;
border: 1px solid #a0b3d6;
box-shadow:
1px 1px #afc4ea,
2px 2px #afc4ea,
3px 3px #afc4ea;
}
.shadow-3d-button:active {
box-shadow:
1px 1px #afc4ea,
2px 2px #afc4ea;
transform: translate(1px, 1px);
}
Button Reference
- 100 modern CSS buttons.
Table
table-layout: fixed
to contain cells with same width, makes<table>
behave a bit more predictably.border: 0
andborder-collapse: collapse
to remove border line.text-align
for<th>
/<td>
text alignment.- Implement filter or pagination with
display: none
applied to<tr>
.
/**
* `fixed` layout and `collapse` border.
*/
table {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
border: 3px solid purple;
}
/**
* Spacing and alignment.
*/
th,
td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #e1e1e1;
}
th:first-child,
td:first-child {
padding-left: 0;
}
th:last-child,
td:last-child {
padding-right: 0;
}
/**
* Control column width.
*/
thead th:nth-child(1) {
width: 30%;
}
thead th:nth-child(2) {
width: 20%;
}
thead th:nth-child(3) {
width: 15%;
}
thead th:nth-child(4) {
width: 35%;
}
Form
- 由于表单组件多为
Replaced Element
, 通过 CSS 控制样式存在困难, 一般利用label
/span
代替input
的方式, 对label
与span
进行核心样式控制, 对input
进行辅助样式控制::disabled
.:checked
.:focus-visible
.:focus:not(:focus-visible)
.:active:not(:disabled)
.:indeterminate
.
- 隐藏
input
, 用label
模拟时, 需要注意表单元素的键盘可访问性:- 保持键盘访问:
不应使用
display: none
/visibility: hidden
隐藏input
(无法键盘访问), 应使用[type="checkbox"] { position: absolute; clip: rect(0 0 0 0); }
. - 修饰键盘访问:
应添加
:focus
/:focus-visible
伪类样式,input:focus ~ label { outline: 1px solid red; border: 1px solid red; }
.
- 保持键盘访问:
不应使用
[type='radio'] {
position: absolute;
width: 1rem;
height: 1rem;
cursor: pointer;
opacity: 0;
}
.radio-label {
background-color: var(--color-transparent);
border-color: var(--color-dark);
border-radius: 999px;
}
:disabled ~ .radio-label {
border-color: var(--color-ghost);
}
:checked ~ .radio-label {
background-color: var(--color-primary);
border-color: var(--color-primary);
}
:focus-visible ~ .radio-label {
outline: 1px solid var(--color-primary);
}
:focus:not(:focus-visible) ~ .radio-label {
border-color: var(--color-primary);
outline: none;
}
:active:not(:disabled) ~ .radio-label {
transform: scale(1.1);
}
Reset Form Styles
input[type='email'],
input[type='number'],
input[type='search'],
input[type='text'],
input[type='tel'],
input[type='url'],
input[type='password'],
textarea,
select {
box-sizing: border-box;
height: 38px;
padding: 6px 10px;
background-color: #fff;
border: 1px solid #d1d1d1;
border-radius: 4px;
box-shadow: none;
}
/* Removes awkward default styles on some inputs for iOS */
input[type='email'],
input[type='number'],
input[type='search'],
input[type='text'],
input[type='tel'],
input[type='url'],
input[type='password'],
textarea {
appearance: none;
}
textarea {
min-height: 65px;
padding-top: 6px;
padding-bottom: 6px;
}
input[type='email']:focus,
input[type='number']:focus,
input[type='search']:focus,
input[type='text']:focus,
input[type='tel']:focus,
input[type='url']:focus,
input[type='password']:focus,
textarea:focus,
select:focus {
/* Custom border color */
border: 1px solid #33c3f0;
/* Key point: remove default outline */
outline: 2px solid transparent;
outline-offset: 2px;
}
label,
legend {
display: block;
padding: 0;
margin-bottom: 0.5rem;
font-weight: bold;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border-width: 0;
}
input[type='checkbox'],
input[type='radio'] {
display: inline;
}
label > .label-body {
display: inline-block;
margin-left: 0.5rem;
font-weight: normal;
}
Custom Form Button
隐藏 <input>
, 添加样式至 <label>
/<span>
:
<input id="submit" type="submit" />
<label class="btn" for="submit">Submit</label>
<style>
[type='submit'] {
position: absolute;
clip: rect(0 0 0 0);
}
.btn {
display: inline-block;
padding: 2px 12px;
font-size: 14px;
color: #fff;
cursor: pointer;
background-color: #cd0000;
}
:focus + label.btn {
outline: 1px dotted var(--highlight);
}
</style>
Custom Form Checkbox
Input itself as border shape, pseudo elements as center shape (checked transform animation):
input[type='checkbox'] + label::before {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
margin-right: 10px;
content: '';
background: white;
}
input[type='checkbox']:checked + label::before {
background: #5ac5c9;
}
input[type='checkbox']:checked + label::after {
position: absolute;
top: 3px;
left: 27px;
width: 13px;
height: 6px;
content: '';
border-bottom: 2px solid black;
border-left: 2px solid black;
transform: rotate(-45deg);
}
input[type='checkbox']:focus + label::before {
outline: #5d9dd5 solid 1px;
box-shadow: 0 0 8px #5e9ed6;
}
input[type='checkbox']:disabled + label {
color: #575757;
}
input[type='checkbox']:disabled + label::before {
background: #ddd;
}
Custom Form Switch
Pseudo element switch from circle to circle:
- thumb-size: 2rem.
- track-width:
2 * thumb-size
. - track-height: thumb-size.
- pseudo-element border-radius: 50%.
- track border-radius: track-size.
- checked transform:
track
background-color
, pseudo elementtranslateX
.
.gui-switch > input {
display: grid;
flex-shrink: 0;
grid: [track] 1fr / [track] 1fr;
align-items: center;
inline-size: var(--track-size);
block-size: var(--thumb-size);
padding: var(--track-padding);
appearance: none;
border-radius: var(--track-size);
}
.gui-switch > input::before {
grid-area: track;
inline-size: var(--thumb-size);
block-size: var(--thumb-size);
content: '';
}
Custom Form Select
.custom-select {
width: 15%;
height: 35px;
margin-right: 20px;
/* 文本属性 */
text-align: center;
text-align-last: center;
/* 消除默认箭头 */
text-indent: 0.01px;
text-overflow: '';
/* 消除默认样式 */
appearance: none;
/* 将箭头图片移至右端 */
background: url('images/arrow.png') no-repeat;
background-color: #fff;
background-position: right;
/* 自定义边框 */
border: 0;
}
.custom-select:focus {
border: 1px solid #e74f4d;
}
.custom-select option {
width: 100%;
height: 25px;
padding-left: 30px;
line-height: 25px;
color: #323333;
background-color: #fff;
direction: rtl;
}
.custom-select option:hover,
.custom-select option:focus {
color: #fff;
background: url('./img/tick.png') no-repeat 8px center;
background-color: #e74f4d;
}
Modal
Overlay Modal
.overlay {
position: fixed;
width: 100%;
height: 100%;
background: rgb(0 0 0 / 50%);
}
Box Shadow Modal
.modal {
box-shadow: 0 0 0 50vmax rgb(0 0 0 / 80%);
}
Dialog Modal
<div class="container">
<div class="dialog">
<div class="content">内容占位</div>
</div>
</div>
.container {
position: fixed;
inset: 0;
z-index: 99;
text-align: center;
white-space: nowrap;
/* for IE8 */
background: url('data:image/png;base64,iVB...g==');
/* for IE9+ */
background: rgb(0 0 0 / 50%), none;
}
.container::after {
display: inline-block;
height: 100%;
vertical-align: middle;
content: '';
}
.dialog {
display: inline-block;
text-align: left;
white-space: normal;
vertical-align: middle;
background-color: #fff;
border-radius: 6px;
}
Clip Modal
图片剪裁的矩形镂空效果:
.crop {
overflow: hidden;
}
.crop > .crop-area {
width: 80px;
height: 80px;
cursor: move;
outline: 256px solid rgb(0 0 0 / 50%);
}
Tooltip
利用伪元素 (无法选中) 生成元素, 并设置 pointer-events: none
(无法交互):
.tooltip {
position: relative;
cursor: help;
}
/* 三角形 */
.tooltip::before {
position: absolute;
top: 12px;
left: 20px;
display: block;
width: 0;
height: 0;
content: '';
border: solid transparent 5px;
border-bottom-color: rgb(0 0 0 / 80%);
opacity: 0;
transition:
opacity 250ms,
top 250ms;
}
/* 提示文字 */
.tooltip::after {
position: absolute;
top: 22px;
left: 0;
display: inline;
width: 230px;
padding: 0.5em 0.8em;
font-size: 13px;
font-weight: 700;
line-height: 1.5em;
color: #fff;
pointer-events: none; /* This prevents the box from appearing when hovered. */
content: attr(aria-label);
background: rgb(0 0 0 / 80%);
opacity: 0;
transition:
opacity 250ms,
top 250ms;
}
/* Keeps the info boxes on top of other elements */
.tooltip:hover {
z-index: 2;
}
.tooltip:hover::before,
.tooltip:hover::after {
opacity: 1;
}
.tooltip:hover::before {
top: 20px;
}
.tooltip:hover::after {
top: 30px;
}
TreeView
GitHub tree view component:
<div class="tree-view-item">
<div class="spacer"></div>
<div class="toggle"></div>
<div class="content">
<div class="visual"></div>
<span class="text">ReactART-test.js.snap</span>
</div>
</div>
<style scoped>
.tree-view-item {
--toggle-width: 1rem;
--spacer-col: calc(calc(var(--level) - 1) * (var(--toggle-width) / 2));
display: grid;
grid-template-areas: 'spacer toggle content';
grid-template-columns: var(--spacer-col) var(--toggle-width) 1fr;
}
.spacer {
grid-area: spacer;
}
.toggle {
grid-area: toggle;
}
.content {
grid-area: content;
}
</style>
Scroll Effect
Parallax Effect
Background Attachment Parallax Effect
.parallax {
min-height: 60%; /* key */
background-image: url('./images/bg.jpg');
background-repeat: no-repeat;
background-attachment: fixed; /* key */
background-position: center;
background-size: cover;
}
3D Perspective Transform Parallax Effect
3D perspective transform parallax effect:
<div class="parallax">
<div class="parallax-group">
<div class="parallax-layer parallax-fore-layer"></div>
<div class="parallax-layer parallax-base-layer"></div>
</div>
<div class="parallax-group">
<div class="parallax-layer parallax-base-layer"></div>
<div class="parallax-layer parallax-back-layer"></div>
<div class="parallax-layer parallax-deep-layer"></div>
</div>
</div>
<style>
.parallax {
height: 100vh;
overflow: hidden auto;
perspective: 1px;
perspective-origin: 100% 50%;
}
.parallax-group {
position: relative;
height: 100vh;
transform-style: preserve-3d;
}
.parallax-layer {
position: absolute;
inset: 0;
transform-origin: 100% 50%;
}
.parallax-fore-layer {
transform: translateZ(90px) scale(0.7);
}
.parallax-base-layer {
transform: translateZ(0);
}
.parallax-back-layer {
transform: translateZ(-1px) scale(2);
}
.parallax-deep-layer {
transform: translateZ(-2px) scale(3);
}
</style>
Page Progress Indicator
body {
position: relative;
}
.indicator {
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
background: linear-gradient(to right top, teal 50%, transparent 50%) no-repeat;
background-size: 100% calc(100% - 100vh);
mix-blend-mode: darken;
}
/* use after element to hidden triangle background gradient */
/* only show 5px background */
.indicator::after {
position: fixed;
inset: 5px 0 0;
z-index: 1;
content: '';
background: #fff;
}
Slides
锚点定位本质上改变了 scrollTop
或 scrollLeft
值,
即使容器设置 overflow: hidden
也会发生滚动,
可以利用锚点定位实现 CSS-only slides:
position: absolute
to stack slides up.id
+:target
for style current slide (change z-index).- Add animation to slide change: (prev, current, next)
.slide
,.slide:target
,.slide:target ~ slide
. - Add
overflow: hidden
to container when animation.
<main>
<section class="slide" id="slide1">
<a class="slide-link" href="#slide2">next</a>
</section>
<section class="slide" id="slide2">
<a class="slide-link" href="#slide1">prev</a>
<a class="slide-link" href="#slide3">next</a>
</section>
<section class="slide" id="slide3">
<a class="slide-link" href="#slide2">prev</a>
<a class="slide-link" href="#slide4">next</a>
</section>
<section class="slide" id="slide4">
<a class="slide-link" href="#slide3">prev</a>
<a class="slide-link" href="#slide5">next</a>
</section>
<section class="slide" id="slide5">
<a class="slide-link" href="#slide4">prev</a>
</section>
</main>
body {
overflow: hidden; /* key 1 */
}
.slide {
position: absolute; /* key 2 */
z-index: 0; /* key 3 */
box-sizing: border-box;
width: 100%;
height: 100vh;
}
.slide:target {
z-index: 1; /* key 4 */
}
/* Rotate Fade-In Animation */
@media only screen and (prefers-reduced-motion: reduce) {
.slide {
transition: none;
}
}
.slide {
z-index: 0;
transition:
transform 1s,
opacity 0.8s;
transform: rotate(90deg);
transform-origin: 0 0;
}
.slide:target {
z-index: 1;
transform: rotate(0deg);
}
.slide:target ~ section {
opacity: 0;
transform: rotate(-90deg);
}
当两个 width: 100%
slide 同时处于同一水平位置,
添加左进/右进动画, 当 slide 向右滑动时,
水平的 scrollX 会直接滑到最右边,
导致幻灯片浏览异常.
解决办法
如下:
function resetScrollX() {
window.scrollTo(0, 0)
}
Gallery
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: 1fr;
grid-auto-flow: dense;
grid-gap: 1em;
}
.gallery .featured {
grid-row: span 2;
grid-column: span 2;
}
.gallery figure {
display: flex;
flex-direction: column;
margin: 0;
}
.gallery img {
flex: 1;
max-width: 100%;
object-fit: cover;
}
Timeline and Steps
Use pseudo elements to construct circle and line:
/* The separator line */
.c-timeline-item:not(:last-child) .c-timeline-content::before {
position: absolute;
top: 0;
right: 100%;
width: 2px;
height: 100%;
content: '';
background-color: #d3d3d3;
}
/* The circle */
.c-timeline-content::after {
position: absolute;
top: 0;
left: -12px;
z-index: 1;
width: 20px;
height: 20px;
content: '';
background-color: #fff;
border: 2px solid #d3d3d3;
border-radius: 50%;
}
Background and Shadow
Gradient Border
.gradient-border {
width: 200px;
height: 100px;
margin: auto;
clip-path: inset(0 round 10px);
filter: hue-rotate(360deg);
border: 10px solid;
border-image: linear-gradient(45deg, gold, deeppink) 1;
animation: hue 6s infinite linear;
}
@keyframes hue {
0% {
filter: hue-rotate(0deg);
}
100% {
filter: hue-rotate(360deg);
}
}
Gradient Box Shadow
.box::before {
position: absolute;
inset: 0;
z-index: -1;
content: '';
background: linear-gradient(-45deg, #ff3d00 0%, #0400ff 100%);
filter: blur(20px);
border-radius: inherit;
opacity: var(0.7);
transition: opacity 0.3s;
transform: translate3d(0, 20px, 0) scale(0.95);
}
/**
* Prevents issues when the parent creates a stacking context:
* For example, using the `transform` property.
*/
.box::after {
position: absolute;
inset: 0;
z-index: -1;
content: '';
background: inherit;
border-radius: inherit;
}
Geometry and Shape
Pseudo Element Shape
.first-details-intro::after {
position: absolute;
top: 50%;
right: 0;
width: 0;
height: 0;
content: '';
border-top: 15px solid transparent;
border-right: 25px solid #fff;
border-bottom: 15px solid transparent;
}
Border Shape
Horizontal and Vertical Border
Separate set horizontal and vertical radius to make well-designed shapes:
.avatar-shape {
border-radius: 70% 30% 30% 70% / 60% 40% 60% 40%;
}
.avatar {
width: 100px;
height: 100px;
object-fit: cover;
border: solid deepskyblue;
border-radius: 50%;
animation: morph 6s paused linear;
}
@keyframes morph {
0% {
border-radius: 40% 60% 60% 40% / 60% 30% 70% 40%;
transform: rotate(-5deg);
}
100% {
border-radius: 40% 60%;
transform: rotate(5deg);
}
}
.avatar:nth-child(4n) {
animation-delay: -3.5s;
}
.avatar:nth-child(2n + 1) {
animation-delay: -1s;
}
.avatar:nth-child(3n + 2) {
animation-delay: -2s;
}
.avatar:nth-child(5n + 3) {
animation-delay: -3s;
}
.avatar:nth-child(7n + 5) {
animation-delay: -4s;
}
.avatar:nth-child(11n + 7) {
animation-delay: -5s;
}
Transparent Border
Mix transparent
with non-transparent
border to make shapes (e.g. triangle):
.arrow-up {
width: 0;
height: 0;
border-right: 16px solid transparent;
border-bottom: 20px solid #8888e8;
border-left: 16px solid transparent;
}
.arrow-right {
width: 0;
height: 0;
border-top: 16px solid transparent;
border-bottom: 16px solid transparent;
border-left: 20px solid #e888a3;
}
.arrow-down {
width: 0;
height: 0;
border-top: 20px solid #f7df6c;
border-right: 16px solid transparent;
border-left: 16px solid transparent;
}
.arrow-left {
width: 0;
height: 0;
border-top: 16px solid transparent;
border-right: 20px solid #8de698;
border-bottom: 16px solid transparent;
}
Background Shape
.btn-add,
.btn-sub {
width: 1.5rem;
height: 1.5rem;
color: dimgray;
background:
linear-gradient(currentcolor, currentcolor) no-repeat center / 0.875em 2px,
linear-gradient(currentcolor, currentcolor) no-repeat center / 2px 0.875em;
border: 1px solid gray;
}
.btn-sub {
background-size:
0.875em 2px,
0;
}
.square {
width: 304px;
height: 160px;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%);
background-position:
0 0,
8px 8px;
background-size: 16px 16px;
}
Stretch Line
background
line.border
line.- Pseudo element with
line-through
text-decoration
.
.line {
width: 70%;
height: 10px;
background-color: #000;
}
.line,
.line-background {
background: linear-gradient(#000, #000) 50% / 70% 10px no-repeat;
}
.line,
.line-border {
border-top: 10px solid #000;
}
.line,
.line::after {
/* set thickness */
font-size: 5em;
/* hide content */
color: transparent;
text-decoration: line-through #000;
/* control line length */
content: '_______';
}
Dash Line
background
dash line.border
dash line.- Pseudo element with
dashed
text-decoration
.
.dash-background {
background: linear-gradient(to left, #000 70%, transparent 0);
background-repeat: repeat-x;
background-size: 30px 10px;
}
.dash-border {
border-top: 10px dashed #000;
}
.dash::after {
text-decoration-style: dashed;
}
Bar Line
Background gradient bar:
.bars {
--color: no-repeat linear-gradient(#000 0 0);
width: 45px;
aspect-ratio: 1;
background:
var(--color) 0% 50%,
var(--color) 50% 50%,
var(--color) 100% 50%;
background-size: 20% 100%; /* 20% * (3 bars + 2 spaces) = 100% */
}
Grid pseudo element border bar:
.loader {
--size: 100px; /* control the size */
display: grid;
place-content: center;
place-items: center;
margin: 0 calc(var(--size) / 2); /* 50px */
}
.loader::before,
.loader::after {
grid-area: 1 / 1;
content: '';
}
.loader,
.loader::before,
.loader::after {
width: calc(var(--size) / 5); /* 20px */
height: var(--size);
border-radius: var(--size);
transform: translate(calc(var(--index, 0) * 200%));
}
.loader::before {
--index: -1;
}
.loader::after {
--index: 1;
}
Wave line
Rotate border wave:
<div class="container">
<div class="wave"></div>
<p>45%</p>
</div>
<style>
.container {
width: 200px;
height: 200px;
overflow: hidden;
border-radius: 50%;
}
.wave {
position: relative;
width: 200px;
height: 200px;
background-color: rgb(118 218 255);
border-radius: 50%;
}
.wave::before,
.wave::after {
position: absolute;
top: 0;
left: 50%;
z-index: 1;
width: 400px;
height: 400px;
content: '';
background-color: rgb(255 255 255 / 40%);
border-radius: 45%;
transform: translate(-50%, -70%) rotate(0);
animation: rotate 6s linear infinite;
}
.wave::after {
z-index: 2;
background-color: rgb(255 255 255 / 90%);
border-radius: 47%;
transform: translate(-50%, -70%) rotate(0);
animation: rotate 10s linear -5s infinite;
}
@keyframes rotate {
50% {
transform: translate(-50%, -73%) rotate(180deg);
}
100% {
transform: translate(-50%, -70%) rotate(360deg);
}
}
</style>
Menu Line
.icon-menu {
display: inline-block;
width: 140px;
height: 10px;
/* Line gap */
padding: 35px 0;
/* Line 2 */
background-color: currentcolor;
background-clip: content-box;
/* Line 1 */
border-top: 10px solid;
/* Line 3 */
border-bottom: 10px solid;
}
Grid Line
background-image
for line color,background-size
for line gap.
.grid-line {
background-color: #fff;
background-image: linear-gradient(var(--line-color) 1px, transparent 0),
linear-gradient(90deg, var(--line-color) 1px, transparent 0);
background-size: 10px 10px;
border-top: 1px solid #e5e8eb;
border-bottom: 1px solid #e5e8eb;
box-shadow:
inset 0 15px 20px -15px #f6f7f9,
inset -5px -15px 20px -15px #f6f7f9;
}
/**
* @see {@link play.csssecrets.io/blueprint}
*/
.nest-grid-line {
background: #58a;
background-image: linear-gradient(var(--primary-line-color) 2px, transparent 0),
linear-gradient(90deg, var(--primary-line-color) 2px, transparent 0),
linear-gradient(var(--secondary-line-color) 1px, transparent 0),
linear-gradient(90deg, var(--secondary-line-color) 1px, transparent 0);
background-size:
75px 75px,
75px 75px,
15px 15px,
15px 15px;
}
Spinner
- Rotate conic gradient.
- Rotate border.
Background gradient loading spinner:
.loading-ring {
--mask: radial-gradient(closest-side, transparent 75%, black 76%);
width: 100px;
height: 100px;
background: conic-gradient(deepskyblue, 30%, white);
border-radius: 50%;
mask-image: var(--mask);
animation: spin 1s linear infinite reverse;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
More spinner see SpinKit.
Dot
Border Dot
background
and border
dot:
.icon-dot {
display: inline-block;
width: 100px;
height: 100px;
/* Cycle gap */
padding: 10px;
/* Cycle shape */
background-color: currentcolor;
background-clip: content-box;
/* Cycle ring */
border: 10px solid;
border-radius: 50%;
}
Gradient Dot
/**
* @see {@link play.csssecrets.io/polka}
*/
.dot {
background: #655;
background-image: radial-gradient(tan 30%, transparent 0);
background-size: 30px 30px;
}
repeating-radial-gradient
dot:
@property --length {
syntax: '<length>';
inherits: false;
initial-value: 0.0008px;
}
/* TV snowflake noise signal screen effect (雪花屏效果) */
div {
background-image: repeating-radial-gradient(
circle at 17% 32%,
rgb(4 4 0),
rgb(52 72 197),
rgb(115 252 224),
rgb(116 71 5),
rgb(223 46 169),
rgb(0 160 56),
rgb(234 255 0) var(--length)
);
animation: change 1s infinite alternate;
}
@keyframes change {
100% {
--length: 0.0009px;
}
}
Circle
background
circle.border
circle.clip-path
circle.- Pseudo element circle.
.circle-background {
background-image: radial-gradient(#000 72%, transparent 0);
}
.circle-background-corner {
background: #58a;
background:
radial-gradient(circle at top left, transparent 15px, #58a 0) top left,
radial-gradient(circle at top right, transparent 15px, #58a 0) top right,
radial-gradient(circle at bottom right, transparent 15px, #58a 0) bottom right,
radial-gradient(circle at bottom left, transparent 15px, #58a 0) bottom left;
background-repeat: no-repeat;
background-size: 50% 50%;
}
.circle-border {
overflow: hidden;
border-radius: 50%;
}
.circle-clip-path {
clip-path: circle(50%);
}
.circle::after {
font-size: 120vw;
line-height: 0;
content: '·';
}
Ellipse
/**
* @see {@link play.csssecrets.io/half-ellipse}
* @see {@link play.csssecrets.io/quarter-ellipse}
*/
.ellipse {
border-radius: 50% / 50%;
border-radius: 50% / 100% 100% 0 0;
border-radius: 50% / 0 0 100% 100%;
border-radius: 100% 0 0 100% / 50%;
border-radius: 0 100% 100% 0 / 50%;
border-radius: 100% 0 0;
border-radius: 0 100% 0 0;
border-radius: 0 0 100%;
border-radius: 0 0 0 100%;
}
Triangle
background
triangle.border
triangle.clip-path
triangle.- Pseudo element triangle.
Background gradient triangle:
.triangle {
background: linear-gradient(45deg, #000 50%, transparent 0);
}
/**
* @see {@link https://codepen.io/Chokcoco/pen/BGeJGm}
*/
.arrow {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
height: 40px;
font-size: 200%;
color: white;
text-align: center;
background:
linear-gradient(-135deg, transparent 10%, #04e6fb 10%, #65ff9a 100%) top right,
linear-gradient(-45deg, transparent 10%, #04e6fb 10%, #65ff9a 100%) bottom right,
linear-gradient(-135deg, #04e6fb 0, #65ff9a 90%, transparent 90%) top left,
linear-gradient(-45deg, #04e6fb 0, #65ff9a 90%, transparent 90%) bottom left;
background-repeat: no-repeat;
background-size: 90% 50%;
transform: translate(-50%, -50%);
}
/**
* @see {@link play.csssecrets.io/folded-corner-realistic}
*/
.note {
position: relative;
background: #58a; /* 回退样式 */
background: linear-gradient(-150deg, transparent 1.5em, #58a 0);
}
.note::before {
position: absolute;
top: 0;
right: 0;
width: 1.73em;
height: 3em;
content: '';
background: linear-gradient(to left bottom, transparent 50%, rgb(0 0 0 / 20%) 0, rgb(0 0 0 / 40%)) 100% 0 no-repeat;
transform: translateY(-1.3em) rotate(-30deg);
transform-origin: bottom right;
}
Border triangle:
/* transparent border */
.arrow-up {
width: 0;
height: 0;
border-right: 16px solid transparent;
border-bottom: 20px solid #8888e8;
border-left: 16px solid transparent;
}
Clip path triangle:
/* clip path */
.arrow-right {
width: 20px;
height: 32px;
clip-path: polygon(0 0, 0 100%, 100% 50%);
background-color: #e888a3;
}
Pseudo element triangle:
/* pseudo element + hidden overflow */
.arrow-down {
position: relative;
width: 40px;
height: 40px;
overflow: hidden;
}
.arrow-down::before {
position: absolute;
top: 0;
left: 0;
display: block;
width: calc(40px / 1.41);
height: calc(40px / 1.41);
content: '';
background: #f7df6c;
transform: rotate(-45deg);
transform-origin: 0 0;
}
/**
* pseudo element + HTML5 entities:
* ◄ : ◄
* ► : ►
* ▼ : ▼
* ▲ : ▲
*/
.arrow::before {
content: '▼';
}
Square
Background gradient square shape:
.checkerboard-linear-gradient {
background: #eee;
background-image: linear-gradient(45deg, rgb(0 0 0 / 25%) 25%, transparent 0 75%, rgb(0 0 0 / 25%) 0),
linear-gradient(45deg, rgb(0 0 0 / 25%) 25%, transparent 0 75%, rgb(0 0 0 / 25%) 0);
background-position:
0 0,
15px 15px;
background-size: 30px 30px;
}
.checkerboard-conic-gradient {
background: repeating-conic-gradient(#bbb 0, #bbb 25%, #eee 0, #eee 50%);
background-size: 30px 30px;
}
Polygon
Gradient Polygon
Background gradient polygon:
/**
* @see {@link play.csssecrets.io/bevel-corners-gradients}
*/
.polygon-background-corner {
background: #58a;
background:
linear-gradient(135deg, transparent 15px, #58a 0) top left,
linear-gradient(-135deg, transparent 15px, #58a 0) top right,
linear-gradient(-45deg, transparent 15px, #58a 0) bottom right,
linear-gradient(45deg, transparent 15px, #58a 0) bottom left;
background-repeat: no-repeat;
background-size: 50% 50%;
}
Clip Path Polygon
clip-path
polygon:
.polygon {
/* 菱形 */
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
/* 矩形箭头 */
clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 25% 50%, 0% 0%);
/* 八边形 */
clip-path: polygon(
20px 0,
calc(100% - 20px) 0,
100% 20px,
100% calc(100% - 20px),
calc(100% - 20px) 100%,
20px 100%,
0 calc(100% - 20px),
0 20px
);
}
function polygon(n = 3) {
const deg = (2 * Math.PI) / n
const points = []
for (let i = 0; i < n; ++i) {
const theta = deg * i
const x = `${50 * Math.cos(theta) + 50}%`
const y = `${50 * Math.sin(theta) + 50}%`
points.push(`${x} ${y}`)
}
return `polygon(${points.join(',')})`
}
Transform Polygon
transform
polygon:
/* 平行四边形 */
.button::before {
position: absolute;
inset: 0;
z-index: -1;
content: ''; /* 用伪元素来生成一个矩形 */
background: #58a;
transform: skew(45deg);
}
/* 梯形 */
.tab::before {
position: absolute;
inset: 0;
z-index: -1;
content: ''; /* 用伪元素来生成一个矩形 */
background: #58a;
transform: scaleY(1.3) perspective(0.5em) rotateX(5deg);
transform-origin: bottom;
}
Filter and Blend Effects
Dark Mode Effect
html[theme='dark'] {
filter: invert(1) hue-rotate(180deg);
}
html[theme='dark'] img {
filter: invert(1) hue-rotate(180deg);
}
html {
transition:
color 300ms,
background-color 300ms;
}
Fusion Effect
- Parent element:
background-color
+filter: contrast()
. - Child element:
filter: blur()
.
Light, flame, rain drop emulation:
<div class="container">
<div class="circle circle-1"></div>
<div class="circle circle-2"></div>
</div>
<style>
.container {
background: #fff; /* Required */
filter: contrast(30);
}
.circle {
filter: blur(10px);
}
</style>
Frosted Glass Effect
毛玻璃效果 (bg-white/30 shadow-lg backdrop-blur-sm
):
body {
background-image: url('https://images.unsplash.com/image');
background-position: center;
}
.card {
background-color: rgb(17 25 40 / 54%);
backdrop-filter: blur(12px) saturate(200%);
border: 1px solid rgb(255 255 255 / 12.5%);
border-radius: 12px;
}
.hero {
--inset-shadow: inset 0 0 1px 1px hsl(204deg 100% 90% / 100%);
--shadow: 10px 10px 60px 20px hsl(194deg 100% 9% / 50%);
background-color: hsl(27deg 10% 90% / 90%);
border: 1px solid hsl(176deg 87% 7% / 60%);
border-radius: 5px;
box-shadow: var(--inset-shadow), var(--shadow);
}
@supports (backdrop-filter: blur(25px) brightness(170%)) {
.hero {
background-color: hsl(27deg 10% 90% / 50%);
backdrop-filter: blur(25px) brightness(170%);
}
}
Gradient Text Effect
.gradient-text {
position: relative;
color: black;
background: #fff;
}
.gradient-text::before {
position: absolute;
inset: 0;
content: '';
background: linear-gradient(to right, deepskyblue, deeppink);
mix-blend-mode: lighten;
}
.gradient-stroked-text {
position: relative;
color: #191325;
text-shadow:
1px 1px #fff,
-1px -1px #fff,
1px -1px #fff,
-1px 1px #fff;
background: #191325;
}
.gradient-stroked-text::after {
position: absolute;
inset: 0;
content: '';
background: linear-gradient(315deg, #78e56c, #127ac9);
mix-blend-mode: darken;
}
/**
* @see {@link https://codepen.io/Chokcoco/pen/jOwEqvR}
*/
.gradient-wave-text {
position: relative;
overflow: hidden;
font-size: 120px;
font-weight: bold;
color: #000;
background: #fff;
}
.gradient-wave-text::before,
.gradient-wave-text::after {
position: absolute;
top: -923px;
left: 50%;
z-index: 1;
width: 2000px;
height: 2000px;
content: '';
background: rgb(3 169 244 / 85%);
border-radius: 45% 48% 43% 47%;
mix-blend-mode: lighten;
transform: translate(-50%, -50%);
animation: rotate 10s infinite linear;
}
.gradient-wave-text::after {
border-radius: 43% 47% 44% 48%;
animation: rotate 10s infinite 0.5s linear;
}
@keyframes rotate {
0% {
transform: translate(-50%, -50%) rotate(0);
}
100% {
transform: translate(-50%, -50%) rotate(360deg);
}
}
Sun Effect
.sun-rise {
filter: contrast(0.34) brightness(1.6) sepia(1) hue-rotate(10deg);
filter: sepia(1) saturate(4) hue-rotate(295deg);
}
Night Effect
.night {
background: rgb(0 40 140 / 60%), url('./house-bed.jpg');
filter: brightness(80%) grayscale(20%) contrast(1.2);
background-size: 100%;
background-blend-mode: darken;
}
Movie Effect
.movie {
filter: contrast(1.1);
background-blend-mode: soft-light;
}
Old Effect
.old-1977 {
position: relative;
filter: contrast(1.1) brightness(1.1) saturate(1.3);
}
.old-1977::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
content: '';
background: rgb(243 106 188 / 30%);
mix-blend-mode: screen;
}
Sketch Effect
.sketch {
width: 256px;
height: 171px;
background:
url('10.jpg') -2px -2px,
url('10.jpg');
filter: brightness(3) invert(1) grayscale(1);
background-size: 258px 173px;
background-blend-mode: difference;
}
Animation
Animated Dots
.dot {
display: inline-block;
height: 1em;
overflow: hidden;
line-height: 1;
text-align: left;
vertical-align: -0.25ex;
}
@media only screen and (prefers-reduced-motion: no-preference) {
.dot::before {
animation: dot1 3s infinite step-start both;
}
}
.dot::before {
display: block;
white-space: pre-wrap;
content: '...\A..\A.';
}
@keyframes dot1 {
33% {
transform: translateY(-2em);
}
66% {
transform: translateY(-1em);
}
}
Hover Animation
- Hover button effects using background.
- Hover button effects using text shadow.
- Hover button effects using clip and mask.
Fade Animation
Visual Fade Animation
.dropdown-drawer {
visibility: hidden;
opacity: 0;
transition:
opacity 0.2s linear,
visibility 0s linear 0.2s;
}
.is-open .dropdown-drawer {
visibility: visible;
opacity: 1;
transition-delay: 0s;
}
Fade In Animation
@keyframes fade-in {
from {
opacity: 0;
transform: rotateX(-90deg);
}
to {
opacity: 1;
transform: rotateX(0deg);
}
}
Fade In Out Animation
@keyframes fade-in-out {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
Fade Mask Animation
p {
margin: auto;
font-family: 'Reggae One', cursive;
font-size: 48px;
color: #fff;
mask: radial-gradient(circle at 0 50%, #000, transparent 10%, transparent 0);
mask-size: 100%;
animation: scale 5s infinite;
}
.radial {
mask: radial-gradient(circle at 50% 0, #000, transparent 20%, transparent 0);
mask-size: 100% 100%;
animation: scale 5s infinite;
}
@keyframes scale {
50%,
100% {
mask-size: 100% 2000%;
}
}
Bounce Animation
/* transform-origin: top center */
@keyframes bounce-in {
0% {
opacity: 0;
transform: scale(0.5) translateY(-30px);
}
80% {
opacity: 1;
transform: scale(1.2);
}
100% {
opacity: 1;
transform: rotateY(0) translateY(0);
}
}
Rotate Animation
Rotate In Animation
/* transform-origin: top center */
@keyframes horizontal-rotate-in {
0% {
opacity: 0;
transform: rotateY(-90deg) translateY(30px);
}
100% {
opacity: 1;
transform: rotateY(0) translateY(0);
}
}
/* transform-origin: top right */
@keyframes rotate-right-in {
0% {
opacity: 0;
transform: rotate(-30deg) translateX(30px);
}
100% {
opacity: 1;
transform: rotate(0) translateX(0);
}
}
Circular Spin Animation
/**
* @see {@link play.csssecrets.io/circular}
*/
@keyframes spin {
from {
transform: rotate(0turn) translateY(-150px) translateY(50%) rotate(1turn);
}
to {
transform: rotate(1turn) translateY(-150px) translateY(50%) rotate(0turn);
}
}
.avatar {
width: 50px;
overflow: hidden;
border-radius: 50%;
animation: spin 3s infinite linear;
}
Fold Flip Animation
/* transform-origin: top center */
@keyframes fold-flip {
0% {
opacity: 0;
transform: rotateX(-90deg);
}
60% {
transform: rotateX(50deg);
}
100% {
opacity: 1;
transform: rotateX(0);
}
}
Accordion Animation
@media only screen and (prefers-reduced-motion: reduce) {
.menu {
transition: none;
}
}
.menu {
max-height: 0;
overflow: hidden;
opacity: 0;
transition:
max-height 0.3s,
opacity 0.3s;
}
.menu:focus-within,
.container:hover .menu {
max-height: 1em;
opacity: 1;
}
Slides Animation
.slide {
width: 500%;
overflow: hidden;
}
@keyframes slide {
0% {
margin-left: 0;
}
10% {
margin-left: 0;
}
12% {
margin-left: -100%;
}
22% {
margin-left: -100%;
}
24% {
margin-left: -200%;
}
34% {
margin-left: -200%;
}
36% {
margin-left: -300%;
}
46% {
margin-left: -300%;
}
48% {
margin-left: -400%;
}
58% {
margin-left: -400%;
}
60% {
margin-left: -300%;
}
70% {
margin-left: -300%;
}
72% {
margin-left: -200%;
}
82% {
margin-left: -200%;
}
84% {
margin-left: -100%;
}
94% {
margin-left: -100%;
}
96% {
margin-left: 0;
}
}
Scale Up Animation
@media only screen and (prefers-reduced-motion: reduce) {
.div {
transition: none;
}
}
.div {
transition: transform 0.5s ease;
transform: scaleX(0);
}
.div:hover,
.div:focus {
transform: scaleX(1);
}
Clear Splash Animation
.cube {
transform: translate3d(0, 0, 0);
perspective: 1000;
backface-visibility: hidden;
transform-style: preserve-3d;
}
Tooltip Animation
@keyframes tooltip {
0% {
opacity: 0;
transform: scale(0.1) rotate(30deg) translateY(50px) rotateX(90deg);
}
50% {
opacity: 1;
transform: rotate(-10deg) rotateX(-2deg);
}
70% {
transform: rotate(3deg);
}
100% {
transform: scale(1);
}
}
Breath Animation
.breath {
animation: breath 7s infinite;
}
@keyframes breath {
0%,
100% {
opacity: 0;
}
70% {
opacity: 1;
}
}
Pulse Animation
@keyframes radial-pulse {
0% {
box-shadow: 0 0 0 0 rgb(0 0 0 / 50%);
}
100% {
box-shadow: 0 0 0 30px rgb(0 0 0 / 0%);
}
}
/* origin opacity is 0 */
@keyframes pulse {
0% {
opacity: 1;
transform: scale(0);
}
100% {
opacity: 0;
transform: scale(1.3);
}
}
Clock Animation
.clock-pendulum {
transform-origin: top;
animation: pendulum 1s infinite alternate ease-in-out;
}
@keyframes pendulum {
0% {
transform: rotate(-10deg);
}
100% {
transform: rotate(10deg);
}
}
Typing Animation
@keyframes typing {
from {
width: 0;
}
}
@keyframes caret {
50% {
border-right-color: transparent;
}
}
h1 {
width: 15ch;
overflow: hidden;
font:
bold 200% Consolas,
Monaco,
monospace;
white-space: nowrap;
border-right: 0.05em solid;
animation:
typing 8s steps(15),
caret 1s steps(1) infinite;
}
CSS Components Reference
- CSS tricks.
- CSS inspiration.
- Gallery for background patterns.
- Modern CSS shapes.
- Pure CSS icons.