カテゴリー
【CSS/Sass】box-shadowプロパティでパーティクルを生成してみる
※ 当ページには【広告/PR】を含む場合があります。
2019/09/12
2023/12/21
<li>
<ul>
<li></li>
<li></li>
<li></li>
<!-- ... -->
<!-- とにかく欲しいだけli要素を記述 -->
<!-- ... -->
<li></li>
</ul>
li:nth-child(1) {
/* 1つ目の円 = 1番目のli */
transform: translate(0px, 0px);
}
li:nth-child(2) {
/* 2つ目の円 = 2番目のli */
transform: translate(100px, 100px);
}
li:nth-child(3) {
/* 3つ目の円 = 3番目のli */
transform: translate(200px, 200px);
}
/* 以下、li要素の数だけ繰り返し */
transformプロパティ
box-shadowプロパティのoffsetを利用する
box-shadowの基本
<div class="circle"></div>
.circle {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: black;
}
box-shadow
.circle {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: black;
box-shadow: 25px 0px black;
}
.circle-b3 {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: black;
box-shadow: 25px 0px black,
50px 0px black;
}
translate()
.circle {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: black;
box-shadow: 25px 0px black,
50px 0px black,
0px 25px black,
25px 25px black,
50px 25px black,
0px 50px black,
25px 50px black,
50px 50px black;
}
パーティクル計算座標との連動
@function
@function generate_positions($iter) {
$size: 4px; // スケール倍率とピクセル単位を記述
$r: 40; // 半径(単位無し)
$xoffset: 50; // 半径(単位無し)
$yoffset: 50; // 半径(単位無し)
$result: '';
@for $t from 1 through $iter {
$sep: ',';
@if $t == 1 {
$sep: '';
}
// 円周上の座標を設定
$angle: 360 / $iter * $t;
$x: $r * cos($angle) + $xoffset;
$y: $r * sin($angle) + $yoffset;
$color: black;
$result: $result + '#{$sep} #{$x * $size} #{$y * $size} #{$color}';
}
@return unquote($result);
}
sin()
cos()
sin()
cos()
sin()
cos()
.circle {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: black;
box-shadow: generate_positions(30);
}
generate_positions
見た目の微調整〜パーティクルに配色する
.circle {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: transparent; // 透明に
box-shadow: generate_positions(24);
}
@function colorshift($input_color, $input_phase) {
$output_color: adjust-hue($input_color, $input_phase);
@return $output_color;
}
@function generate_positions($iter) {
$size: 4px;
$r: 40;
$xoffset: 50;
$yoffset: 50;
$result: '';
@for $t from 1 through $iter {
$sep: ',';
@if $t == 1 {
$sep: '';
}
$angle: 360 / $iter * $t;
$x: $r * cos($angle) + $xoffset;
$y: $r * sin($angle) + $yoffset;
// $color: black;
$color: colorshift( hsl(292, 89, 51), $angle); // 色相偏移させる
$result: $result + '#{$sep} #{$x * $size} #{$y * $size} #{$color}';
}
@return unquote($result);
}
カスタムプロパティと連携して、パーティクル計算座標を設定する
@function
Sass
box-shadow
generate_positions
@function generate_positions($iter) {
$result: '';
@for $t from 1 through $iter {
$sep: ',';
@if $t == 1 {
$sep: '';
}
$x: --xcoor_#{$t};
$y: --ycoor_#{$t};
$color: transparent;
$result: $result + '#{$sep} var(#{$x},0) var(#{$y},0) #{$color}';
}
@return unquote($result);
}
.circle {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: black;
//30点のパーティクルを生成
box-shadow: generate_positions(30);
}
.circle {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: transparent;
box-shadow: var(--xcoor_1,0) var(--ycoor_1,0) black, var(--xcoor_2,0) var(--ycoor_2,0) black, var(--xcoor_3,0) var(--ycoor_3,0) black, var(--xcoor_4,0) var(--ycoor_4,0) black, var(--xcoor_5,0) var(--ycoor_5,0) black, var(--xcoor_6,0) var(--ycoor_6,0) black, var(--xcoor_7,0) var(--ycoor_7,0) black, var(--xcoor_8,0) var(--ycoor_8,0) black, var(--xcoor_9,0) var(--ycoor_9,0) black, var(--xcoor_10,0) var(--ycoor_10,0) black, var(--xcoor_11,0) var(--ycoor_11,0) black, var(--xcoor_12,0) var(--ycoor_12,0) black, var(--xcoor_13,0) var(--ycoor_13,0) black, var(--xcoor_14,0) var(--ycoor_14,0) black, var(--xcoor_15,0) var(--ycoor_15,0) black, var(--xcoor_16,0) var(--ycoor_16,0) black, var(--xcoor_17,0) var(--ycoor_17,0) black, var(--xcoor_18,0) var(--ycoor_18,0) black, var(--xcoor_19,0) var(--ycoor_19,0) black, var(--xcoor_20,0) var(--ycoor_20,0) black, var(--xcoor_21,0) var(--ycoor_21,0) black, var(--xcoor_22,0) var(--ycoor_22,0) black, var(--xcoor_23,0) var(--ycoor_23,0) black, var(--xcoor_24,0) var(--ycoor_24,0) black, var(--xcoor_25,0) var(--ycoor_25,0) black, var(--xcoor_26,0) var(--ycoor_26,0) black, var(--xcoor_27,0) var(--ycoor_27,0) black, var(--xcoor_28,0) var(--ycoor_28,0) black, var(--xcoor_29,0) var(--ycoor_29,0) black, var(--xcoor_30,0) var(--ycoor_30,0) black;
}
box-shadow
<script>
const isSupported = window.CSS && window.CSS.supports && window.CSS.supports('--a', 0);
if (isSupported) {
const div = document.getElementById("...要素のID名...");
const _size= 4;
const _r = 40;
const _xoffset = 50;
const _yoffset = 50;
for (let i=0;i<30;i++) {
const _angle = 2*Math.PI/30*i;
const _x = Number(_size * (_r * Math.cos(_angle) + _xoffset));
const _y = Number(_size * (_r * Math.sin(_angle) + _yoffset))
div.style.setProperty(`--xcoor_${i+1}`, `${_x}px`);
div.style.setProperty(`--ycoor_${i+1}`, `${_y}px`);
}
}
else {
console.log('お使いのブラウザはカスタムプロパティ非対応です');
}
const isSupported = window.CSS && window.CSS.supports && window.CSS.supports('--a', 0);
if (isSupported) {
const div = document.getElementById("...要素のID名...");
const _size= 4;
const _r = 40;
const _xoffset = 50;
const _yoffset = 50;
let count = 0;
setInterval(() => {
for (let i=0;i<30;i++) {
const _angle = 2*Math.PI/30*i;
const _delay = 2*Math.PI/90*count;
if (_delay >= 2*Math.PI) { count = 0; }
const _x = Number(_size * (_r * Math.cos(_angle - _delay) + _xoffset));
const _y = Number(_size * (_r * Math.sin(_angle - _delay) + _yoffset))
div.style.setProperty(`--xcoor_${i+1}`, `${_x}px`);
div.style.setProperty(`--ycoor_${i+1}`, `${_y}px`);
}
count++;
}, 500);
}
else {
console.log('お使いのブラウザはカスタムプロパティ非対応です');
}
box-shadow
カスタムプロパティ
まとめ
付録〜sin関数とcos関数
sin
cos
$cordic_dataset: (
0: (45, 1),
1: (26.56505118, 2),
2: (14.03624347, 4),
3: (7.125016349, 8),
4: (3.576334375, 16),
5: (1.789910608, 32),
6: (0.8951737102, 64),
7: (0.4476141709, 128),
8: (0.2238105004, 256),
9: (0.1119056771, 512),
10: (0.05595289189, 1024),
11: (0.02797645262, 2048),
12: (0.01398822714, 4096),
13: (0.006994113675, 8192),
14: (0.003497056851, 16384),
15: (0.001748528427, 32768),
16: (0.0008742642137, 65536),
17: (0.0004371321069, 131072),
18: (0.0002185660534, 262144),
);
$s_all: 1.646760258;
@function check_domain($angle) {
$reduced_angle: $angle % 360;
$result: (0, 0, 0);
$constraint_angle: $reduced_angle % 90;
@if ($reduced_angle >= 0) and ($reduced_angle < 90) {
$result: ($constraint_angle, 1, 1);
} @else if ($reduced_angle >= 90) and ($reduced_angle < 180) {
$result: (90 - $constraint_angle, -1, 1);
} @else if ($reduced_angle >= 180) and ($reduced_angle < 270) {
$result: ($constraint_angle, -1, -1);
} @else {
$result: (90 - $constraint_angle, 1, -1);
}
@return $result;
}
@function cossintan($angle, $mode) {
$modifier: check_domain($angle);
$p_c: 1 / $s_all;
$q_c: 0;
$theta: 0;
$p_next: 0;
$q_next: 0;
$result: 0;
@for $n from 1 through length($cordic_dataset) {
$coeffecient: nth(nth($cordic_dataset, $n), 2);
@if nth($modifier, 1) > $theta {
$p_next: $p_c - ($q_c / nth($coeffecient, 2));
$q_next: $q_c + ($p_c / nth($coeffecient, 2));
$theta: $theta + nth($coeffecient, 1);
} @else {
$p_next: $p_c + ($q_c / nth($coeffecient, 2));
$q_next: $q_c - ($p_c / nth($coeffecient, 2));
$theta: $theta - nth($coeffecient, 1);
}
$p_c: $p_next;
$q_c: $q_next;
}
@if $mode == 0 {
$result: $p_c * nth($modifier, 2); // cos
} @else if $mode == 1 {
$result: $q_c * nth($modifier, 3); // sin
} @else {
$result: $q_c / $p_c * nth($modifier, 2) * nth($modifier, 3); // tan
}
@return $result;
}
@function sin($angle) {
@return cossintan($angle, 1);
}
@function cos($angle) {
@return cossintan($angle, 0);
}
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー