javascript - 如何通过 CSS 使用垂直居中的锚点为文本设置动画
问题描述
我有一个简单的 JS 脚本,它监听键盘输入并在随机位置显示每个键入的字母淡出并变小的简短动画。
'use strict'
const body = document.querySelector('body')
const ignoreKeys = [
'Alt', 'Shift', 'Control', 'CapsLock', 'Tab', 'Backspace', 'Escape', 'Meta',
'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'
]
document.addEventListener('keydown', function(e) {
if (!ignoreKeys.includes(e.key)) {
// Values 400 & 200 keep the div completely inside the window
const maxHeight = window.innerHeight - 400
const maxWidth = window.innerWidth - 200
const div = document.createElement('div')
div.className = 'anim'
div.textContent = e.key
div.style.top = getRandomInt(0, maxHeight) + 'px'
div.style.left = getRandomInt(0, maxWidth) + 'px'
body.append(div)
setTimeout(function() { div.remove() }, 3000)
}
})
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min) + min)
}
.anim {
position: fixed;
text-align: center;
animation-name: fade;
animation-duration: 2s;
animation-timing-function: ease-in-out;
opacity: 0%;
}
@keyframes fade {
0% { opacity: 100%; font-size: 300px;}
100% { opacity: 0%; font-size: 100px;}
}
通过为属性设置动画font-size
,每个字母都会变小。然而,由于它的“锚点”是 div 的顶部,可见效果是一个字母变小并略微向上移动。我希望每个字母都向垂直中心收缩div
。
我可以div
轻松计算中心并将正确的top
坐标添加到@keyframe
属性中,但我不知道如何在 JS 中单独修改每个div
. 这完全可以通过 CSS 实现吗?还是我应该用纯 JS 重写整个事情?
解决方案
您根本不需要调整 div 的最高值。由于 DIV 标签本身没有边框或其他任何显示 - 只是其中的字母 - 您可以调整边距、边框和/或填充以达到与增加 DIV 的顶部值相同的效果。由于这些中的每一个都可以在 css 转换中处理,因此您可以执行以下操作:
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min) + min)
}
document.addEventListener('keydown', function(e) {
const body = document.querySelector('body')
const ignoreKeys = [
'Alt', 'Shift', 'Control', 'CapsLock', 'Tab', 'Backspace', 'Escape', 'Meta',
'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'
]
if (!ignoreKeys.includes(e.key)) {
// Values 400 & 200 keep the div completely inside the window
const maxHeight = window.innerHeight - 400
const maxWidth = window.innerWidth - 200
const div = document.createElement('div')
div.className = 'anim'
div.textContent = e.key;
div.style.top = getRandomInt(0, maxHeight) + 'px'
div.style.left = getRandomInt(0, maxWidth) + 'px'
body.append(div)
setTimeout(function() { div.remove() }, 3000)
}
})
.anim {
display:block;
position: fixed;
text-align: center;
width:200px;
animation-name: fade;
animation-duration: 2s;
animation-timing-function: ease-in-out;
opacity: 0;
margin:0px;
}
@keyframes fade {
0% { opacity:1; font-size: 300px;}
100% { opacity:0; font-size: 100px; margin-top:100px;}
}
DIV 的初始状态为 margin:0px。在关键帧 css 中添加 margin-top 设置,在过渡期间将其从 0 增加到 100。这样做的效果是向下推 DIV - 如上所述,由于 DIV 本身没有显示任何内容,因此用户不会看到它移动。请注意,我已将 DIV 的宽度固定为 200 像素,因此确保所有内容始终水平居中 - 否则 DIV 宽度基于字符的宽度,因此在过渡期间会发生变化,并且字符将向左移动作为中心线路变化。我已经移动了一些代码以使其更易于测试 - 但唯一实际的变化是 CSS 样式。另请注意,不透明度是从 0 到 1 的值,因此不应显示为百分比。
更新
看看下面的代码片段。我认为可能有随机字体大小和随机位置使用transform
而不是animate
.
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min) + min)
}
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split("");
function zoomOUT(){
let d = document.getElementById("test");
d.classList.remove("zoomIN");
d.classList.add("zoomOUT");
}
function zoomIN(){
let d = document.getElementById("test");
let dletter = document.getElementById("testletter");
let t = getRandomInt(20, 60) * 10;
let l = getRandomInt(20, 100) * 10;
let fs = getRandomInt(10, 20) * 10;
dletter.innerHTML = letters[getRandomInt(0, 61)];
d.style.top = t + "px";
d.style.left = l + "px";
d.style.fontSize = fs + "%";
d.classList.remove("zoomOUT");
d.classList.add("zoomIN");
}
#test {
position:absolute;
padding: 50px;
margin: 0 auto;
text-align:center;
vertical-align:middle;
}
.zoomIN {
opacity:1;
transform: scale(3);
transition: transform 2s;
}
.zoomOUT {
opacity:0.5;
transform: scale(0.1);
transition: transform 3s;
}
<button onclick="zoomOUT();" z-index=1>Play</button><button onclick="zoomIN();" z-index=1>Restart</button>
<div id="test" class="zoomIN" style="top:300px; left:300px;" z-index=0><div id="testletter" style="font-size:600%; width:100%; height:100%">A</div></div>
Transform 似乎将事物保持在同一个地方,因此根本不需要调整任何顶部/边距/边框/填充设置。事实上,唯一改变的是字体大小(使用scale(..)
)和不透明度。字体大小由代码决定。请注意,这要求字符位于 div 中的 div 中。这只是一个测试,但应该足以让您将内容转换为您的代码要求。
推荐阅读
- status - 如何获取 RingCentral 软电话中显示的用户状态?
- javascript - 将新数据行添加到 postgresql 数据库时如何更新前端
- excel - 如果单元格 A1 是某个值,则 B1 在两个值之间是随机的
- gulp - 如何将车把参数从字符串部分转换为整数?
- javascript - WebRTC ICE 连接卡在检查状态
- java - 从 Cosmosdb 获取文档 Java 跨分区查询是必需的,但已禁用
- node.js - 将 Prisma GraphQL-Yoga 用作 Express/Node 应用程序:如何在服务器端调用 GraphQL 突变?
- php - PHP - 从数据库中获取出生日期,将其转换为年龄,如果年龄超过 15 岁,则从数据库中回显他们的电子邮件
- kotlin - Kotlin 和 Arrow.io:使用 IO.bracketCase 进行交易
- animation - 格挡时如何移动人物剑格挡敌人的攻击?