由点组成的圆盘
<style>#wrap {
margin: 30px auto;
width: 200px;
height: 200px;
display: grid;
place-items: center;
position: relative;
}
#wrap >span {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
border: 8px dotted black;
}
</style>
<p>先看效果:<br><br></p>
<div id="wrap"></div>
<script>
Array.from({length:10}).forEach((item,key) => {
let sp = document.createElement('span');
sp.style.cssText += `
width: ${key*18}px;
height: ${key*18}px;
border-color: #${Math.random().toString(16).substr(-6)};
`;
wrap.appendChild(sp);
});
</script>
<p><br><br>然后我将在后续的回复中逐一讲解——</p> 本帖最后由 马黑黑 于 2023-4-8 21:23 编辑
先说一下HTML结构:
<div id="wrap">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
这是一个 div 父元素 wrap 带十个 span 子元素的简单结构。在实际实现一楼的效果中,我并没有这么写HTML代码,而是这样写:
<div id="wrap"></div>
没有 span 元素。为什么?因为,这些 span 元素涉及到诸多的算法,如果全用 CSS+HTML 写出来代码会有些繁琐,可以使用JS来高效实现。不过结构如此,理解了结构有助于对后续实现原理的理解。下面就说说——
实现原理:
父元素 wrap 起到包裹和约束子元素的作用,#wrap 选择器将定义为 grip 布局并设置其子元素绝对居中(即横向纵向两个方向都居中),仅此而已。
10 个 span 子元素,宽高从里到外,依次设置为外比里大一定尺寸的像素值,而它们的边框(border)设置为统一的尺寸值,样式风格为 dotted(小圆点),设置任意的初始边框颜色(后面JS会覆盖掉它们的边框颜色)。
本帖最后由 马黑黑 于 2023-4-8 18:50 编辑 <br /><br /><style>
.papa > p { margin: 10px 0; }
.wrap {
margin: 30px auto;
width: 200px;
height: 200px;
display: grid;
place-items: center;
border: 1px solid purple;
position: relative;
}
.wrap >span {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
border: 8px dotted black;
}
</style>
<div class="papa">
<p><font color="#ff0000">实现步骤</font>(一):</p>
<p>首先,先写好 #wrap 选择器的CSS代码和wrap元素的HTML代码:</p>
<blockquote><pre>
<style>
#wrap {
margin: 30px auto;
width: 200px;
height: 200px;
display: grid;
place-items: center;
position: relative;
border: 1px solid purple;
}
</style>
<div class="wrap"></div>
</pre></blockquote>
<p>#wrap 选择器的最后一句设置了一个边框,用来协助观察,将来弄好了要删掉它。这样,父元素准备好了,效果如下:</p>
<div class="wrap"></div>
<p>一楼效果的那些点,将会呈现在上面这个方框里。</p>
</div> 本帖最后由 马黑黑 于 2023-4-8 22:42 编辑 <br /><br /><style>
.wrap > span {
position: absolute;
width: 0;
height: 0;
border-radius: 50%;
border: 8px dotted black;
}
.wrap > span:nth-of-type(2) {
width: 18px;
height: 18px;
border-color: red;
}
</style>
<div class="papa">
<p><font color="#ff0000">实现步骤</font>(二):</p>
<p>这个步骤是尝试性质,主要是推演一下各个 span 子元素的宽高尺寸算法。当然,span 的基本CSS设置,最终效果会用到,所以应加入到CSS代码中。下面,我们就给 span 标签做一个基本设置,它隶属于 wrap,是 wrap 的子元素,所以我们可以这样写这些 span 标签的共性基本代码:</p>
<blockquote><pre><style>
#wrap {
margin: 30px auto;
width: 200px;
height: 200px;
display: grid;
place-items: center;
position: relative;
border: 1px solid purple;
}
#wrap > span {
position: absolute;
width: 0;
height: 0;
border-radius: 50%;
border: 8px dotted black;
}
</style>
<div id="wrap">
<span></span>
</div>
</pre></blockquote>
<p>运行以上代码,效果如下:</p>
<div class="wrap"><span></span></div>
<p>如果我们有第二个 span 标签,它会覆盖在第一个标签之上,因而,我们需要为第二个 span 标签单独设置更大的尺寸以及其它属性:</p>
<blockqute><pre>#wrap > span:nth-of-type(2) {
width: 18px;
height: 18px;
border-color: red;
}
</pre></blockqute>
<p>为什么宽高设置为18px呢?首先,这是为所有的 span 预设了一个规律:每一个 span 的宽高尺寸都按自己的索引乘以18,第一个 span 的索引是 0,0 乘以 18 等于 0,正是CSS里所设计的,第二个索引是1,乘以18就是18,其余依次类推;其次,18的依据是,span 的边框厚度是8,当 span 的宽高为 0 时,它实际占位是16个像素,我们给第二个 span 的宽高都加上 2 ,是希望它与第一个拉开 2px 的距离。</p>
<p>现在,我们给HTML代码加一组 span 标签,看看效果:</p>
<div class="wrap"><span></span><span></span></div>
</div> 本帖最后由 马黑黑 于 2023-4-8 21:32 编辑
实现步骤(三):
前面,在尝试性的步骤二中,我们预设了 wrap 父元素的 span 子元素一些规则:最里边的 span 宽高为0,它由 border 边框构成一个 8 像素的圆点,它之外两个两个像素处是它的第一个兄弟,宽高为 10 像素,边框厚度同样是 4 个像素。接着,下一个兄弟,排行老三,索引号是2,它的宽高尺寸按照预设规则是 2*18 = 36 个像素,其余的依此类推。嗯,写 10个 #wrap > span:nth-of-type(x) 很繁琐,这个工作可以交给 JS 完成:
<script>
Array.from({length:10}).forEach((item,key) => {
let sp = document.createElement('span');
sp.style.cssText += `
width: ${key*18}px;
height: ${key*18}px;
border-color: #${Math.random().toString(16).substr(-6)};
`;
wrap.appendChild(sp);
});
</script>
Array.from({length:10}) 构建了一个有 10 个数组元素的数组,如果想修改 span 子元素的个数,将 10 改为其他数字就好。
接着,使用 forEach 循环方法,为上述数组的每一个数组元素构建 span 标签并追加到 wrap 元素中。这些 span 标签,每一个都以自己的索引号 key 乘以 18,它的边框颜色(border-color)取16进制随机值。因为事先存在了 span 标签的CSS设定,因此 span 子标签变量 sp 的 style.cssText 采用 += 的方式追加,注意我们使用了反引号 `` ,因之我们可以将CSS语句分行写,里面涉及到JS变量和运算式子时,用 ${...} 表示,该语句的 ... 即为JS变量或运算式子。
一楼效果的完整代码放在下一层楼。
本帖最后由 马黑黑 于 2023-4-8 21:00 编辑
一楼效果完整代码:
<style>
#wrap {
margin: 30px auto;
width: 200px;
height: 200px;
display: grid;
place-items: center;
position: relative;
}
#wrap > span {
position: absolute;
width: 0;
height: 0;
border-radius: 50%;
border: 8px dotted black;
}
#wrap > span:nth-of-type(2) {
width: 18px;
height: 18px;
border-color: red;
}
</style>
<div id="wrap"></div>
<script>
Array.from({length:10}).forEach((item,key) => {
let sp = document.createElement('span');
sp.style.cssText += `
width: ${key*18}px;
height: ${key*18}px;
border-color: #${Math.random().toString(16).substr(-6)};
`;
wrap.appendChild(sp);
});
</script>
本帖最后由 马黑黑 于 2023-4-9 00:23 编辑
占位六:扩展应用
<style>
.wrap {
margin: 30px auto;
width: 200px;
height: 200px;
display: grid;
place-items: center;
position: relative;
border: 1px solid tan;
--deg: 0deg; --state: running; --time: 10s;
}
.wrap > span {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
border: 8px dashed black;
transform: rotate(var(--deg));
animation: rot var(--time) infinite linear var(--state);
}
@keyframes rot {
from { transform: rotate(var(--deg)); }
to { transform: rotate(calc(var(--deg) + 360deg)); }
}
</style>
<div class="wrap"></div>
<script>
let wrap = document.querySelector('.wrap'), root = document.querySelector(':root');
Array.from({length:10}).forEach((item,key) => {
let sp = document.createElement('span');
sp.style.cssText += `
--deg: ${Math.random()*(key+10)}deg;
--time: ${Math.random()*10+10}s;
width: ${key*18}px;
height: ${key*18}px;
border-color: #${Math.random().toString(16).substr(-6)};
border-width: ${key+4}px;
`;
wrap.appendChild(sp);
});
</script>
现在可以回帖了 黑黑这个圆盘是为后面做播放器组排准备吧 小辣椒 发表于 2023-4-8 21:38
黑黑这个圆盘是为后面做播放器组排准备吧
也未必吧,主要是觉得它好看。类似的结构,doodle 框架有一个非常漂亮的示例,我研究了一下,决定用原生 JS 做一个相近的(二者并不一样)。
小辣椒 发表于 2023-4-8 21:37
现在可以回帖了
早就可以会了,该站位的俺都占了{:5_106:} 马黑黑 发表于 2023-4-8 21:42
也未必吧,主要是觉得它好看。类似的结构,doodle 框架有一个非常漂亮的示例,我研究了一下,决定用原生...
反正小辣椒就套用学习的{:4_170:} 马黑黑 发表于 2023-4-8 21:43
早就可以会了,该站位的俺都占了
我特意等一下的,怕占了楼 小辣椒 发表于 2023-4-8 22:00
我特意等一下的,怕占了楼
我早占了额 小辣椒 发表于 2023-4-8 21:59
反正小辣椒就套用学习的
基础知识不懂还是不行的 马黑黑 发表于 2023-4-8 17:48
本帖最后由 马黑黑 于 2023-4-8 21:27 编辑
.wrap > span {
position: absolute;
到这步已经不懂了,为什么“span 的边框厚度是4“?不是设置了8px么? 红影 发表于 2023-4-8 22:38
到这步已经不懂了,为什么“span 的边框厚度是4“?不是设置了8px么?
额,那是我描述错误。应该是酱紫:
第一个span,宽高为0,边框厚度是8,实际占位是16,加上两个像素的差距,所以第二个span的宽高是18,其他的依此类推。 马黑黑 发表于 2023-4-8 22:44
额,那是我描述错误。应该是酱紫:
第一个span,宽高为0,边框厚度是8,实际占位是16,加上两个像素的 ...
这样说好像能懂点,可是,第二个也有厚度,若是16,再加上第二个的厚度,那么2个像素出不来啊。实际上却出来了,我就是没弄明白怎么出来的。
我拿像素尺去量了一下,那个黑点是8不是16
如果第一和第二个都是8,那么用18的宽高,剩下的间隙是1个像素,不是2个。只是从第二个开始,看着都小了一半啊。今天跑出忙一天,脑袋有点晕,黑黑勿怪{:5_109:} 红影 发表于 2023-4-8 23:10
这样说好像能懂点,可是,第二个也有厚度,若是16,再加上第二个的厚度,那么2个像素出不来啊。实际上却 ...
黑点绝对是 16px,你再量一量。
第一个span实际占位16px;第二个18px宽高,肯定于前一个 16px实际占位拉开2px的距离,再加上8px边框,实际占位 18+8*2 = 34px;第三个span,2*18=36px,离第二个也拉开2px,加上 2*8=16的边框,它实际占位 2*18 + 2*8 = 52 ……
这里面的算法是没有问题的 马黑黑 发表于 2023-4-8 23:39
黑点绝对是 16px,你再量一量。
第一个span实际占位16px;第二个18px宽高,肯定于前一个 16px实际占位 ...
对对,边框是向外的,我又弄错了,以为是骑在线上的,哈哈,弄错第二次了都,下回坚决要记住了{:4_170:}