見出し画像

>は計算すれば良い位置に置けるのでは?と気づいた

1.はじめに

はじめまして、Engineers GroupのS本です。

いきなりですが、よくあるこの装飾。

画像1


いろんな所で様々なサイズで出てきた時、>をいい感じの場所に設定するのが面倒と感じています。
いい感じの位置に配置したと思ったら、ディレクターさんに「あと1px右に」と言われたり。。。

ですが、SCSSで設定しているときに、ふと「円の直径」「>の1辺の長さ」「>の太さ」がわかるのだから、普通に良い位置を計算できるのでは?と気づきました。

数学っていいですよね。

ということで、>のrightに設定すべき値を計算しました。
最終的にはmixinで気楽に使用できるようにするのが目標です。
(計算大変になるので、角度は90度限定とします。)

(難しいことは一切やりたくない精神状態なので、私の趣味丸出しの内容になっています。技術的な話は一切ないので気楽に聞いていただけると助かります。)

2.前提条件

今回は、若干計算を楽にするためにspanで作成します。
(座標計算がしっかりできれば、今回の結果から普通にbefore, afterに調整も可能です。)

<span class="next"></span>

<span></span>で○を作り、span::beforeで>を用意します。

また、簡略化のために、下記制限をつけます。

・単位はpx(ただ、pxのところを他の単位の記述に直して、その単位だけを使用するようにすればうまく行くはず)
・ box-sizingはborder-box
・transform-originはcenter center


変数は下記の様に定義します。

画像2

3.計算する

① >の先っぽまでの距離を求める

そもそも、>は実は右寄りにしないとバランスが悪いので、
そのあたり調整できるようにします。
(数学的にはこういう曖昧な数値は鬱陶しいことこの上ないのですが、中央に置いても人の目でみた時に中央にあるように見えないから仕方ないですね)

画像3

ということで、
 ① + ①‘ = 100
として
①が何%であるかを示す数値pを定義する。
p = 50の時 ① = ①’ ・・・「>」が中央に来る
p < 50の時 ① < ①‘ ・・・「>」が右に寄る
ということです。

直角二等辺三角形の辺の比は1:1:√2というのを利用すれば求めることが可能です。

画像4

ということで、①は
(R - (√2b / 2 + √2l / 2)) * p /100
でした。

② >を回転させたときのズレを求める

画像5

透けている黄色が回転前の状態。
回転の中心を中央にしているため、>の先っぽが飛び出ます。

そこで、どれだけ飛び出るか求めます。

画像6

ということで、②は√2l/2 - l/2でした。

③ これまでの結果を合体させる

画像7

right = ① + ②
となる。
できる限り無理数(√2)が出てこないように
かつできる限り割り算をしないように

すると計算のズレが少なくなるので、そのように整理します。

画像8

ということで、rightは
(2(Rp - 50l) + √2(100l - bp - lp)) / 200
でした。

4.mixin作成

無理数の√2は定数として定義して使用します。
また、変数pとして設定した>までの距離の調整用変数も、定数として定義します。(きうちの装飾をみると、45くらいがちょうど良かったです)

