Inspire.js
Lean, hackable, extensible slide deck framework. Create basic slides by just writing HTML and CSS, do fancy custom stuff with JS, the sky is the limit!
Getting started
HTML
<span class="loader"></span>
CSS
.loader {
width: 48px;
height: 48px;
border: 5px solid #FFF;
border-bottom-color: #FF3D00;
border-radius: 50%;
display: inline-block;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
hfghfghfghfghhfghfg
CDN
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>加载动画生成器 - 动画速度修复版</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 30px;
color: #2c3e50;
}
h2 {
margin: 25px 0 15px;
color: #3498db;
border-bottom: 1px solid #ddd;
padding-bottom: 8px;
}
.templates {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 15px;
margin-bottom: 30px;
}
@media (max-width: 1000px) {
.templates {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 600px) {
.templates {
grid-template-columns: repeat(2, 1fr);
}
}
.template {
background: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: all 0.3s;
text-align: center;
}
.template:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.template.active {
border: 2px solid #3498db;
background: #e8f4fd;
}
.template-preview {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10px;
}
.template-name {
font-size: 14px;
font-weight: 500;
}
.generator {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
@media (max-width: 900px) {
.generator {
grid-template-columns: 1fr;
}
}
.panel {
background: white;
border-radius: 10px;
padding: 25px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.preview-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 200px;
margin-bottom: 20px;
border: 1px dashed #ccc;
border-radius: 8px;
padding: 20px;
}
.controls {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
.control-group {
margin-bottom: 20px;
}
.control-group h3 {
margin-bottom: 10px;
font-size: 16px;
color: #2c3e50;
}
.control-row {
display: flex;
align-items: center;
margin-bottom: 10px;
}
label {
flex: 1;
font-weight: 500;
font-size: 14px;
}
input[type="range"] {
flex: 2;
margin: 0 10px;
}
.value-display {
width: 60px;
text-align: center;
font-family: monospace;
font-size: 14px;
}
input[type="color"] {
width: 40px;
height: 30px;
border: none;
border-radius: 5px;
cursor: pointer;
}
select {
padding: 5px;
border-radius: 5px;
border: 1px solid #ddd;
}
.code-container {
background: #2d2d2d;
border-radius: 5px;
padding: 15px;
margin-top: 20px;
overflow-x: auto;
}
pre {
color: #f8f8f2;
white-space: pre-wrap;
font-family: 'Fira Code', monospace;
font-size: 13px;
}
.comment { color: #75715e; }
.selector { color: #a6e22e; }
.property { color: #66d9ef; }
.value { color: #ae81ff; }
.export-btn {
display: block;
width: 100%;
padding: 12px;
background: #3498db;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
margin-top: 20px;
transition: background 0.3s;
}
.export-btn:hover {
background: #2980b9;
}
/* 加载动画样式 */
.loader {
font-weight: bold;
font-family: sans-serif;
font-size: 20px;
}
.loader:before {
content: "Loading...";
}
/* 方案1 */
.loader-1 {
animation: l1 1s linear infinite alternate;
}
@keyframes l1 {to{opacity: 0}}
/* 方案2 */
.loader-2 {
width: fit-content;
padding-bottom: 8px;
background: linear-gradient(currentColor 0 0) 0 100%/0% 3px no-repeat;
animation: l2 2s linear infinite;
}
@keyframes l2 {to{background-size: 100% 3px}}
/* 方案3 */
.loader-3 {
width: fit-content;
padding: 0 5px 8px 0;
background: repeating-linear-gradient(90deg,currentColor 0 8%,#0000 0 10%) 200% 100%/200% 3px no-repeat;
animation: l3 2s steps(6) infinite;
}
@keyframes l3 {to{background-position: 80% 100%}}
/* 方案4 */
.loader-4 {
width: fit-content;
font-family: monospace;
clip-path: inset(0 3ch 0 0);
animation: l4 1s steps(4) infinite;
}
@keyframes l4 {to{clip-path: inset(0 -1ch 0 0)}}
/* 方案5 */
.loader-5 {
width: fit-content;
font-family: monospace;
clip-path: inset(0 100% 0 0);
animation: l5 2s steps(11) infinite;
}
@keyframes l5 {to{clip-path: inset(0 -1ch 0 0)}}
/* 方案6 */
.loader-6 {
--c:#000;
width: fit-content;
font-family: monospace;
color: #0000;
overflow: hidden;
text-shadow: 0 0 var(--c),11ch 0 var(--c);
animation: l6 2s infinite linear;
}
@keyframes l6 {to{text-shadow:-11ch 0 var(--c),0ch 0 var(--c)}}
/* 方案7 */
.loader-7 {
width: fit-content;
font-family: monospace;
color: #0000;
background: linear-gradient(90deg,#C02942 calc(50% + 0.5ch),#000 0) right/calc(200% + 1ch) 100%;
-webkit-background-clip: text;
background-clip: text;
animation: l7 2s infinite steps(11);
}
@keyframes l7 {to{background-position: left}}
/* 方案8 */
.loader-8 {
width: fit-content;
font-family: monospace;
color:#0000;
background:linear-gradient(90deg,#000 calc(50% - 0.5ch),#C02942 0 calc(50% + 0.5ch),#000 0) right/calc(200% + 1ch) 100%;
-webkit-background-clip:text;
background-clip:text;
animation: l8 2s infinite steps(11);
}
@keyframes l8 {to{background-position: left}}
/* 方案9 */
.loader-9 {
width: fit-content;
font-family: monospace;
color :#0000;
overflow: hidden;
animation: l9 5s infinite cubic-bezier(0.3,1,0,1);
}
@keyframes l9 {
0% {text-shadow: 0 0 #000, 11ch 0 #8A9B0F, 22ch 0 #C02942, 33ch 0 #00A0B0,44ch 0 #000}
25% {text-shadow:-11ch 0 #000, 0 0 #8A9B0F, 11ch 0 #C02942, 22ch 0 #00A0B0,33ch 0 #000}
50% {text-shadow:-22ch 0 #000,-11ch 0 #8A9B0F, 0 0 #C02942, 11ch 0 #00A0B0,22ch 0 #000}
75% {text-shadow:-33ch 0 #000,-22ch 0 #8A9B0F,-11ch 0 #C02942, 0 0 #00A0B0,11ch 0 #000}
100%{text-shadow:-44ch 0 #000,-33ch 0 #8A9B0F,-22ch 0 #C02942,-11ch 0 #00A0B0,0 0 #000}
}
/* 方案10 */
.loader-10 {
width: fit-content;
font-family: monospace;
color:#0000;
background: linear-gradient(90deg,#000 25%,#8A9B0F 0 50%,#C02942 0 75%,#00A0B0 0) 0 0/400% 100%;
-webkit-background-clip:text;
background-clip:text;
animation:l10 5s infinite cubic-bezier(0.3,1,0,1);
}
@keyframes l10 {
25% {background-position: calc(1*100%/3) 0}
50% {background-position: calc(2*100%/3) 0}
75% {background-position: calc(3*100%/3) 0}
100%{background-position: calc(4*100%/3) 0}
}
/* 方案11 */
.loader-11 {
font-family: monospace;
display: inline-grid;
}
.loader-11:before,
.loader-11:after {
content:"Loading...";
grid-area: 1/1;
-webkit-mask:linear-gradient(90deg,#000 50%,#0000 0) 0 50%/2ch 100%;
animation: l11 1s infinite cubic-bezier(0.5,220,0.5,-220);
}
.loader-11:after {
-webkit-mask-position:1ch 50%;
--s:-1;
}
@keyframes l11 {100%{transform: translateY(calc(var(--s,1)*0.1%));}}
/* 方案12 */
.loader-12 {
font-family: monospace;
display: inline-grid;
overflow: hidden;
}
.loader-12:before,
.loader-12:after {
content: "Loading...";
grid-area: 1/1;
clip-path: inset(0 -200% 50%);
text-shadow: -10ch 0 0;
animation: l12 1s infinite;
}
.loader-12:after {
clip-path: inset(50% -200% 0%);
text-shadow: 10ch 0 0;
--s:-1;
}
@keyframes l12 {50%,100%{transform: translateX(calc(var(--s,1)*100%));}}
/* 方案13 */
.loader-13 {
font-family: monospace;
display: inline-grid;
overflow: hidden;
}
.loader-13:before,
.loader-13:after {
content: "Loading...";
grid-area: 1/1;
clip-path: inset(0 -200% 50%);
text-shadow: -10ch 0 0;
animation: l13 2s infinite;
}
.loader-13:after {
clip-path: inset(50% -200% 0%);
text-shadow: 10ch 0 0;
--s:-1;
animation-delay: 1s;
}
@keyframes l13 {25%,100%{transform: translateX(calc(var(--s,1)*100%));}}
/* 方案14 */
.loader-14 {
width: fit-content;
padding-bottom: 5px;
font-family: monospace;
overflow: hidden;
color: #0000;
text-shadow: 0 0 0 #000,10ch 0 0 #000;
background: linear-gradient(#000 0 0) bottom left/0% 3px no-repeat;
animation: l14 1.5s infinite;
}
@keyframes l14 {
80% {text-shadow: 0 0 0 #000,10ch 0 0 #000;background-size:100% 3px}
100% {text-shadow: -10ch 0 0 #000,0 0 0 #000}
}
/* 方案15 */
.loader-15 {
font-family: monospace;
line-height: 1.2em;
display: inline-grid;
}
.loader-15:before,
.loader-15:after {
content:"Loading...";
grid-area: 1/1;
-webkit-mask: linear-gradient(90deg,#000 50%,#0000 0) 0 50%/2ch 100%;
color: #0000;
text-shadow: 0 0 0 #000,0 calc(var(--s,1)*1.2em) 0 #000;
animation: l15 1s infinite;
}
.loader-15:after {
-webkit-mask-position: 1ch 50%;
--s:-1;
}
@keyframes l15 {80%,100%{text-shadow:0 calc(var(--s,1)*-1.2em) 0 #000,0 0 0 #000}}
/* 方案16 */
.loader-16 {
--w:10ch;
font-family: monospace;
letter-spacing: var(--w);
width:var(--w);
overflow: hidden;
white-space: nowrap;
text-shadow:
calc(-1*var(--w)) 0,
calc(-2*var(--w)) 0,
calc(-3*var(--w)) 0,
calc(-4*var(--w)) 0,
calc(-5*var(--w)) 0,
calc(-6*var(--w)) 0,
calc(-7*var(--w)) 0,
calc(-8*var(--w)) 0,
calc(-9*var(--w)) 0;
animation: l16 2s infinite;
}
@keyframes l16 {
20% {text-shadow:
calc(-1*var(--w)) 0,
calc(-2*var(--w)) 0 red,
calc(-3*var(--w)) 0,
calc(-4*var(--w)) 0 #ffa516,
calc(-5*var(--w)) 0 #63fff4,
calc(-6*var(--w)) 0,
calc(-7*var(--w)) 0,
calc(-8*var(--w)) 0 green,
calc(-9*var(--w)) 0;}
40% {text-shadow:
calc(-1*var(--w)) 0,
calc(-2*var(--w)) 0 red,
calc(-3*var(--w)) 0 #e945e9,
calc(-4*var(--w)) 0,
calc(-5*var(--w)) 0 green,
calc(-6*var(--w)) 0 orange,
calc(-7*var(--w)) 0,
calc(-8*var(--w)) 0 green,
calc(-9*var(--w)) 0;}
60% {text-shadow:
calc(-1*var(--w)) 0 lightblue,
calc(-2*var(--w)) 0,
calc(-3*var(--w)) 0 #e945e9,
calc(-4*var(--w)) 0,
calc(-5*var(--w)) 0 green,
calc(-6*var(--w)) 0,
calc(-7*var(--w)) 0 yellow,
calc(-8*var(--w)) 0 #ffa516,
calc(-9*var(--w)) 0 red;}
80% {text-shadow:
calc(-1*var(--w)) 0 lightblue,
calc(-2*var(--w)) 0 yellow,
calc(-3*var(--w)) 0 #63fff4,
calc(-4*var(--w)) 0 #ffa516,
calc(-5*var(--w)) 0 red,
calc(-6*var(--w)) 0,
calc(-7*var(--w)) 0 grey,
calc(-8*var(--w)) 0 #63fff4,
calc(-9*var(--w)) 0 ;}
}
</style>
</head>
<body>
<h1>加载动画生成器 - 动画速度修复版</h1>
<div class="container">
<h2>选择加载动画模板</h2>
<div class="templates" id="templates">
<!-- 模板将通过JS动态生成 -->
</div>
<h2>自定义设置</h2>
<div class="generator">
<div class="panel">
<div class="preview-container">
<div class="loader loader-1" id="previewLoader"></div>
</div>
<button class="export-btn" id="exportBtn">复制CSS代码</button>
<div class="code-container">
<pre id="cssCode"><code><span class="comment">/* 生成的CSS代码 */</span>
<span class="selector">.loader</span> {
<span class="property">font-weight</span>: <span class="value" id="code-font-weight">bold</span>;
<span class="property">font-family</span>: <span class="value" id="code-font-family">sans-serif</span>;
<span class="property">font-size</span>: <span class="value" id="code-font-size">30px</span>;
<span class="property">animation</span>: <span class="value" id="code-animation">l1 1s linear infinite alternate</span>;
}
<span class="selector">.loader:before</span> {
<span class="property">content</span>: <span class="value">"Loading..."</span>;
}
<span class="selector">@keyframes l1</span> {
<span class="selector">to</span> { <span class="property">opacity</span>: <span class="value">0</span>; }
}</code></pre>
</div>
</div>
<div class="panel">
<h2>参数调整</h2>
<div class="controls">
<div class="control-group">
<h3>基本设置</h3>
<div class="control-row">
<label for="fontSize">字体大小:</label>
<input type="range" id="fontSize" min="10" max="50" value="30">
<span class="value-display" id="fontSizeValue">30px</span>
</div>
<div class="control-row">
<label for="fontWeight">字体粗细:</label>
<select id="fontWeight">
<option value="normal">普通</option>
<option value="bold" selected>加粗</option>
<option value="bolder">更粗</option>
<option value="lighter">更细</option>
</select>
</div>
<div class="control-row">
<label for="fontFamily">字体:</label>
<select id="fontFamily">
<option value="sans-serif" selected>无衬线</option>
<option value="monospace">等宽</option>
<option value="serif">衬线</option>
<option value="cursive">手写</option>
</select>
</div>
</div>
<div class="control-group">
<h3>颜色设置</h3>
<div class="control-row">
<label for="color">颜色:</label>
<input type="color" id="color" value="#000000">
</div>
</div>
<div class="control-group">
<h3>动画设置</h3>
<div class="control-row">
<label for="speed">动画速度:</label>
<input type="range" id="speed" min="0.5" max="5" step="0.1" value="1">
<span class="value-display" id="speedValue">1s</span>
</div>
<div class="control-row">
<label for="timing">时间函数:</label>
<select id="timing">
<option value="linear" selected>linear</option>
<option value="ease">ease</option>
<option value="ease-in">ease-in</option>
<option value="ease-out">ease-out</option>
<option value="ease-in-out">ease-in-out</option>
<option value="steps(4)">steps(4)</option>
<option value="cubic-bezier(0.3,1,0,1)">cubic-bezier</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// 当前选中的加载器类型
let currentLoaderType = 1;
// 模板数据
const templates = [
{ id: 1, name: "淡入淡出", class: "loader-1" },
{ id: 2, name: "下划线", class: "loader-2" },
{ id: 3, name: "点状下划线", class: "loader-3" },
{ id: 4, name: "打字效果1", class: "loader-4" },
{ id: 5, name: "打字效果2", class: "loader-5" },
{ id: 6, name: "滑动文本", class: "loader-6" },
{ id: 7, name: "渐变文本1", class: "loader-7" },
{ id: 8, name: "渐变文本2", class: "loader-8" },
{ id: 9, name: "多彩阴影", class: "loader-9" },
{ id: 10, name: "多彩渐变", class: "loader-10" },
{ id: 11, name: "弹跳效果", class: "loader-11" },
{ id: 12, name: "拆分滑动1", class: "loader-12" },
{ id: 13, name: "拆分滑动2", class: "loader-13" },
{ id: 14, name: "滑动下划线", class: "loader-14" },
{ id: 15, name: "上下跳动", class: "loader-15" },
{ id: 16, name: "多彩字母", class: "loader-16" }
];
// 初始化模板
function initTemplates() {
const templatesContainer = document.getElementById('templates');
templates.forEach(template => {
const templateElement = document.createElement('div');
templateElement.className = 'template';
templateElement.dataset.id = template.id;
templateElement.innerHTML = `
<div class="template-preview">
<div class="loader ${template.class}"></div>
</div>
<div class="template-name">${template.id}. ${template.name}</div>
`;
templateElement.addEventListener('click', () => {
setLoaderType(template.id);
});
templatesContainer.appendChild(templateElement);
});
// 默认选中第一个模板
setLoaderType(1);
}
// 设置加载器类型
function setLoaderType(type) {
currentLoaderType = type;
// 更新模板选中状态
document.querySelectorAll('.template').forEach(template => {
if (parseInt(template.dataset.id) === type) {
template.classList.add('active');
} else {
template.classList.remove('active');
}
});
// 更新预览
updatePreview();
}
// 更新预览
function updatePreview() {
const previewLoader = document.getElementById('previewLoader');
const fontSize = document.getElementById('fontSize').value;
const fontWeight = document.getElementById('fontWeight').value;
const fontFamily = document.getElementById('fontFamily').value;
const color = document.getElementById('color').value;
const speed = document.getElementById('speed').value;
const timing = document.getElementById('timing').value;
// 更新样式
previewLoader.style.fontSize = fontSize + 'px';
previewLoader.style.fontWeight = fontWeight;
previewLoader.style.fontFamily = fontFamily;
previewLoader.style.color = color;
// 更新类名
previewLoader.className = 'loader';
previewLoader.classList.add(`loader-${currentLoaderType}`);
// 创建动态样式来更新动画速度和时序函数
const styleId = 'loaderAnimationStyle';
let existingStyle = document.getElementById(styleId);
if (existingStyle) {
document.head.removeChild(existingStyle);
}
const style = document.createElement('style');
style.id = styleId;
// 为当前选定的加载器类型设置动画
style.textContent = `
#previewLoader {
animation: l${currentLoaderType} ${speed}s ${timing} infinite;
}
`;
document.head.appendChild(style);
// 更新代码显示
updateCodeDisplay();
}
// 更新代码显示
function updateCodeDisplay() {
const fontSize = document.getElementById('fontSize').value;
const fontWeight = document.getElementById('fontWeight').value;
const fontFamily = document.getElementById('fontFamily').value;
const speed = document.getElementById('speed').value;
const timing = document.getElementById('timing').value;
document.getElementById('code-font-size').textContent = `${fontSize}px`;
document.getElementById('code-font-weight').textContent = fontWeight;
document.getElementById('code-font-family').textContent = fontFamily;
document.getElementById('code-animation').textContent = `l${currentLoaderType} ${speed}s ${timing} infinite`;
// 根据不同的加载器类型更新代码
updateKeyframesCode();
}
// 更新关键帧代码
function updateKeyframesCode() {
const keyframesElement = document.querySelector('#cssCode .value:last-child');
if (!keyframesElement) return;
// 根据当前选择的加载器类型显示相应的关键帧代码
switch(currentLoaderType) {
case 1:
keyframesElement.textContent = "to { opacity: 0; }";
break;
case 2:
keyframesElement.textContent = "to { background-size: 100% 3px; }";
break;
case 3:
keyframesElement.textContent = "to { background-position: 80% 100%; }";
break;
case 4:
keyframesElement.textContent = "to { clip-path: inset(0 -1ch 0 0); }";
break;
case 5:
keyframesElement.textContent = "to { clip-path: inset(0 -1ch 0 0); }";
break;
case 6:
keyframesElement.textContent = "to { text-shadow: -11ch 0 var(--c), 0ch 0 var(--c); }";
break;
case 7:
keyframesElement.textContent = "to { background-position: left; }";
break;
case 8:
keyframesElement.textContent = "to { background-position: left; }";
break;
case 9:
keyframesElement.textContent = "0% { text-shadow: 0 0 #000, 11ch 0 #8A9B0F, 22ch 0 #C02942, 33ch 0 #00A0B0, 44ch 0 #000; }\n 25% { text-shadow: -11ch 0 #000, 0 0 #8A9B0F, 11ch 0 #C02942, 22ch 0 #00A0B0, 33ch 0 #000; }\n 50% { text-shadow: -22ch 0 #000, -11ch 0 #8A9B0F, 0 0 #C02942, 11ch 0 #00A0B0, 22ch 0 #000; }\n 75% { text-shadow: -33ch 0 #000, -22ch 0 #8A9B0F, -11ch 0 #C02942, 0 0 #00A0B0, 11ch 0 #000; }\n 100% { text-shadow: -44ch 0 #000, -33ch 0 #8A9B0F, -22ch 0 #C02942, -11ch 0 #00A0B0, 0 0 #000; }";
break;
case 10:
keyframesElement.textContent = "25% { background-position: calc(1*100%/3) 0; }\n 50% { background-position: calc(2*100%/3) 0; }\n 75% { background-position: calc(3*100%/3) 0; }\n 100% { background-position: calc(4*100%/3) 0; }";
break;
case 11:
keyframesElement.textContent = "100% { transform: translateY(calc(var(--s,1)*0.1%)); }";
break;
case 12:
keyframesElement.textContent = "50%, 100% { transform: translateX(calc(var(--s,1)*100%)); }";
break;
case 13:
keyframesElement.textContent = "25%, 100% { transform: translateX(calc(var(--s,1)*100%)); }";
break;
case 14:
keyframesElement.textContent = "80% { text-shadow: 0 0 0 #000, 10ch 0 0 #000; background-size: 100% 3px; }\n 100% { text-shadow: -10ch 0 0 #000, 0 0 0 #000; }";
break;
case 15:
keyframesElement.textContent = "80%, 100% { text-shadow: 0 calc(var(--s,1)*-1.2em) 0 #000, 0 0 0 #000; }";
break;
case 16:
keyframesElement.textContent = "20% { text-shadow: calc(-1*var(--w)) 0, calc(-2*var(--w)) 0 red, calc(-3*var(--w)) 0, calc(-4*var(--w)) 0 #ffa516, calc(-5*var(--w)) 0 #63fff4, calc(-6*var(--w)) 0, calc(-7*var(--w)) 0, calc(-8*var(--w)) 0 green, calc(-9*var(--w)) 0; }\n 40% { text-shadow: calc(-1*var(--w)) 0, calc(-2*var(--w)) 0 red, calc(-3*var(--w)) 0 #e945e9, calc(-4*var(--w)) 0, calc(-5*var(--w)) 0 green, calc(-6*var(--w)) 0 orange, calc(-7*var(--w)) 0, calc(-8*var(--w)) 0 green, calc(-9*var(--w)) 0; }\n 60% { text-shadow: calc(-1*var(--w)) 0 lightblue, calc(-2*var(--w)) 0, calc(-3*var(--w)) 0 #e945e9, calc(-4*var(--w)) 0, calc(-5*var(--w)) 0 green, calc(-6*var(--w)) 0, calc(-7*var(--w)) 0 yellow, calc(-8*var(--w)) 0 #ffa516, calc(-9*var(--w)) 0 red; }\n 80% { text-shadow: calc(-1*var(--w)) 0 lightblue, calc(-2*var(--w)) 0 yellow, calc(-3*var(--w)) 0 #63fff4, calc(-4*var(--w)) 0 #ffa516, calc(-5*var(--w)) 0 red, calc(-6*var(--w)) 0, calc(-7*var(--w)) 0 grey, calc(-8*var(--w)) 0 #63fff4, calc(-9*var(--w)) 0; }";
break;
}
}
// 复制CSS代码
function copyCSSCode() {
const fontSize = document.getElementById('fontSize').value;
const fontWeight = document.getElementById('fontWeight').value;
const fontFamily = document.getElementById('fontFamily').value;
const color = document.getElementById('color').value;
const speed = document.getElementById('speed').value;
const timing = document.getElementById('timing').value;
let cssCode = `.loader {
font-weight: ${fontWeight};
font-family: ${fontFamily};
font-size: ${fontSize}px;
color: ${color};
animation: l${currentLoaderType} ${speed}s ${timing} infinite;
}
.loader:before {
content: "Loading...";
}
@keyframes l${currentLoaderType} {
${getKeyframesCode()}
}`;
navigator.clipboard.writeText(cssCode).then(() => {
const exportBtn = document.getElementById('exportBtn');
exportBtn.textContent = '已复制到剪贴板!';
setTimeout(() => {
exportBtn.textContent = '复制CSS代码';
}, 2000);
});
}
// 获取关键帧代码
function getKeyframesCode() {
switch(currentLoaderType) {
case 1: return "to { opacity: 0; }";
case 2: return "to { background-size: 100% 3px; }";
case 3: return "to { background-position: 80% 100%; }";
case 4: return "to { clip-path: inset(0 -1ch 0 0); }";
case 5: return "to { clip-path: inset(0 -1ch 0 0); }";
case 6: return "to { text-shadow: -11ch 0 var(--c), 0ch 0 var(--c); }";
case 7: return "to { background-position: left; }";
case 8: return "to { background-position: left; }";
case 9: return "0% { text-shadow: 0 0 #000, 11ch 0 #8A9B0F, 22ch 0 #C02942, 33ch 0 #00A0B0, 44ch 0 #000; }\n 25% { text-shadow: -11ch 0 #000, 0 0 #8A9B0F, 11ch 0 #C02942, 22ch 0 #00A0B0, 33ch 0 #000; }\n 50% { text-shadow: -22ch 0 #000, -11ch 0 #8A9B0F, 0 0 #C02942, 11ch 0 #00A0B0, 22ch 0 #000; }\n 75% { text-shadow: -33ch 0 #000, -22ch 0 #8A9B0F, -11ch 0 #C02942, 0 0 #00A0B0, 11ch 0 #000; }\n 100% { text-shadow: -44ch 0 #000, -33ch 0 #8A9B0F, -22ch 0 #C02942, -11ch 0 #00A0B0, 0 0 #000; }";
case 10: return "25% { background-position: calc(1*100%/3) 0; }\n 50% { background-position: calc(2*100%/3) 0; }\n 75% { background-position: calc(3*100%/3) 0; }\n 100% { background-position: calc(4*100%/3) 0; }";
case 11: return "100% { transform: translateY(calc(var(--s,1)*0.1%)); }";
case 12: return "50%, 100% { transform: translateX(calc(var(--s,1)*100%)); }";
case 13: return "25%, 100% { transform: translateX(calc(var(--s,1)*100%)); }";
case 14: return "80% { text-shadow: 0 0 0 #000, 10ch 0 0 #000; background-size: 100% 3px; }\n 100% { text-shadow: -10ch 0 0 #000, 0 0 0 #000; }";
case 15: return "80%, 100% { text-shadow: 0 calc(var(--s,1)*-1.2em) 0 #000, 0 0 0 #000; }";
case 16: return "20% { text-shadow: calc(-1*var(--w)) 0, calc(-2*var(--w)) 0 red, calc(-3*var(--w)) 0, calc(-4*var(--w)) 0 #ffa516, calc(-5*var(--w)) 0 #63fff4, calc(-6*var(--w)) 0, calc(-7*var(--w)) 0, calc(-8*var(--w)) 0 green, calc(-9*var(--w)) 0; }\n 40% { text-shadow: calc(-1*var(--w)) 0, calc(-2*var(--w)) 0 red, calc(-3*var(--w)) 0 #e945e9, calc(-4*var(--w)) 0, calc(-5*var(--w)) 0 green, calc(-6*var(--w)) 0 orange, calc(-7*var(--w)) 0, calc(-8*var(--w)) 0 green, calc(-9*var(--w)) 0; }\n 60% { text-shadow: calc(-1*var(--w)) 0 lightblue, calc(-2*var(--w)) 0, calc(-3*var(--w)) 0 #e945e9, calc(-4*var(--w)) 0, calc(-5*var(--w)) 0 green, calc(-6*var(--w)) 0, calc(-7*var(--w)) 0 yellow, calc(-8*var(--w)) 0 #ffa516, calc(-9*var(--w)) 0 red; }\n 80% { text-shadow: calc(-1*var(--w)) 0 lightblue, calc(-2*var(--w)) 0 yellow, calc(-3*var(--w)) 0 #63fff4, calc(-4*var(--w)) 0 #ffa516, calc(-5*var(--w)) 0 red, calc(-6*var(--w)) 0, calc(-7*var(--w)) 0 grey, calc(-8*var(--w)) 0 #63fff4, calc(-9*var(--w)) 0; }";
default: return "to { opacity: 0; }";
}
}
// 添加事件监听器
document.getElementById('fontSize').addEventListener('input', () => {
document.getElementById('fontSizeValue').textContent = document.getElementById('fontSize').value + 'px';
updatePreview();
});
document.getElementById('fontWeight').addEventListener('change', updatePreview);
document.getElementById('fontFamily').addEventListener('change', updatePreview);
document.getElementById('color').addEventListener('input', updatePreview);
document.getElementById('speed').addEventListener('input', () => {
document.getElementById('speedValue').textContent = document.getElementById('speed').value + 's';
updatePreview();
});
document.getElementById('timing').addEventListener('change', updatePreview);
document.getElementById('exportBtn').addEventListener('click', copyCSSCode);
// 初始化
initTemplates();
</script>
</body>
</html>
<script src="https://inspirejs.org/inspire.js"></script>
or
import Inspire from "https://inspirejs.org/inspire.mjs";
NPM
npm install inspirejs.org
then
<script src="node_modules/inspirejs.org/inspire.js"></script>
or
import Inspire from "node_modules/inspirejs.org/inspire.mjs";
or if you use a bundler:
import Inspire from "inspirejs.org";
Quick start
- Copy (and rename) blank.html somewhere
- Also copy talk.css, theme.css
- Add Your Own Content
- Add talk-specific styling to talk.css
Previously known as CSSS.
If you were using CSSS and would rather stay at it, run git checkout v1.0.0 and stay there.Migrating from CSSS
- Almost all HTML syntax is the same! The same JS events are still fired. So, very little should break.
slideshow.cssis nowinspire.cssslideshow.jsis nowinspire.js- You don’t need to run JS to create a slideshow, it is created automatically.
- The
SlideShowJS class is nowInspire - The
slideshowJS variable is nowInspire - Presenter view will not be loaded unless there is at least one
class="presenter-notes"item. - The CSS Controls plugin is now gone. Use Mavo if you need this functionality.
- The CSS Snippets plugin is now gone. We will soon add a much better one, extracted based on the live demo script in https://github.com/leaverou/talks.
- Incrementable is no longer a plugin. Use the separate script from https://github.com/leaverou/incrementable.
reusable.csshas now been merged into the default theme,theme.css.data-importis nowdata-insert
API FAQ
Running code after any imports have loaded
await Inspire.importsLoaded; // code to run after imports have loaded
Note that await needs to be inside an async function otherwise it will error. However, this could just be a self-executing async function.
Running code after a specific plugin has loaded
await Inspire.importsLoaded; await Inspire.plugins.loaded.PLUGIN_ID.loaded; // code to run after the plugin with id PLUGIN_ID has loaded and executed
or:
await Inspire.loadPlugin(PLUGIN_ID); // code to run after the plugin with id PLUGIN_ID has loaded and executed
The second example would load the plugin if it hasn’t otherwise been loaded, but if it will never be loaded twice.
Running code when a specific slide is displayed
You can do this via the slidechange hook:
Inspire.hooks.add("slidechange", env => {
if (Inspire.currentSlide.id === "slide-id") {
// Code to run
}
});
or, via an event:
document.addEventListener("slidechange", evt => {
if (Inspire.currentSlide.id === "slide-id") {
// Code to run
}
});
Running code when a specific slide is displayed for the first time
You can do this via the slidechange hook:
Inspire.hooks.add("slidechange", env => {
if (Inspire.currentSlide.id === "slide-id" && env.firstTime) {
// Code to run
}
});
or, via an event:
document.addEventListener("slidechange", evt => {
if (Inspire.currentSlide.id === "slide-id" && evt.firstTime) {
// Code to run
}
});
or:
$("#slide-id").addEventListener("slidechange", evt => {
// Code to run
}, {once: true});
Running code after a specific slide has been displayed
You can do this via the slidechange hook:
Inspire.hooks.add("slidechange", env => {
if (env.prevSlide.id === "slide-id") {
// Code to run
}
});
or, via an event:
document.addEventListener("slidechange", evt => {
if (evt.prevSlide.id === "slide-id") {
// Code to run
}
});
© 版权声明
The copyright of the article belongs to the author. Please do not reproduce without the author's consent.
THE END

暂无评论内容