html - 尝试使用 div 创建相机快门效果
问题描述
我试图制作一个圆形相机快门,但我无法让它看起来正确。
它应该是这样的:
第一个“花瓣”应低于最后一个,高于下一个。怎么做?
下面是我尝试过的:
let partAmount = 10;
let cont = document.getElementById('cont');
let parts = [];
for(let i = 1; i <= partAmount; i++){
let partCont = createElement('div','partCont');
let part = createElement('div','part');
parts.push(part);
partCont.appendChild(part);
cont.appendChild(partCont);
partCont.style.transform = 'rotate('+ 360 / partAmount * i+'deg) translatey(-250px)';
}
function createElement(tag,className){
let elem = document.createElement(tag);
elem.classList.add(className);
return elem;
}
#cont{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
border-radius: 50%;
}
.dia{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 300px;
height: 300px;
border-radius: 50%;
overflow: hidden;
}
.partCont{
position: absolute;
transform-origin: left top;
}
.part{
width: 500px;
height: 100px;
background-color: lightgray;
border-bottom: 3px solid gray;
box-sizing: border-box;
transform-origin: left bottom;
transform: rotate(60deg);
transition-duration: 1s;
}
<div class="dia">
<div id="cont">
</div>
</div>
解决方案
这里的诀窍是考虑到你有一个对称的形状这一事实,所以你可以使用两个不同的元素来构建它,你应用相同的东西,然后旋转其中一个来创造一种形状的错觉。
我将在上一个问题中考虑相同的想法,并依靠多种背景linear-gradient
来创建:
.camera{
width:200px;
height:200px;
margin:auto;
border-radius: 50%;
border:1px solid;
overflow:hidden;
position:relative;
--c1: transparent 55%,#000 calc(55% + 1px) calc(55% + 4px),grey calc(55% + 5px);
--c2: transparent 40%,#000 calc(40% + 1px) calc(40% + 4px),grey calc(40% + 5px);
}
.camera::before,
.camera::after{
content:"";
position:absolute;
top:0;
left:0;
height:100%;
width:50%;
background:
linear-gradient(-153deg,var(--c1)),
linear-gradient(-107deg,var(--c2)),
linear-gradient(-73deg ,var(--c2)),
linear-gradient(-27deg ,var(--c1));
}
.camera::after {
transform:rotate(180deg);
transform-origin:right;
}
<div class="camera">
</div>
正如您在上面看到的,我们几乎接近了,我们可以使用下面的额外渐变添加两条缺失的线:
.camera{
width:200px;
height:200px;
margin:auto;
border-radius: 50%;
border:1px solid;
overflow:hidden;
position:relative;
--c1: transparent 55%,#000 calc(55% + 1px) calc(55% + 4px),grey calc(55% + 5px);
--c2: transparent 40%,#000 calc(40% + 1px) calc(40% + 4px),grey calc(40% + 5px);
}
.camera::before,
.camera::after{
content:"";
position:absolute;
top:0;
left:0;
height:100%;
width:50%;
background:
linear-gradient( 153deg,var(--c1)) bottom/100% 43.5% no-repeat,
linear-gradient(-153deg,var(--c1)),
linear-gradient(-107deg,var(--c2)),
linear-gradient(-73deg ,var(--c2)), /* 180 - 107 = 73deg*/
linear-gradient(-27deg ,var(--c1)); /* 180 - 153 = 27deg*/
}
.camera::after{
transform:rotate(180deg);
transform-origin:right;
}
<div class="camera">
</div>
一些数学
如果我们需要精确计算,我们应该考虑到里面绘制的形状是一个八边形:
由此我们可以确定旋转的角度。第一个将是45deg/2 = 22.5deg
。然后我们递增45deg
以找到其他人:
然后代码将变为:
.camera{
width:200px;
height:200px;
margin:auto;
border-radius: 50%;
border:1px solid;
overflow:hidden;
position:relative;
--p1:55%;
--p2:40%;
--c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 4px),grey calc(var(--p1) + 5px);
--c2: transparent var(--p2),#000 calc(var(--p2) + 1px)calc(var(--p2) + 4px),grey calc(var(--p2) + 5px);
}
.camera::before,
.camera::after{
content:"";
position:absolute;
top:0;
left:0;
height:100%;
width:50%;
background:
linear-gradient( 112.5deg,var(--c1)) bottom right/10% 14% no-repeat,
linear-gradient( 157.5deg,var(--c1)) bottom /100% 54% no-repeat,
linear-gradient(-157.5deg,var(--c1)), /* -135deg */
linear-gradient(-112.5deg,var(--c2)), /* -90deg */
linear-gradient(-67.5deg ,var(--c2)), /* -45deg */
linear-gradient(-22.5deg ,var(--c1));
}
.camera::after{
transform:rotate(180deg);
transform-origin:right;
}
<div class="camera">
</div>
您会注意到我们将需要 2 个额外的渐变,因为会有更多的缺失线。
要控制形状,您必须调整色标(--p1
和--p2
)的值并纠正额外渐变的尺寸(仍然需要找到这些值之间的关系)
.camera{
width:200px;
height:200px;
display:inline-block;
border-radius: 50%;
border:1px solid;
overflow:hidden;
position:relative;
--p1:55%;
--p2:40%;
--c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 4px),grey calc(var(--p1) + 5px);
--c2: transparent var(--p2),#000 calc(var(--p2) + 1px)calc(var(--p2) + 4px),grey calc(var(--p2) + 5px);
}
.camera::before,
.camera::after{
content:"";
position:absolute;
top:0;
left:0;
height:100%;
width:50%;
background:
linear-gradient( 112.5deg,var(--c1)) bottom right/var(--e1,10%) var(--e2,14%) no-repeat,
linear-gradient( 157.5deg,var(--c1)) bottom /100% var(--e3,54%) no-repeat,
linear-gradient(-157.5deg,var(--c1)), /* -135deg */
linear-gradient(-112.5deg,var(--c2)), /* -90deg */
linear-gradient(-67.5deg ,var(--c2)), /* -45deg */
linear-gradient(-22.5deg ,var(--c1));
}
.camera::after{
transform:rotate(180deg);
transform-origin:right;
}
<div class="camera">
</div>
<div class="camera" style="--p1:65%;--p2:55%; --e1:0;--e3:40%">
</div>
<div class="camera" style="--p1: 46%;--p2: 29%; --e1: 26%;--e2: 35%;--e3: 62%;">
</div>
我们可以通过添加更多层轻松移动到任何多边形形状并正确计算旋转度数。
十边形的示例:
.camera{
width:200px;
height:200px;
display:inline-block;
border-radius: 50%;
border:1px solid;
overflow:hidden;
position:relative;
--p1:60%;
--p2:48%;
--p3:38%;
--c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 4px),grey calc(var(--p1) + 5px);
--c2: transparent var(--p2),#000 calc(var(--p2) + 1px) calc(var(--p2) + 4px),grey calc(var(--p2) + 5px);
--c3: transparent var(--p3),#000 calc(var(--p3) + 1px) calc(var(--p3) + 4px),grey calc(var(--p3) + 5px);
}
.camera::before,
.camera::after{
content:"";
position:absolute;
top:0;
left:0;
height:100%;
width:50%;
background:
linear-gradient( 126deg,var(--c1)) bottom right/var(--e1,40%) var(--e2,20%) no-repeat,
linear-gradient( 162deg,var(--c1)) bottom /100% var(--e3,60%) no-repeat,
linear-gradient(-162deg,var(--c1)),
linear-gradient(-126deg,var(--c2)),
linear-gradient(-90deg, var(--c3)),
linear-gradient(-54deg ,var(--c2)),
linear-gradient(-18deg ,var(--c1)); /* 36deg/2 then we increment by 36deg*/
}
.camera::after{
transform:rotate(180deg);
transform-origin:right;
}
<div class="camera">
</div>
<div class="camera" style="--p1: 66.5%;--p2: 56%;--p3: 51%; --e3: 51%;--e2: 8%;--e1: 13%;">
</div>
<div class="camera" style="--p1: 50%;--p2: 37%;--p3: 15%; --e3: 68%;--e2: 41%;--e1: 50%;">
</div>
由于我们正在处理背景,我们可以为图像添加一个额外的图层:
#camera{
width:200px;
height:200px;
display:inline-block;
border-radius: 50%;
border:1px solid;
overflow:hidden;
position:relative;
background:url(https://picsum.photos/id/155/800/800) center/80% 80%;
--p1:60%;
--p2:48%;
--p3:38%;
--c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 3px),grey calc(var(--p1) + 4px);
--c2: transparent var(--p2),#000 calc(var(--p2) + 1px) calc(var(--p2) + 3px),grey calc(var(--p2) + 4px);
--c3: transparent var(--p3),#000 calc(var(--p3) + 1px) calc(var(--p3) + 3px),grey calc(var(--p3) + 4px);
}
#camera::before,
#camera::after{
content:"";
position:absolute;
top:0;
left:0;
height:100%;
width:50%;
background:
linear-gradient( 126deg,var(--c1)) bottom right/var(--e1,40%) var(--e2,20%) no-repeat,
linear-gradient( 162deg,var(--c1)) bottom /100% var(--e3,60%) no-repeat,
linear-gradient(-162deg,var(--c1)),
linear-gradient(-126deg,var(--c2)),
linear-gradient(-90deg, var(--c3)),
linear-gradient(-54deg ,var(--c2)),
linear-gradient(-18deg ,var(--c1)); /* 36deg/2 then we increment by 36deg*/
}
#camera::after{
transform:rotate(180deg);
transform-origin:right;
}
<div id="camera">
</div>
<div id="camera" style="--p1: 66.5%;--p2: 56%;--p3: 51%; --e3: 51%;--e2: 8%;--e1: 13%;">
</div>
<div id="camera" style="--p1: 50%;--p2: 37%;--p3: 15%; --e3: 68%;--e2: 41%;--e1: 50%;">
</div>
如果您想切换百叶窗的方向,只需将所有角度乘以-1
并切换一些左/右
.camera{
width:200px;
height:200px;
display:inline-block;
border-radius: 50%;
border:1px solid;
overflow:hidden;
position:relative;
--p1:60%;
--p2:48%;
--p3:38%;
--c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 4px),grey calc(var(--p1) + 5px);
--c2: transparent var(--p2),#000 calc(var(--p2) + 1px) calc(var(--p2) + 4px),grey calc(var(--p2) + 5px);
--c3: transparent var(--p3),#000 calc(var(--p3) + 1px) calc(var(--p3) + 4px),grey calc(var(--p3) + 5px);
}
.camera::before,
.camera::after{
content:"";
position:absolute;
top:0;
/*left:0;*/ right:0;
height:100%;
width:50%;
background:
linear-gradient(-126deg,var(--c1)) bottom left/var(--e1,40%) var(--e2,20%) no-repeat,
linear-gradient(-162deg,var(--c1)) bottom /100% var(--e3,60%) no-repeat,
linear-gradient(162deg,var(--c1)),
linear-gradient(126deg,var(--c2)),
linear-gradient(90deg, var(--c3)),
linear-gradient(54deg ,var(--c2)),
linear-gradient(18deg ,var(--c1)); /* 36deg/2 then we increment by 36deg*/
}
.camera::after{
transform:rotate(180deg);
/*transform-origin:right;*/transform-origin:left;
}
<div class="camera">
</div>
<div class="camera" style="--p1: 66.5%;--p2: 56%;--p3: 51%; --e3: 51%;--e2: 8%;--e1: 13%;">
</div>
<div class="camera" style="--p1: 50%;--p2: 37%;--p3: 15%; --e3: 68%;--e2: 41%;--e1: 50%;">
</div>
带动画
这是一个创建百叶窗打开/关闭动画的想法:
.camera{
width:200px;
height:200px;
display:inline-block;
border-radius: 50%;
border:1px solid;
overflow:hidden;
position:relative;
background:url(https://picsum.photos/id/155/800/800) center/cover;
--p1:60%;
--p2:48%;
--p3:38%;
--c1: transparent var(--p1),#000 calc(var(--p1) + 1px) calc(var(--p1) + 4px),grey calc(var(--p1) + 5px);
--c2: transparent var(--p2),#000 calc(var(--p2) + 1px) calc(var(--p2) + 4px),grey calc(var(--p2) + 5px);
--c3: transparent var(--p3),#000 calc(var(--p3) + 1px) calc(var(--p3) + 4px),grey calc(var(--p3) + 5px);
}
.camera::before,
.camera::after{
content:"";
position:absolute;
top:-50%;
left:50%;
height:200%;
width:100%;
transition:.5s all linear;
background:
linear-gradient(-126deg,var(--c1)) bottom left/var(--e1,40%) var(--e2,20%) no-repeat,
linear-gradient(-162deg,var(--c1)) bottom /100% var(--e3,60%) no-repeat,
linear-gradient(162deg,var(--c1)),
linear-gradient(126deg,var(--c2)),
linear-gradient(90deg, var(--c3)),
linear-gradient(54deg ,var(--c2)),
linear-gradient(18deg ,var(--c1)); /* 36deg/2 then we increment by 36deg*/
}
.camera::after{
transform:rotate(180deg);
transform-origin:left;
}
.camera:hover::before,
.camera:hover::after {
top:0;
left:50%;
height:100%;
width:50%;
}
<div class="camera">
</div>
我们只需要通过保持相同的位置来增加/减少伪元素的大小。
替代解决方案
我们可以结合您的代码和两个对称形状的想法并创建如下:
let partAmount = 10;
let cont = document.querySelector('.cont');
let parts = [];
for(let i = 1; i <= partAmount ; i++){
let partCont = createElement('div','partCont');
let part = createElement('div','part');
parts.push(part);
partCont.appendChild(part);
cont.appendChild(partCont);
partCont.style.transform = 'rotate('+ 360 / partAmount * i+'deg) translatey(-250px)';
}
function createElement(tag,className){
let elem = document.createElement(tag);
elem.classList.add(className);
return elem;
}
/*added*/
let alt = cont.cloneNode(true);
document.querySelector('.dia').appendChild(alt);
.cont{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
border-radius: 50%;
clip-path: polygon(0 -150px, 0 150px, -150px 150px,-150px -150px); /*added*/
}
.cont:last-child {
transform:rotate(180deg); /*added*/
}
.dia{
width: 300px;
height: 300px;
border-radius: 50%;
overflow: hidden;
position:relative;
}
.partCont{
position: absolute;
transform-origin: left top;
}
.part{
width: 300px;
height: 100px;
background-color: lightgray;
border-bottom: 3px solid gray;
box-sizing: border-box;
transform-origin: left bottom;
transform: rotate(60deg);
transition-duration: 1s;
}
<div class="dia">
<div class="cont">
</div>
</div>
推荐阅读
- android - 如何使用 agora.io 将铃声添加到我的应用程序
- ruby-on-rails - 如何使用 Azure Pipelines 将 Ruby 部署到 Azure 应用服务?
- javascript - Date-fns 格式函数显示下一个日期而不是预期的日期
- arraylist - Java8过滤器数组列表与字段日期的自定义对象
- r - 如何在 kableExtra 表的单元格中增加字体大小并调整多行中的字符串?
- android - SCALER_CROP_REGION 如何在 camera2 和原生相机中工作?
- typescript - Typescript 通用可调用构造函数类型
- asp.net-mvc - 如何在 ASP.NET MVC 中集成条带?
- reactjs - 如何监听路由器的变化并强制类组件重新渲染?
- google-apps-script - Apps 脚本将数据导出到另一个电子表格,在 xlsx 中构建并附加到电子邮件