$root2: 1.41421356;
$ratioOfRight: 45;  // >の先までの比率(0~100)
// ******************************************
// 機能:>に設定すべきrightの値を取得
// 引数:$diameter 背景の円の直径
//      $borderLength >の一辺の長さ
//      $borderWidth >の線の太さ
// 返値:rightに指定すべき値(pxの単位付きで返す)
// ******************************************
@function getRightPoint($diameter, $borderLength, $borderWidth) {
 @return (((2 * ($diameter * $ratioOfRight - 50 * $borderLength)) + $root2 * (100 * $borderLength - $borderWidth * $ratioOfRight - $borderLength * $ratioOfRight)) / 200)+px;
}
// ******************************************
// 概要:○の中に>がある装飾
// 引数:$diameter 背景の円の直径
//      $borderLength >の一辺の長さ
//      $borderWidth >の線の太さ
//      $circleColor 背景の円の色
//      $borderColor >の線の色
// ******************************************
@mixin circleArrow($diameter, $borderLength, $borderWidth, $circleColor, $borderColor) {
 position: relative;
 display: block;
 box-sizing: border-box;
 width: $diameter+px;
 height:$diameter+px;
 border-radius: 50%;
 background: $circleColor;
 &::before {
   content: "";
   position: absolute;
   top: 50%;
   *right**: getRightPoint($diameter, $borderLength, $borderWidth);*
   display: block;
   box-sizing: border-box;
   width: $borderLength+px;
   height: $borderLength+px;
   transform: translateY(-50%) rotate(45deg);
   transform-origin: center center;
   border-top: $borderWidth+px solid $borderColor;
   border-right: $borderWidth+px solid $borderColor;
 }
}
.next {
 @include circleArrow(28, 9, 2, #a00, #eee);
}

はい。できました〜

画像9

比較用に、上記のmixin内のrightを固定値(単位は%)にしたverと並べてみます。
%だとなんとなくうまく行きそうな気がしますが、イマイチなのがわかると思います。うまく行かないのです〜
上記の結果の②を流用します。
矢印の場合、常に中央に来るように配置しても良さそう!!
というわけで、曖昧な数値も出てこず、完璧に計算できます。

気分いいですね。

実際にプロジェクト内で様々なサイズで出てきてborder-widthが違ったりすると、見え方の印象が変わってくるため、それぞれ調整はしなくてはいけない可能性大です。
ひとまずサクッと作成するには有用であると思います。($ratioOfRightの値は、いい感じにしてください。)

5.ついでに → も作ってみた。

上記の結果の②を流用します。
矢印の場合、常に中央に来るように配置しても良さそう!!
というわけで、曖昧な数値も出てこず、完璧に計算できます。

気分いいですね。

必要なパラメータとして、>の先っぽから−の末端までの距離wが追加となります。

画像10

こちらもspanか何かで用意します。

<span class="arrow1"></span>

spanで背景の円、beforeで「>」、afterで「−」を作成します。

beforeのrightは(√2l + R - l - w) / 2
afterのleftは(R - w) / 2でした。

// ******************************************
// 機能:>に設定すべきright&leftの値を取得
// 引数:$diameter 背景の円の直径
//      $borderLength >の一辺の長さ
//      $borderWidth >の線の太さ
//      $arrowWidth >の先っぽから-の末端までの長さ
// 返値:rightに指定すべき値(pxの単位付きで返す)
// ******************************************
@function getRightPoint_arrow($diameter, $borderLength, $borderWidth, $arrowWidth) {
 @return (($root2 * $borderLength + $diameter - $borderLength - $arrowWidth) / 2)+px;
}
@function getLeftPoint_arrow($diameter, $borderLength, $borderWidth, $arrowWidth) {
 @return (($diameter - $arrowWidth) / 2)+px;
}
// ******************************************
// 概要:○の中に->がある装飾
// 引数:$diameter 背景の円の直径
//      $borderLength >の一辺の長さ
//      $borderWidth >の線の太さ
//      $arrowWidth >の先っぽから-の末端までの長さ
//      $circleColor 背景の円の色
//      $borderColor >の線の色
// ******************************************
@mixin arrow($diameter, $borderLength, $borderWidth, $arrowWidth, $circleColor, $borderColor) {
 position: relative;
 display: block;
 box-sizing: border-box;
 width: $diameter+px;
 height:$diameter+px;
 border-radius: 50%;
 background: $circleColor;

 &::before,
 &::after {
   content: "";
   position: absolute;
   top: 50%;
   display: block;
   box-sizing: border-box;
   transform-origin: center center;
 }

 &::before {
   *right**: getRightPoint_arrow($diameter, $borderLength, $borderWidth, $arrowWidth);*
   width: $borderLength+px;
   height: $borderLength+px;
   transform: translateY(-50%) rotate(45deg);
   border-top: $borderWidth+px solid $borderColor;
   border-right: $borderWidth+px solid $borderColor;
 }

 &::after {
   *left**: getLeftPoint_arrow($diameter, $borderLength, $borderWidth, $arrowWidth);*
   *width**: ($arrowWidth - $borderWidth)+px;*
   height: $borderWidth+px;
   transform: translateY(-50%);
   background: $borderColor;
 }
}

.arrow1 {
 @include arrow(20, 7, 2, 10, #482edb, #fff);
}

長さや線の太さに関わらず、それなりにいい感じに表示されますね。

画像11

6.さいごに

角度も長さもわかるので、「目で見ていい感じの位置」という曖昧なものでなければ全て普通に計算出来ます。
(45度or90度以外の角度や長方形が出てきたら、sin, cos, tanの出番で面倒になりますが。)
また何か見つけたら、こっそりmixin化しようと思いました。

個人的に楽しかったので満足。

【おまけ1】
デザインデータから計測した>の先っぽまでの距離を適用させる場合(┐を45度回転させる)

x = デザインデータから得た右端から>の先っぽまでの距離
l = 正方形の一辺の長さ
right = calc(x + (0.20710678 * l));
もちろんleftやtopなども同様です。

【おまけ2】
before, after ver(beforeで○、afterで>を作成)

設定パラメータに背景の円のrightに設定する値が追加になっています。

// before, after ver
// ******************************************
// 機能:>に設定すべきrightの値を取得
// 引数:$right 背景の円のrightに設定する値
//      $diameter 背景の円の直径
//      $borderLength >の一辺の長さ
//      $borderWidth >の線の太さ
// 返値:rightに指定すべき値(pxの単位付きで返す)
// ******************************************
@function getRightPoint_ba($right, $diameter, $borderLength, $borderWidth) {
 @return ((((2 * ($diameter * $ratioOfRight - 50 * $borderLength)) + $root2 * (100 * $borderLength - $borderWidth * $ratioOfRight - $borderLength * $ratioOfRight)) / 200) + $right)+px;
}
// ******************************************
// 概要:○の中に>がある装飾
// 引数:$right 背景の円のrightに設定する値
//      $diameter 背景の円の直径
//      $borderLength >の一辺の長さ
//      $borderWidth >の線の太さ
//      $circleColor 背景の円の色
//      $borderColor >の線の色
// ******************************************
@mixin circleArrow_ba($right, $diameter, $borderLength, $borderWidth, $circleColor, $borderColor) {
 position: relative;

 &::before,
 &::after {
   content: "";
   position: absolute;
   top: 50%;
   display: block;
   box-sizing: border-box;
 }

 &::before {
   right: $right+px;
   width: $diameter+px;
   height:$diameter+px;
   transform: translateY(-50%);
   border-radius: 50%;
   background: $circleColor;
 }

 &::after {
   right: getRightPoint_ba($right, $diameter, $borderLength, $borderWidth);
   width: $borderLength+px;
   height: $borderLength+px;
   transform: translateY(-50%) rotate(45deg);
   transform-origin: center center;
   border-top: $borderWidth+px solid $borderColor;
   border-right: $borderWidth+px solid $borderColor;
 }
}

a {
 @include circleArrow_ba(10, 30, 10, 2, #333, #eee);
}

この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?