在这个网站(minimal-portfolio-swart.vercel.app)发现一个不错的交互效果,用户体验效果很不错。如上图所示,这个卡片上有一根白色的线条围绕着卡片移动,且在线条的卡片内部跟随这一块模糊阴影,特别是在线条经过卡片圆角部分有特别丝滑的感觉。
今天的文章就来解析如何实现这种效果。
根据示例图片分析需要实现的功能点如下:
这里为什么单独说明圆角部分是因为这块需要特殊处理,请看后面的文章。
思考
看到这个效果首先感觉是丝滑,沿着边框移动的动画元素如果是根据当前边框实时计算而来的话,那么难度和算法会劝退很多人。
需要换一种思路,本质移动的线条元素和边框并没有关系,而是一个元素沿着边框移动,线条和卡片内部的阴影就是一个元素,通过某种透视的方式产生了这种效果。
透视
通过透视的方式实现一个边框效果,我们可以用2个盒子嵌套,父级设置1像素的padding,如下代码简单的实现一个边框效果。
.outer {
width: 400px;
height: 200px;
margin: 100px;
background: rgb(54, 224, 202);
padding: 1px;
position: relative;
}
.inner {
background: rgb(99, 99, 99);
width: 100%;
height: 100%;
}
然后增加一个子元素作为移动的元素,这个元素基于父级定位在边框位置,由于动画是沿着卡片内部四周移动,要确保在每一条边上的透出的长度保持一致,所有创建的这个子元素是一个正方形。
.moving-element {
position: absolute;
top: 0;
left: 0;
width: 80px;
height: 80px;
background: #fff;
animation: moveAround 8s linear infinite;
}
并对这个元素增加简单的animation动画,沿着内边框移动。
这个动画需要注意的一个点是要使元素在移动的过程中保持匀速的动画,需要计算每个关键帧之间的距离,并根据这些距离来调整每个关键帧的百分比。这样可以确保元素在每个时间段内移动的距离与时间成正比,从而实现真正的匀速移动。
这里我们以上面的卡片举例,其宽度为400px,高度为200px,元素沿矩形的边框移动。
@keyframes moveAround {
0%, 100% {
top: 0px;
left: 0px;
}
33.33% {
top: 0px;
left: calc(100% - 80px);
}
50% {
top: calc(100% - 80px);
left: calc(100% - 80px);
}
83.33% {
top: calc(100% - 80px);
left: 0px;
}
}
最终完成的简单版动画效果如下:
这里为了方便大家看增加了透明度展示内部移动的元素,若去掉透明度则只有边框上的一根线。
仔细看上面的图可以发现在边框尽头时的过渡效果不好,瞬间从一条边切换到另一条边。首先还原网站的效果,增加边框圆角,然后将内部移动的元素通过圆角变成一个圆形,这时候还需要同步调整内部元素的定位和动画移动时设置的定位,保证内部圆形的中心和边框的一致。
增加圆角处理:
.outer {
border-radius: 20px;
}
.inner {
border-radius: 20px;
}
.moving-element {
border-radius: 40px;
/* 圆心和边框一致 */
transform: translate(-40px, -40px);
}
调整动画过程中的定位:
@keyframes moveAround {
0%, 100% {
top: 0px;
left: 0px;
}
33.33% {
top: 0px;
left: 100%;
}
50% {
top: 100%;
left: 100%;
}
83.33% {
top: 100%;
left: 0px;
}
}
此时的动画效果:
此时的边框位置动画已经很接近网站的效果,进一步观察在图中的效果可以发现在边框角落的位置有一点卡顿的感觉,这是因为边框位置我们设置了圆角,但是元素移动的轨迹是直角,导致视觉上停顿了一下。这里我们需要进一步优化animation。设置圆角后内部动画元素移动的点应该从4个变成8个,且对应的位置需要和圆角的大小一一对应才能保障流畅的动画效果。
如下所示黑色圆点是到四个顶点的动画坐标,新的绿色圆点是基于圆角后的动画移动坐标。
基于上面的动画百分比算法计算出最新的比例及坐标代码如下:
@keyframes moveAround {
0% { left: 40px; top: 0px; }
28.93% { left: 360px; top: 0px; }
33.99% { left: 400px; top: 40px; }
44.82% { left: 400px; top: 160px; }
49.88% { left: 360px; top: 200px; }
78.81% { left: 40px; top: 200px; }
83.87% { left: 0px; top: 160px; }
94.70% { left: 0px; top: 40px; }
100% { left: 40px; top: 0px; }
}
这里的动画需要注意的是圆角部分绿色按钮之间的动画距离需要使用使用勾股定理计算。比如右上角的两个点之间的计算方式是:
此时的动画效果:
现在就差最后的阴影部分还未实现,仔细观察移动的线条并不是全实心纯色,而是有渐变的效果,目前移动的元素是一个正方形,设置背景色为径向渐变即可,修改背景色的代码如下:
background-image: radial-gradient(#fff 40%,transparent 80%);
现在还需要将内部的渐变进一步模糊,注意这里仅仅是模糊元素背后的背景,不能影响卡片上面其他的元素内容展示。这里我们使用backdrop-filter设置blur模糊效果。
到此整体的代码实现过程就结束了,完整还原的网站的动画效果。这是一个对用户体验很不错的卡片效果,原网站实现的部分细节不一样,整体实现原理差不多,基于两个元素的1像素间距透出移动的线条,配合使用backdrop-filter设置纯背景模糊效果,有兴趣的可以尝试看看。
PS:评论留言可参与抽奖活动获得完整源码!
]]>🌟 CSS边框流光闪烁阴影动画效果是一种令人印象深刻的技术,它通过动态的光影变化,为网页元素增添了独特的视觉吸引力。本文将深入探讨如何使用CSS来实现这种高级动画效果,从基础的阴影应用到复杂的光流动画,一步步引导您创造出令人惊叹的视觉效果,让您的设计作品在众多网站中脱颖而出。
<div class="cardBox"> 边框流光闪烁阴影效果 </div>
@property --rotate {
syntax: "<angle>";
initial-value: 132deg;
inherits: false;
}
:root {
--card-height: 65vh;
--card-width: calc(var(--card-height) / 1.5);
}
body {
min-height: 100vh;
background: #212534;
display: flex;
align-items: center;
flex-direction: column;
padding-top: 2rem;
padding-bottom: 2rem;
box-sizing: border-box;
}
.cardBox {
background: #191c29;
width: var(--card-width);
height: var(--card-height);
padding: 3px;
position: relative;
border-radius: 6px;
justify-content: center;
align-items: center;
text-align: center;
display: flex;
font-size: 1.5em;
color: rgb(88 199 250 / 0%);
cursor: pointer;
font-family: cursive;
}
.cardBox:hover {
color: rgb(88 199 250 / 100%);
transition: color 1s;
}
.cardBox:hover:before, .cardBox:hover:after {
animation: none;
opacity: 0;
}
.cardBox::before {
content: "";
width: 104%;
height: 102%;
border-radius: 8px;
background-image: linear-gradient(
var(--rotate)
, #5ddcff, #3c67e3 43%, #4e00c2);
position: absolute;
z-index: -1;
top: -1%;
left: -2%;
animation: spin 2.5s linear infinite;
}
.cardBox::after {
position: absolute;
content: "";
top: calc(var(--card-height) / 6);
left: 0;
right: 0;
z-index: -1;
height: 100%;
width: 100%;
margin: 0 auto;
transform: scale(0.8);
filter: blur(calc(var(--card-height) / 6));
background-image: linear-gradient(
var(--rotate)
, #5ddcff, #3c67e3 43%, #4e00c2);
opacity: 1;
transition: opacity .5s;
animation: spin 2.5s linear infinite;
}
@keyframes spin {
0% {
--rotate: 0deg;
}
100% {
--rotate: 360deg;
}
}
🌟 以下是实现这个效果的关键技术:
🌟 在视觉传达的艺术中,logo作为品牌的第一印象,其设计至关重要。随着网页设计趋势的发展,动态元素的加入使得logo不再局限于静态图像,而是能够通过动画效果与用户产生更深层次的互动。本文将探讨如何利用CSS为logo添加阴影动画效果,让品牌标志在网页上生动起来,增强品牌的吸引力和记忆度。
<div class="textItem" data-word="HELLO WORLD"></div>
body {background:#000}
.textItem {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(3);
width: 300px;
font-size: 36px;
font-family: Raleway, Verdana, Arial;
color: transparent;
}
.textItem::before {
content: attr(data-word);
position: absolute;
top: 0;
left: 0;
height: 36px;
color: red;
overflow: hidden;
z-index: 2;
filter: contrast(200%);
text-shadow: 1px 0 0 red;
animation: move 0.95s infinite;
}
.textItem::after {
content: attr(data-word);
position: absolute;
top: 0;
left: -1px;
height: 36px;
color: rgba(255, 255, 255, 0.8);
overflow: hidden;
z-index: 3;
color: cyan;
filter: contrast(200%);
text-shadow: -1px 0 0 cyan;
mix-blend-mode: lighten;
animation: move 1.1s infinite 0.2s;
}
@keyframes move {
10% {
top: -0.4px;
left: -1.1px;
}
20% {
top: 0.4px;
left: -0.2px;
}
30% {
left: .5px;
}
40% {
top: -0.3px;
left: -0.7px;
}
50% {
left: 0.2px;
}
60% {
top: 1.8px;
left: -1.2px;
}
70% {
top: -1px;
left: 0.1px;
}
80% {
top: -0.4px;
left: -0.9px;
}
90% {
left: 1.2px;
}
100% {
left: -1.2px;
}
}
🌟 关键技术点如下:
🌟在网页设计中,按钮不仅仅是用户界面的一个简单组成部分,它还能够通过视觉效果增强用户体验和美感。CSS动画酷炫毛玻璃按钮展开效果是一种创新的交互设计,它结合了流行的毛玻璃美学和动态动画,为按钮添加了深度和动感。
<div class="container">
<div class="btn"><a href="#">button 1</a></div>
<div class="btn"><a href="#">button 2</a></div>
<div class="btn"><a href="#">button 3</a></div>
</div>
body {
position: relative;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: linear-gradient(to bottom, #5d326c, #350048); /*fiolet*/
}
.container {
width: 1000px;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.container .btn {
position: relative;
top: 0;
left: 0;
width: 250px;
height: 50px;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
.container .btn a {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.05);
box-shadow: 0 15px 15px rgba(0, 0, 0, 0.3);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
border-top: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 30px;
padding: 10px;
box-sizing: border-box;
letter-spacing: 1px;
text-decoration: none;
overflow: hidden;
color: #fff;
font-weight: 400px;
z-index: 1;
transition: 0.5s;
backdrop-filter: blur(15px);
}
.container .btn:hover a {
letter-spacing: 3px;
}
.container .btn a::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 50%;
height: 100%;
background: linear-gradient(to left, rgba(255, 255, 255, 0.15), transparent);
transform: skewX(45deg) translate(0);
transition: 0.5s;
filter: blur(0px);
}
.container .btn:hover a::before {
transform: skewX(45deg) translate(200px);
}
.container .btn::before {
content: "";
position: absolute;
left: 50%;
transform: translatex(-50%);
bottom: -5px;
width: 30px;
height: 10px;
background: #f00;
border-radius: 10px;
transition: 0.5s;
transition-delay: 0.5;
}
.container .btn:hover::before /*lightup button*/ {
bottom: 0;
height: 50%;
width: 80%;
border-radius: 30px;
}
.container .btn::after {
content: "";
position: absolute;
left: 50%;
transform: translatex(-50%);
top: -5px;
width: 30px;
height: 10px;
background: #f00;
border-radius: 10px;
transition: 0.5s;
transition-delay: 0.5;
}
.container .btn:hover::after /*lightup button*/ {
top: 0;
height: 50%;
width: 80%;
border-radius: 30px;
}
.container .btn:nth-child(1)::before, /*chnage 1*/
.container .btn:nth-child(1)::after {
background: #ff1f71;
box-shadow: 0 0 5px #ff1f71, 0 0 15px #ff1f71, 0 0 30px #ff1f71, 0 0 60px #ff1f71;
}
.container .btn:nth-child(2)::before, /* 2*/
.container .btn:nth-child(2)::after {
background: #2db2ff;
box-shadow: 0 0 5px #2db2ff, 0 0 15px #2db2ff, 0 0 30px #2db2ff, 0 0 60px #2db2ff;
}
.container .btn:nth-child(3)::before, /* 3*/
.container .btn:nth-child(3)::after {
background: #1eff45;
box-shadow: 0 0 5px #1eff45, 0 0 15px #1eff45, 0 0 30px #1eff45, 0 0 60px #1eff45;
}
🌟 关键技术点如下:
今天分享一些酷炫的登录页面能够为网站或应用留下深刻的第一印象。本文将分享使用HTML和CSS打造的登录页面源码,这些源码不仅外观酷炫,而且易于实现和定制。无论是开发者还是设计师,都可以从中获得灵感,提升自己的项目。
<!-- 背景云层 -->
<div id="header">
<div id="clouds">
<div class="cloud-1" data-speed="35000"></div>
<div class="cloud-2" data-speed="45000" data-delay="15000"></div>
<div class="cloud-3" data-speed="40000"></div>
<div class="cloud-4" data-speed="38000" data-delay="20000"></div>
</div>
</div><!-- / #header -->
<div id="content">
<div class="container">
<!-- 登录模块 -->
<form id="login" method="post" action="login.jsp" onsubmit="return checkForm(this);">
<div id="login_header"><i class="icon-home"></i>智能小区服务管理系统</div>
<div id="login_content">
<span>
<input class="tip" name="username" type="text" maxlength="18" onclick="onClick(this);" onblur="onBlur(this);">
<label for="username">用户名</label>
<i class="icon-user"></i>
<div class="tooltip" data-text="填写您的身份证号">填写您的身份证号</div>
</span>
<span>
<input class="tip" name="password" type="password" maxlength="16" onclick="onClick(this);" onblur="onBlur(this);">
<label for="password">密码</label>
<i class="icon-lock"></i>
<div class="tooltip" data-text="填写您的密码">填写您的密码</div>
</span>
<div class="option">
<div class="option_result">用户类型</div>
<div class="option_arrow"><b class="arrow"></b></div>
<ul class="option_list">
<li>住户</li>
<li>管理员</li>
<li>运营商</li>
</ul>
<div class="tooltip" data-text="选择您的用户类型">选择您的用户类型</div>
</div><!-- / .option -->
</div><!-- / #login_content -->
<div id="login_footer">
<div class="ing"></div>
<button id="login_btn" type="submit">登录</button>
</div><!-- / #login_footer -->
<div><a id="register_link" href="javascript:void(0);">新用户注册</a></div>
</form><!-- / #login -->
<!-- 注册模块 -->
<form id="register" method="post" action="register.jsp" onsubmit="return checkForm(this);">
<div id="register_header"><i class="icon-home"></i>新用户注册</div>
<div id="register_content">
<span>
<input class="tip" name="realname" type="text" maxlength="4" onclick="onClick(this);" onblur="onBlur(this);">
<label for="realname">真实姓名</label>
<i class="icon-user"></i>
<div class="tooltip" data-text="填写您的真实中文姓名">填写您的真实中文姓名</div>
</span>
<span>
<input class="tip" name="ID" type="text" maxlength="18" onclick="onClick(this);" onblur="onBlur(this);">
<label for="ID">身份证号</label>
<i class="icon-lock"></i>
<div class="tooltip" data-text="填写您的真实身份证号码">填写您的真实身份证号码</div>
</span>
<span>
<input class="tip" name="password" maxlength="16" type="password" onclick="onClick(this);" onblur="onBlur(this);">
<label for="password">密码</label>
<i class="icon-lock"></i>
<div class="tooltip" data-text="填写6~16个字母或者数字">填写6~16位字母或者数字</div>
</span>
</div><!-- / #register_content -->
<div id="register_footer">
<div class="ing"></div>
<button id="register_btn" type="submit">注册</button>
</div><!-- / #register_footer -->
<div><a id="login_link" href="javascript:void(0);">返回登录</a></div>
</form><!-- / #register -->
</div><!-- / .container -->
</div><!-- / #content-->
<div id="footer">
<div class="container">
</div><!-- / .container -->
</div><!-- / #footer -->
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline; }
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block; }
body {
line-height: 1; }
ol, ul {
list-style: none; }
blockquote, q {
quotes: none; }
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none; }
table {
/*border-collapse: collapse;*/
border-spacing: 0; }
/* #Basic Styles
================================================== */
body {
background:#87CEFA;
overflow:hidden;
font:normal 16px/1.5 Helvetica, "Microsoft Yahei", Arial, sans-serif;
color:#444;
-webkit-font-smoothing:antialiased; /* Fix for webkit rendering */
-webkit-text-size-adjust:100%;
}
input {padding:10px 15px;outline:0;border:0;border-radius:3px;width:200px;}
a, a:visited { color: #333; text-decoration: none; outline: 0; }
a:hover, a:focus { color: #000;}
/*云层*/
#clouds{position:absolute;top:0;right:0;bottom:0;left:0;}
[class^="cloud-"]{position:absolute;right:120%;width:200px;height:60px;background:white;-webkit-border-radius:200px;-moz-border-radius:200px;border-radius:200px;}
[class^="cloud-"]:before,[class^="cloud-"]:after{content:'';position:absolute;top:-15px;left:10px;width:100px;height:80px;background:#fff;-webkit-border-radius:100px;border-radius:100px;-webkit-transform:rotate(30deg);-moz-transform:rotate(30deg);transform:rotate(30deg);}
[class^="cloud-"]:after {top: -55px;left: auto;right: 15px;width: 120px;height: 120px;}
.cloud-1 {top: 50px;-webkit-animation: moveclouds 30s linear infinite;-moz-animation: moveclouds 30s linear infinite;-o-animation: moveclouds 30s linear infinite;animation: moveclouds 30s linear infinite;}
.cloud-2 {top: 100px;opacity: 0.8;-webkit-transform: scale(0.8);-moz-transform: scale(0.8);transform: scale(0.8);-webkit-animation: moveclouds 45s linear infinite;-moz-animation: moveclouds 45s linear infinite;-o-animation: moveclouds 45s linear infinite;animation: moveclouds 45s linear infinite;-webkit-animation-delay: 5s;-moz-animation-delay: 5s;animation-delay: 5s;}
.cloud-3 {top: 150px;opacity: 0.6;-webkit-transform: scale(0.6);-moz-transform: scale(0.6);transform: scale(0.6);-webkit-animation: moveclouds 40s linear infinite;-moz-animation: moveclouds 40s linear infinite;-o-animation: moveclouds 40s linear infinite;animation: moveclouds 40s linear infinite;}
.cloud-4 {top: 200px;opacity: 0.75;-webkit-transform: scale(0.75);-moz-transform: scale(0.75);transform: scale(0.75);-webkit-animation: moveclouds 26s linear infinite;-moz-animation: moveclouds 26s linear infinite;-o-animation: moveclouds 26s linear infinite;animation: moveclouds 26s linear infinite;-webkit-animation-delay: 8s;-moz-animation-delay: 8s;animation-delay: 8s;}
/*云层移动*/
@-webkit-keyframes moveclouds {
0% { right: -20%; }
100% { right: 120%; }
}
@-moz-keyframes moveclouds {
0% { right: -20%; }
100% { right: 120%; }
}
@-o-keyframes moveclouds {
0% { right: -20%; }
100% { right: 120%; }
}
/* #Content Styles
================================================== */
/*内容*/
#content{width:100%;}
.container{width:960px;margin:0 auto;text-align:center;}
/*登录/注册*/
#login,#register{width:400px;height:380px;position:absolute;top:50%;left:50%;margin-top:-200px;margin-left:-200px;background:#F8F8F8;border-radius:10px;box-shadow:0 3px 6px rgba(0, 0, 0, 0.5);}
#register{left:120%;}
#login_header,#register_header{height:60px;line-height:60px;font-size:20px;font-weight:bold;color:#77CA60;background:#FFF;border-radius:10px 10px 0 0;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, .1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, .1);box-shadow:0 1px 3px rgba(0, 0, 0, .1);}
.icon-home{font-size:30px;position:relative;top:3px;}
#login_content,#register_content{height:200px;padding:30px 20px;}
input{width:300px;padding:14px 15px;background:#F0F0F0;font:normal 16px/1.5 Helvetica,"Microsoft Yahei",Arial,sans-serif;color:#444;}
span{position:relative;display:inline-block;height:50px;margin-bottom:30px;}
.tip{text-indent:80px;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;transition:all .3s ease-in-out;}
.tip:focus,.tip:active{text-indent:0;}
.tip + label{position:absolute;top:16px;left:15px;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;transition:all .3s ease-in-out;}
.tip:focus + label,.tip:active + label{-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);transform:translateY(-40px);}
.icon-user,.icon-lock{position:absolute;top:16px;right:14px;color:#999;}
.tooltip{width:200px;padding:14px;position:absolute;left:20%;top:0;right:0;color:#999;background:white;text-align:left;z-index:-1;box-shadow:0 1px 3px rgba(0, 0, 0, .1);}
.tooltip:after{width:0;height:0;content:"";position:absolute;right:100%;top:18px;color:#87CEFA;border:8px solid;border-right-color:white;}
#login_footer,#register{}
#login_btn,#register_btn{width:100%;height:60px;line-height:60px;outline:0;border:none;color:white;font-weight:bold;font-size:20px;background:#77CA60;border-radius:0 0 10px 10px;cursor:pointer;text-shadow:1px 1px 1px rgba(0, 0, 0, 0.3);}
.ing{width:100%;height:5px;position:absolute;bottom:60px;}
#register_link,#login_link{width:80px;display:block;margin:20px auto;color:white;border-bottom:1px dashed;}
/*下拉菜单*/
.option{width:330px;position:absolute;margin:0 0 0 15px;text-align:left;background:#F0F0F0;cursor:pointer;border-radius:3px;}
.option_result{display:inline-block;padding:11px 15px;}
.option_arrow{padding:10px 19px;float:right;}
.option_arrow .arrow{width:0;height:0;font-size:0;border:6px solid;border-color:#6F7880 #F0F0F0 #F0F0F0;}
.option_list{background:#F3F3F3;display:none;}
.option_list li{padding:10px 15px;float:none;}
.option_list li:hover{background:#DFDFDF;}
/**
* 输入框被点击
*/
function onClick(){
//对函数的第一个参数进行判断
if (arguments[0]) {
var obj = arguments[0];
}else{
return false;
}
//获取.tooltip
var tooltip = $(obj).siblings('.tooltip');
//.tooltip如果存在,就滑出
if (tooltip.length != 0) {
//对函数第二个参数进行判断
if (arguments[1]) {
var text = arguments[1];
}else{
text = tooltip.data('text');
}
//设置提示框文字
tooltip.text(text);
//滑出提示框
tooltip.animate({left:'120%'});
};
}
/**
* 输入框失去焦点
*/
function onBlur(){
//对函数的第一个参数进行判断
if (arguments[0]) {
var obj = arguments[0];
}else{
return false;
}
//获取.tooltip
var tooltip = $(obj).siblings('.tooltip');
//.tooltip如果存在,就滑入
if (tooltip.length != 0) {
tooltip.animate({left:'20%'});
};
}
/**
* 表单验证
*/
function checkForm(){
//对函数的第一个参数进行判断
if (arguments[0]) {
//获取当前表单
var form = arguments[0];
}else{
return false;
}
//验证规则汇总
var id = new RegExp(/[0-9]{18}/);//匹配数字18次,用于身份证号码匹配
var password = new RegExp(/\w{6,16}/);//字母6到16次,用于密码匹配
var chinese = new RegExp(/[^\u4e00-\u9fa5]|^$/);//匹配中文以外的字符,用于真实姓名验证
var email = new RegExp(/\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/);//用于邮箱格式验证
//用户名username验证(同样适用身份证验证)
if (form.username != undefined && !id.test(form.username.value)) {
//不符合匹配规则
onClick($(form.username)[0],'身份证号码不规范,应为18位数字');
//阻止页面跳转
return false;
};
//密码password验证
if (form.password != undefined && !password.test(form.password.value)) {
//不符合匹配规则
onClick($(form.password)[0],'密码不规范,应为6~16位字母和数字');
//阻止页面跳转
return false;
};
//用户类型type验证
if ($(form).find('.option_result').text() == '用户类型') {
//用户没有勾选
onClick($('.option_result')[0],'请选择用户类型');
//阻止页面跳转
return false;
};
//真实姓名realname验证
if (form.realname != undefined && chinese.test(form.realname.value)) {
//有非中文字符
onClick($(form.realname)[0],'姓名不规范');
//阻止页面跳转
return false;
};
//真实身份证号码id验证
if (form.ID != undefined && !id.test(form.ID.value)) {
//不符合匹配规则
onClick($(form.ID)[0],'身份证号码不规范,应为18位数字');
//阻止页面跳转
return false;
};
//邮箱email验证
if (form.email != undefined && !email.test(form.email.value)){
//不符合匹配规则
onClick($(form.email)[0],'不是有效地电子邮件地址');
//阻止页面跳转
return false;
};
}
$(document).ready(function(){
/**
* 展开/收起下拉列表
*/
$('.option').click(function(){
$(this).children('.option_list').slideToggle(100);
$(this).toggleClass('active');
});
/**
* 设置option的值
*/
$('.option_list li').click(function(){
//获取选择的值
var text = $(this).text();
//设置option的值
$(this).parent().siblings('.option_result').text(text);
//如果存在就收起提示栏
var tooltip = $(this).parent();//原生js的parentNode是属性而不是方法
if (tooltip.length != 0) {
onBlur(tooltip[0]);//需要传入原生js对象
};
});
/**
* 切换到注册栏
*/
$('#register_link').click(function(){
//滑出#login栏,滑入#register栏
$('#login').animate({left:'-100%'},400,function(){
$('#register').animate({left:'50%'});
});
});
/**
* 切换到登陆栏
*/
$('#login_link').click(function(){
//滑出#register栏,滑入#login栏
$('#register').animate({left:'120%'},400,function(){
$('#login').animate({left:'50%'});
});
});
/**
* 登录
*/
$('#login_btn').click(function(){
var $obj = $(this);
$obj.text('登录中...');
setTimeout(function(){
$obj.text('登录');
},5000);
});
/**
* 注册
*/
$('#register_btn').click(function(){
var $obj = $(this);
$obj.text('注册中...');
setTimeout(function(){
$obj.text('注册');
},5000);
});
});
]]>在 WordPress 中开发自定义区块并在其中使用其他区块(如 wp:image),可以通过 Gutenberg 块编辑器的 React 组件来实现。这通常涉及使用 @wordpress/blocks 和 @wordpress/block-editor 包来创建和嵌套区块。以下是详细步骤,包括创建一个自定义区块并在其内部使用 wp:image。
使用 @wordpress/create-block
npx @wordpress/create-block my-custom-block
这个命令会生成一个名为 my-custom-block 的项目文件夹,包含开发自定义区块所需的基础文件。
编辑 block.json
定义自定义区块的基本信息:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "my-custom-block/container",
"title": "My Custom Block",
"category": "widgets",
"icon": "smiley",
"description": "A custom block with nested image block.",
"supports": {
"html": false
},
"attributes": {
"content": {
"type": "string",
"default": ""
}
},
"textdomain": "my-custom-block",
"editorScript": "file:./build/index.js",
"editorStyle": "file:./build/editor.css",
"style": "file:./build/style.css"
}
编辑 src/index.js
注册区块:
import { registerBlockType } from '@wordpress/blocks';
import Edit from './edit';
import save from './save';
import './style.scss';
registerBlockType('my-custom-block/container', {
edit: Edit,
save,
});
编辑 src/edit.js
在编辑视图中使用 wp:image 块:
import { __ } from '@wordpress/i18n';
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
const ALLOWED_BLOCKS = ['core/image'];
const Edit = ({ attributes, setAttributes }) => {
const blockProps = useBlockProps();
return (
<div {...blockProps}>
<h2>{__('My Custom Block', 'my-custom-block')}</h2>
<InnerBlocks allowedBlocks={ALLOWED_BLOCKS} />
</div>
);
};
export default Edit;
编辑 src/save.js
保存视图支持嵌套内容:
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
const save = ({ attributes }) => {
const blockProps = useBlockProps.save();
return (
<div {...blockProps}>
<InnerBlocks.Content />
</div>
);
};
export default save;
编辑 src/style.scss
定义区块的样式:
/* style.scss - 前端样式 */
.wp-block-my-custom-block-container {
padding: 20px;
border: 1px solid #ccc;
}
/* editor.scss - 编辑器样式 */
.wp-block-my-custom-block-container {
padding: 20px;
border: 1px dashed #ccc;
}
构建区块
在项目目录中运行以下命令以构建 JavaScript 和样式文件:
npm install
npm run build
加载区块
在 WordPress 插件或主题中注册和加载区块。
插件主文件(例如 my-custom-block.php):
<?php
/*
Plugin Name: My Custom Block
Description: A custom block with nested image block.
Version: 1.0
Author: Your Name
*/
function my_custom_block_register() {
register_block_type(__DIR__);
}
add_action('init', 'my_custom_block_register');
?>
使用区块属性
如果需要在自定义区块中使用区块属性,可以在 edit.js 和 save.js 中处理属性。例如,为图片块添加自定义属性:
// edit.js
const ALLOWED_BLOCKS = ['core/image'];
const Edit = ({ attributes, setAttributes }) => {
const blockProps = useBlockProps();
return (
<div {...blockProps}>
<h2>{__('My Custom Block', 'my-custom-block')}</h2>
<InnerBlocks
allowedBlocks={ALLOWED_BLOCKS}
template={[
['core/image', { align: 'center' }]
]}
/>
</div>
);
};
// save.js
const save = ({ attributes }) => {
const blockProps = useBlockProps.save();
return (
<div {...blockProps}>
<InnerBlocks.Content />
</div>
);
};
使用 InspectorControls
你可以使用 InspectorControls 添加额外的设置:
// edit.js
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl } from '@wordpress/components';
const Edit = ({ attributes, setAttributes }) => {
const blockProps = useBlockProps();
return (
<div {...blockProps}>
<InspectorControls>
<PanelBody title={__('Settings', 'my-custom-block')}>
<TextControl
label={__('Example Setting', 'my-custom-block')}
value={attributes.exampleSetting}
onChange={(value) => setAttributes({ exampleSetting: value })}
/>
</PanelBody>
</InspectorControls>
<h2>{__('My Custom Block', 'my-custom-block')}</h2>
<InnerBlocks allowedBlocks={ALLOWED_BLOCKS} />
</div>
);
};
如果你需要在前端显示自定义的样式或脚本,可以在 style.scss 中定义样式,或在保存视图中添加自定义 HTML 结构。
自定义前端样式
/* style.scss */
.wp-block-my-custom-block-container .wp-block-image img {
border-radius: 50%;
}
总结
通过以上步骤,你可以开发一个自定义 WordPress 区块,并在其中嵌套使用 wp:image(即 core/image)等其他核心区块。此流程包括:
通过这种方式,你可以在自定义区块中实现复杂的布局和功能,利用 WordPress 提供的区块编辑器 API 构建动态和互动性强的内容块。
]]>在 WordPress 中开发高度自定义的区块(blocks)除了使用 HTML,还可以利用现代 JavaScript、React、和 WordPress 的 @wordpress/block-editor 和 @wordpress/blocks 等包。这里是详细步骤,包括设置开发环境、创建区块、以及如何实现自定义功能。
使用 @wordpress/create-block 工具
WordPress 提供了 @wordpress/create-block 工具,简化区块开发的基本设置。
npx @wordpress/create-block my-custom-block
这会创建一个新项目文件夹 my-custom-block,包含所有必要的文件和配置。
文件结构
my-custom-block/
├── build/
├── src/
│ ├── index.js
│ ├── edit.js
│ ├── save.js
│ ├── style.scss
│ └── editor.scss
├── block.json
├── package.json
├── README.md
└── webpack.config.js
重要文件
编写区块代码
block.json
定义区块的基本信息:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "my-custom-block/block",
"title": "My Custom Block",
"category": "widgets",
"icon": "smiley",
"description": "A custom block example.",
"supports": {
"html": false
},
"textdomain": "my-custom-block",
"editorScript": "file:./build/index.js",
"editorStyle": "file:./build/editor.css",
"style": "file:./build/style.css"
}
src/index.js
注册区块:
import { registerBlockType } from '@wordpress/blocks';
import Edit from './edit';
import save from './save';
import './style.scss';
registerBlockType('my-custom-block/block', {
edit: Edit,
save,
});
src/edit.js
定义编辑视图:
import { useBlockProps } from '@wordpress/block-editor';
import { TextControl } from '@wordpress/components';
const Edit = ({ attributes, setAttributes }) => {
const blockProps = useBlockProps();
return (
<div {...blockProps}>
<TextControl
label="Example Text"
value={attributes.exampleText}
onChange={(value) => setAttributes({ exampleText: value })}
/>
</div>
);
};
export default Edit;
src/save.js
定义保存视图:
import { useBlockProps } from '@wordpress/block-editor';
const save = ({ attributes }) => {
const blockProps = useBlockProps.save();
return (
<div {...blockProps}>
{attributes.exampleText}
</div>
);
};
export default save;
src/style.scss 和 src/editor.scss
定义区块的样式:
/* style.scss - 前端样式 */
.wp-block-my-custom-block-block {
padding: 20px;
border: 1px solid #ccc;
}
/* editor.scss - 编辑器样式 */
.wp-block-my-custom-block-block {
padding: 20px;
border: 1px dashed #ccc;
}
使用 npm 脚本来打包区块:
npm install
npm run build
这会编译你的 JavaScript 和 SCSS 文件到 build 目录。
确保在你的 WordPress 主题或插件中注册和加载区块。
PHP 代码
在插件或主题的 PHP 文件中:
function my_custom_block_register() {
register_block_type(__DIR__);
}
add_action('init', 'my_custom_block_register');
使用更多 React 组件
你可以使用 WordPress 提供的各种 React 组件,如 TextControl, MediaUpload, InspectorControls 等,以增强区块的功能。
import { InspectorControls, MediaUpload } from '@wordpress/block-editor';
import { Button, PanelBody } from '@wordpress/components';
// 在 edit.js 中使用这些组件
<InspectorControls>
<PanelBody title="Media Settings">
<MediaUpload
onSelect={(media) => setAttributes({ mediaId: media.id, mediaUrl: media.url })}
allowedTypes={['image']}
render={({ open }) => (
<Button onClick={open} className="button button-large">
Select Image
</Button>
)}
/>
</PanelBody>
</InspectorControls>
动态区块
创建动态区块可以在保存时执行 PHP 代码生成内容:
function render_my_custom_block($attributes, $content) {
// 使用 $attributes 和 $content 来生成动态内容
return '<div class="my-custom-block">' . esc_html($attributes['exampleText']) . '</div>';
}
register_block_type('my-custom-block/block', [
'render_callback' => 'render_my_custom_block',
]);
总结
开发高度自定义的 WordPress 区块涉及现代 JavaScript(尤其是 React)和 WordPress 提供的区块编辑器 API。你可以从基础的 HTML 开始,逐步增加交互性和复杂性。这里是主要步骤:
这种方法可以让你在 WordPress 中创建功能丰富且高度自定义的区块,满足各种复杂的需求。
]]>要在博客网站右上角添加悬挂年兽喜迎龙年的元素,你可以通过在 Typecho 主题中添加自定义 HTML 代码和 CSS 样式来实现。以下是具体的步骤:
<div style="position: absolute; top: 10px; right: 10px;">
<img src="path/to/your/image.png" alt="悬挂年兽" style="width: 100px; height: 100px;">
</div>
请将 path/to/your/image.png 替换为你准备好的悬挂年兽图片路径,并调整 width 和 height 属性以适应你的布局。
img#hangYearBeast {
position: absolute;
top: 10px;
right: 10px;
width: 100px;
height: 100px;
z-index: 9999; /* 确保悬挂年兽在最上层 */
}
请根据实际情况调整样式。
刷新你的博客网站,现在右上角应该会显示悬挂年兽的元素了。
如果有任何问题或需要进一步帮助,请随时告诉我。
祝您新年快乐!
]]>为了在WordPress主题中的LOGO上增加扫光效果,你可以通过添加一些CSS代码来实现这种视觉动画。
这里我将提供一个简单的CSS扫光效果示例,你可以根据需要调整样式和动画的具体参数。
步骤 1: 定位LOGO元素
首先,你需要确定你的WordPress主题中LOGO的CSS选择器。通常这可以在主题的HTML结构中找到,例如它可能是一个图片 ( < img > 或者一个链接 (< a >) 包含一个图片。例如,假设LOGO的HTML是这样的:
<a href="/" class="custom-logo-link">
<img src="logo.png" class="custom-logo">
</a>
步骤 2: 添加CSS扫光效果
接下来,你可以在主题的CSS文件中添加以下样式或者在WordPress后台的外观 -> 自定义 -> 额外的CSS中添加:
.custom-logo-link {
position: relative;
display: inline-block; /* 确保a标签是块级元素 */
}
.custom-logo-link::after {
content: '';
position: absolute;
top: 0;
left: -75%;
width: 150%;
height: 100%;
background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.8) 50%, rgba(255,255,255,0) 100%);
animation: sweep 3s infinite;
z-index: 1;
}
@keyframes sweep {
0% {
left: -75%;
}
100% {
left: 100%;
}
}
解释:
步骤 3: 调整和测试
你可能需要根据你的LOGO的尺寸和网站的具体布局调整上述CSS代码中的一些值,比如伪元素的宽度、高度或动画速度等。
通过这种方式,你可以为WordPress网站的LOGO添加一个简单而吸引人的扫光动画效果,使网站看起来更加动态和专业。
]]>为了实现在WordPress网站中美化浏览器右侧的多色滚动条,并且支持360浏览器、QQ浏览器和谷歌浏览器,您可以使用以下CSS代码来实现:
/* Webkit浏览器(Chrome、Safari)样式 */
::-webkit-scrollbar {
width: 12px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
}
::-webkit-scrollbar-thumb {
background: linear-gradient(45deg, #ff0000, #00ff00, #0000ff);
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: linear-gradient(45deg, #00ff00, #0000ff, #ff0000);
}
/* Firefox浏览器样式 */
* {
scrollbar-width: thin;
scrollbar-color: #ff0000 #00ff00;
}
/* IE浏览器样式 */
body {
scrollbar-base-color: #0000ff;
scrollbar-arrow-color: #ff0000;
scrollbar-face-color: #00ff00;
}
上面的代码中,我们分别提供了针对Webkit浏览器、Firefox浏览器和IE浏览器的滚动条样式设置。
您可以根据需要调整颜色和样式属性。
将这段代码添加到您的WordPress主题的CSS文件中,然后保存并刷新您的网站,您应该能够看到自定义样式的滚动条效果。
请注意,由于不同浏览器对滚动条样式的支持程度不同,可能会有一些样式在某些浏览器上不起作用。如
果您需要更多定制化的支持或有其他问题,请随时告诉我。
]]>