- 投稿日:2019-11-27T21:08:16+09:00
初心者によるプログラミング学習ログ 170日目
100日チャレンジの170日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
170日目は
おはようございます
— ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) November 26, 2019
170日目
今日もwebサイトコーディング課題
box-shadowとか区切り線がうまくいかなくて苦戦中#100DaysOfCode#早起きチャレンジ#駆け出しエンジニアと繋がりたい
- 投稿日:2019-11-27T19:15:59+09:00
要素を右下に配置
・親要素に
position: relative;
・子要素に
position: absolute
right: 0;
bottom: 0;
をあててあげましょう。
xxx.css.contents { position: relative; } .content { position: absolute; right: 0; bottom: 0; }
ではまた!
- 投稿日:2019-11-27T17:34:13+09:00
Vuetifyのv-messagesのmin-heightを0pxにしたい
- 投稿日:2019-11-27T15:03:23+09:00
CSSでスライドショーをつくる(SCSS)
CSSスライドショー
JSを一切使わない、フェードアニメーションによるスライドショーを作成しました。
使用言語
- HTML
- CSS(時短のためSCSSを使用、CSSでもできます。)
完成系です。いろいろと見た目もつけてます。
See the Pen xxxomJO by k1-web (@k1-web) on CodePen.
内容の解説
まずはHTMLでスライドショーのDOMから。
slideshow.html<div class="slideshow"> <input type="radio" name="slideshow" id="s-1" checked> <input type="radio" name="slideshow" id="s-2"> <input type="radio" name="slideshow" id="s-3"> <input type="radio" name="slideshow" id="s-4"> <input type="radio" name="slideshow" id="s-5"> <ul class="slideshow_list"> <li class="item-1" style="background:#ff7f7f;"></li> <li class="item-2" style="background:#bf7fff;"></li> <li class="item-3" style="background:#7fffff;"></li> <li class="item-4" style="background:#7fff7f;"></li> <li class="item-5" style="background:#ffbf7f;"></li> </ul> <div class="slideshow_label"> <label for="s-1"></label> <label for="s-2"></label> <label for="s-3"></label> <label for="s-4"></label> <label for="s-5"></label> </div> <div class="slideshow_page"> <label for="s-1"></label> <label for="s-2"></label> <label for="s-3"></label> <label for="s-4"></label> <label for="s-5"></label> </div> </div>HTMLですが、PHPとかPugとかで個数分forなどで回すと簡単に制御できます。
例えば、PHPでやるとすると下記のように枚数を簡単に制御できます。slideshow.php<?php $slideNum = 5 ; ?> <div class="slideshow"> <?php for($i=1;$i<=$slideNum;$i++): ?> <input type="radio" name="slideshow" id="s-<?php echo $i; ?>"<?php echo $i == '1' ? ' checked': ''; ?>> <?php endfor; ?> <ul class="slideshow_list"> <?php for($i=1;$i<=$slideNum;$i++): ?> <li class="item-<?php echo $i; ?>"></li> <?php endfor; ?> </ul> <div class="slideshow_label"> <?php for($i=1;$i<=$slideNum;$i++): ?> <label for="s-<?php echo $i; ?>"></label> <?php endfor; ?> </div> <div class="slideshow_page"> <?php for($i=1;$i<=$slideNum;$i++): ?> <label for="s-<?php echo $i; ?>"></label> <?php endfor; ?> </div> </div>解説-スライド画像の部分
slideshow.html<ul class="slideshow_list"> <li class="item-1" style="background:#ff7f7f;"></li> <li class="item-2" style="background:#bf7fff;"></li> <li class="item-3" style="background:#7fffff;"></li> <li class="item-4" style="background:#7fff7f;"></li> <li class="item-5" style="background:#ffbf7f;"></li> </ul>スライドショーの画像とかを入れる部分、スライドの枚数分、
タグを作成。
本来はタグの中にタグなどをいれますが、今回は画像添付が面倒なので、背景色を指定しているだけです。解説-タグの部分
slideshow.html<input type="radio" name="slideshow" id="s-1" checked> <input type="radio" name="slideshow" id="s-2"> <input type="radio" name="slideshow" id="s-3"> <input type="radio" name="slideshow" id="s-4"> <input type="radio" name="slideshow" id="s-5">スライドショーのうち、どこが今見えている所かを判定するためのラジオボタンになります。
タグや、タグの親要素がタグに隣接していないとスタイルをあてられません。
スライドの枚数分を作成し、一番上位の親要素の直下にを指定してください。
CSSセレクタの「~」という、隣接する要素を指定できるセレクタを使用するので、
スライドのまた、見た目上には非表示にしていますが、要素で選択し、2番目の画像なら2番目にチェックみたいな感じで動作しています。
解説-左右の矢印ボタンとぺジテーション
slideshow.html<div class="slideshow_label"> <label for="s-1"></label> <label for="s-2"></label> <label for="s-3"></label> <label for="s-4"></label> <label for="s-5"></label> </div> <div class="slideshow_page"> <label for="s-1"></label> <label for="s-2"></label> <label for="s-3"></label> <label for="s-4"></label> <label for="s-5"></label> </div>先程のラジオボタンに対応するラベルです。2つ存在しても同じ#s-Nのラジオボタンに対応しています。
今回は.slideshow_labelの中のタグは進む・戻るボタンとして、.slideshow_pageはぺジテーションとして動作します。本題のCSS(SCSS)です
codepenから説明に必要部分だけ抜粋しています。
slideshow.scss@mixin slideLength($length, $show){ $page: ceil($length / $show); content: $page; @for $i from 1 through $page { &:nth-of-type(#{$i}):checked { & ~ .slideshow_list { > li:nth-of-type(n+#{$i * $show - $show + 1}):nth-of-type(-n+#{$i * $show}) { opacity: 1; z-index: 10; > a::before { z-index: 11; } } } & ~ .slideshow_label { $prev: $i - 1; $next: $i + 1; @if $prev < 1 { $prev: $prev + $page; } @if $next > $page { $next: $next - $page; } > label:nth-of-type(#{$prev}) { display: block; right: auto; &::before { right: auto; -webkit-transform: rotate(45deg); transform: rotate(45deg); } } > label:nth-of-type(#{$next}) { display: block; left: auto; &::before { left: auto; -webkit-transform: rotate(-135deg); transform: rotate(-135deg); } } } & ~ .slideshow_page { > label:nth-of-type(#{$i})::before { content: ''; } } } } } .slideshow { position: relative; input[type="radio"] { display: none; opacity: 0; width: 0; height: 0; margin: 0; padding: 0; $length: 5; //合計の枚数 $show: 1; //1ページあたりに見せる数 @include slideLength($length, $show); } .slideshow_list { > li { display: block; width: 300px; height: 150px; //~~ opacity: 0; -webkit-transition: opacity 0.3s ease-in-out; transition: opacity 0.3s ease-in-out; } } .slideshow_label { > label { display: none; width: 40px; height: 40px; background-color: #fff; border: 1px solid #f30; border-radius: 50%; cursor: pointer; position: absolute; top: 52px; left: 20px; right: 20px; } } .slideshow_page { > label { display: inline-block; width: 10px; height: 10px; background-color: #a8b7c6; border-radius: 50%; cursor: pointer; position: relative; &::before { display: inline-block; width: 10px; height: 10px; background-color: #777; cursor: pointer; position: relative; border-radius: 50%; position: absolute; top: 0; left: 0; } } } }解説-スライド画像の部分
slideshow.scss.slideshow_list { > li { display: block; width: 300px; height: 150px; //~~ opacity: 0; -webkit-transition: opacity 0.3s ease-in-out; transition: opacity 0.3s ease-in-out; } }opacityを0にしていて、transitionでopacityの透過をアニメーションにしています。
後ほど解説するラジオボタンのチェックを判定してopacityを1にしています。解説-inputタグの部分
slideshow.scss@mixin slideLength($length, $show){ $page: ceil($length / $show); content: $page; @for $i from 1 through $page { &:nth-of-type(#{$i}):checked { & ~ .slideshow_list { > li:nth-of-type(n+#{$i * $show - $show + 1}):nth-of-type(-n+#{$i * $show}) { opacity: 1; z-index: 10; > a::before { z-index: 11; } } } & ~ .slideshow_label { $prev: $i - 1; $next: $i + 1; @if $prev < 1 { $prev: $prev + $page; } @if $next > $page { $next: $next - $page; } > label:nth-of-type(#{$prev}) { display: block; right: auto; &::before { right: auto; -webkit-transform: rotate(45deg); transform: rotate(45deg); } } > label:nth-of-type(#{$next}) { display: block; left: auto; &::before { left: auto; -webkit-transform: rotate(-135deg); transform: rotate(-135deg); } } } & ~ .slideshow_page { > label:nth-of-type(#{$i})::before { content: ''; } } } } } .slideshow { input[type="radio"] { display: none; opacity: 0; width: 0; height: 0; margin: 0; padding: 0; $length: 5; //合計の枚数 $show: 1; //1ページあたりに見せる数 @include slideLength($length, $show); } }input:nth-of-type(1)がチェック付いた時には、.slideshow_list > li:nth-of-type(1)をopacity: 1;にして表示、
input:nth-of-type(2)がチェック付いた時には、.slideshow_list > li:nth-of-type(2)をopacity: 1;にして表示...
のようにラジオボタンでnth-of-typeを利用し、何番目にチェックついたら何番目のスタイルを変更するという動作にしています。左右の矢印部分は、input:nth-of-type(2)だったら.slideshow_label>label:nth-of-type(1)を戻るボタンとして表示、
.slideshow_label>label:nth-of-type(3)を進むボタンとして表示、というようにチェックした数値の前後を表示としています。ぺジテーションはそれぞれに対応したラベルに対してチェックを付けるようになっています。
SCSSの場合は上記らを自動的に計算できるので、関数化して「$length」に応じた枚数分スライドできるようになっています。
あとがき
フェードアニメーションのスライドショーはラジオボタンで認識して表示非表示で切り替える簡単な仕組みで作れます。
これが左右に動くスライドショーとなると、なかなか難しくなるので次回挑戦してみたいと思います。
- 投稿日:2019-11-27T13:00:27+09:00
CSSのbackgroundプロパティで出来るいろいろなことまとめ
backgroundプロパティ
backgroundの主要なプロパティ一覧
プロパティ 役割 background 背景プロパティの一括指定 background-color 背景色の指定 background-image 背景画像の指定 background-position 背景画像の位置の指定 background-size 背景画像の大きさの指定 background-repeat 背景画像の繰り返し表示の指定 background-colorのいろいろ
div.a { background-color: #f30; } div.b { background-color: #ff3300; } div.c { background-color: rgb(255, 51, 0); } div.d { background-color: rgba(255, 51, 0, 0.8); }#から始まる3桁または6桁の16進数のカラーコードやrgb()による10進数での背景色指定の他に、
rgba()によって透過度の指定が対応しています。background-imageのいろいろ
グラデーションの指定
div { background-image: linear-gradient(rgba(255, 51, 0, 0.8), rgba(255, 255, 0255, 1)); }background-imageプロパティにlinear-gradientを使用すれば、線形グラデーションをかけることができます。
線形グラデーションに、放射・扇形グラデーションも使用できます。
radial-gradient() 放射グラデーション
div { background-image: radial-gradient(rgba(255, 51, 0, 0.8), rgba(255, 255, 0255, 1)); }radial-gradient() 扇形グラデーション
div { background-image: conic-gradient(rgba(255, 51, 0, 0.8), rgba(255, 255, 0255, 1)); }背景画像の複数指定
bg.cssdiv { background-image: url(hoge.png), url(fuga.png); background-position: top left, right bottom; background-repeat: no-repeat; }background-imageの各プロパティで、「,」カンマを区切ると複数の画像を入れることができます。
また、background-positionやbackground-size,background-repeatも「,」カンマで区切るとbackground-imageで指定した画像に対してそれぞれプロパティを当てることが出来ます。同一の場合は「,」カンマを外すことで一括指定となります。backgroundプロパティをいろいろ使って、複雑な背景を指定する
グラデーションに水玉模様
See the Pen gOONQma by k1-web (@k1-web) on CodePen.
背景グラデーションに合わせて白い水玉模様がついてるこの背景も全てCSSでやってます。
水玉模様のドットをradial-gradient(放射グラデーション)でつくる
1.円を作る
bg.css.bg { background-image: radial-gradient(rgba(255,255,255,0.7) 15%, transparent 20%); }数%ずらすことによって、画像のギザギザ感をなくし滑らかになります。
これだと中心に大きな楕円しか表示できていません。2.サイズを調整
bg.css.bg { background-image: radial-gradient(rgba(255,255,255,0.7) 15%, transparent 20%); background-size: 30px 30px; }background-sizeを指定することによって、指定したサイズに応じた円が表示されます。
ただこのままだと余白感が開きすぎているのと、上下左右にしか繰り返していません。
ここにさらに、同じグラデーションを重ねます。3.ドットを複数表示して重ねる。
bg.css.bg { background-image: radial-gradient(rgba(255,255,255,0.7) 15%, transparent 20%), radial-gradient(rgba(255,255,255,0.7) 15%, transparent 20%); background-size: 30px 30px, 30px 30px; }このままだと同じ位置に重なっているので、ずらします。
4.複数表示したのをずらす。
bg.css.bg { background-image: radial-gradient(rgba(255,255,255,0.7) 15%, transparent 20%), radial-gradient(rgba(255,255,255,0.7) 15%, transparent 20%); background-size: 30px 30px, 30px 30px; background-position: 0 0, 15px 15px; }background-sizeの半分をずらすことによって、ななめにも繰り返し表示になります。
最後に、背景に線形グラデーションを付ける。
bg.css.bg { background-image: radial-gradient(rgba(255,255,255,0.7) 15%, transparent 20%), radial-gradient(rgba(255,255,255,0.7) 15%, transparent 20%), linear-gradient(135deg, #e2ecff 0%,#e2ecff 40%,#bde7ff 60%,#bde7ff 100%); background-size: 30px 30px, 30px 30px, 100% 100%; background-position: 0 0, 15px 15px, center center; }背景はsizeを100%にすることによって全体表示に、グラデーションに水玉模様が重なった綺麗なはいけいになりました。
左右に違う色を使った吹き出し
See the Pen yLLdQRj by k1-web (@k1-web) on CodePen.
左から50%を境に色を切り分けるlinear-gradient線形グラデーションをかける
bg.scss.bg { background-image: linear-gradient(90deg, #00a0e9 50%,#ff7e00 50%); background-size: 100% calc(100% - 30px); background-repeat: no-repeat; }before,afterの疑似要素を使用し、三角をつくる
bg.scss.bg { background-image: linear-gradient(90deg, #00a0e9 50%,#ff7e00 50%); background-image: linear-gradient(90deg, #00a0e9 50%,#ff7e00 50%); background-size: 100% calc(100% - 30px); background-repeat: no-repeat; position: relative; &::before, &::after { content: ''; display: inline-block; width: 0; height: 0; border: 15px solid transparent; position: absolute; bottom: 0; } &::before { border-right-color: #00a0e9; border-top-color: #00a0e9; right: 50%; } &::after { border-left-color: #ff7e00; border-top-color: #ff7e00; left: 50%; } }今後も備忘録的に更新していきます。
- 投稿日:2019-11-27T09:40:16+09:00
CSS in JS時代のCSS設計
Ateam Lifestyle Advent Calendar 2019の1日目は
株式会社エイチームライフスタイル クリエイティブ戦略部 シニアデザイナーの綿貫が担当します!先陣切って投稿しますので、みなさんどうぞ読んでください!
はじめに
CSS in JSもそこまで珍しくなくなってきたと思いますが、CSS in JSでのCSS設計の話はなかなか見かけません。
ないなら自分で書こう!と思い立ったので書きます。そもそもCSS設計が必要な理由
CSSを書くに当たって、人間が悩むのは主に「名前空間が存在していない」からだと思います。
1つ1つのパーツを個別にスタイリングをするだけならさほど難しくもありませんよね?ところが、サイト全体を通してスタイリングするとなると
- 自分が触っている箇所に
- 予期せぬスタイルが当たっている
- 当たるはずのスタイルが当たらない
- 自分が触っていない箇所に
- 予期せぬスタイルが当たっている
などに悩まされるかと思います。
大抵の場合はカスケーディングやセレクタの詳細度が絡み合い事故を起こすのですが、名前空間を持っていれば防げたであろうケースも多いのです。
こういったつらさを解消するためにCSS設計が必要であり、色々な種類のものが考案されてきました。
この記事では詳しくは触れませんが、一例を挙げますので気になる方は読んでみてください。CSS in JSについて
ここまで散々CSS in JSという言葉を使ってきましたが、これはある特定の技術を指すものではありません。
言葉通り「JavaScriptの中でCSSを書く」という概念です。実際にコードを書く際にはライブラリを選ぶところから始まります。
有名どころだと以下のもの。
- CSS Modules(厳密に言うと違うけどCSS in JSの文脈で出てくることが多い)
- styled components
- Emotion
CSS Modulesは学習コストが一番低く、styled componentsは普及している範囲が一番広く、Emotionは最近追い上げて来ている&個人的に好きです。
どれも共通しているのは、擬似的にローカルスコープを生成してセレクタを閉じ込められる点。
これが出来るようになったおかげで命名に悩む時間は大幅に減りました。では名前空間の問題が解消した上で、それでもなお、人間が設計しないといけないことは何でしょうか?
CSS in JSでの設計とこれまでの設計との違い
大きく分類すれば
- グローバルに使うものとそうでないものを明らかにする
- propsによるスタイルの変化を考慮する
- どの機能・オプションを使うのかを明示する
ことに分かれると思います。
グローバルに使うものとそうでないものを明らかにする
UIをコンポーネントとして実装する際のメリットはそれぞれが独立していることです。
スタイリングにおいても大きなメリットですが、そうは言ってもグローバルに共通化したいものもあります。代表例はカラーパレット。
特にブランドカラーを定義している際は、毎回手打ちで色を指定するのは非現実的です。あるいはreset CSSの類。
各コンポーネントにいちいち記述するのは絶対に嫌です。かといってなんでもかんでも共通化していては、せっかくのローカルスコープが意味をなさなくなってしまうのが悩みどころ。
チームやプロダクトによりますが、どこまでを共通化してどこからは各コンポーネントに閉じ込めるかをしっかり話し合うのが大事だと思います。範囲さえ決めることが出来れば、先に挙げたライブラリならどれでもglobalなスタイルも定義できます。
また、定数や関数を他で定義しておいて読み込めばいつでも使いまわせます。propsによるスタイルの変化を考慮する
CSS in JSで楽になることの1つとして、propsを渡してスタイルを変更できることが挙げられます。
選ぶライブラリによって実装方法は変わりますが、例えばstyled componentsなら以下のようにバリエーションを生成できます。
Input
コンポーネントにinputColor
が指定されていたらcolorがその値になる- 指定されていなかったらフォールバックとして
palevioletred
が適用される// 公式ドキュメントよりコードを抜粋 const Input = styled.input` padding: 0.5em; margin: 0.5em; color: ${props => props.inputColor || "palevioletred"}; background: papayawhip; border: none; border-radius: 3px; `; render( <div> <Input defaultValue="@probablyup" type="text" /> <Input defaultValue="@geelen" type="text" inputColor="rebeccapurple" /> </div> );しかし、なんでもかんでもpropsで渡せるようにしてしまっては記述が汚くなります。
やろうと思えば……// 先ほどのコードを改変 const Input = styled.input` padding: ${props => props.inputPadding || 0.5}em; margin: ${props => props.inputMargin || 0.5}em; color: ${props => props.inputColor || "palevioletred"}; background: ${props => props.inputBackground || "papayawhip"}; border: none; border-radius: ${props => props.inputBorderRadius || 3}px; `; render( <div> <Input defaultValue="@probablyup" type="text" /> <Input defaultValue="@geelen" type="text" inputPadding="2" inputMargin="1" inputColor="rebeccapurple" inputBackground="red" inputBorderRadius="5" /> </div> );かなり嫌なコードですよね?
全てのカスタムを許せば良いってものじゃありませんし、Input
はもはやコンポーネントとして成立しているのか怪しいです。こういった場合は以下のような書き方にすることもできます。
// 更に改変 const Input = styled.input` padding: 0.5em; margin: 0.5em; color: palevioletred; background: papayawhip; border: none; border-radius: 3px; ${props => props.primary && css` padding: 1em; margin: 1em; color: rebeccapurple; background: red; border-radius: 5px; `} `; render( <div> <Input defaultValue="@probablyup" type="text" /> <Input defaultValue="@geelen" type="text" primary /> </div> );これなら自由すぎるカスタム性はなくなり、
Input
の書き方もスッキリしました。ただし、これだけ変わるなら別コンポーネントとして定義した方が良いのでは?とか、
今後secondary
やtertiary
が出てきたらどうなるのか?とか
propsの渡し方はboolとenumのどちらの方が良いのか?とか
疑問が次々湧きますよね。色々なやり方でpropsをの受け渡しとスタイルの変更ができてしまうため、何を許容して何を縛るかの設計が大事になるかと思います。
どの機能・オプションを使うのかを明示する
上の話とも少し似ています。
今CSS in JSのライブラリはお互いがしのぎを削っているからか、各種オプションが非常に豊富です。
- オブジェクト記法でも書けるし、テンプレートリテラルでも書ける
- component化もできるし、インラインで直接も書ける
- jsx内にも書けるし、外にconstとしても書ける
などなど……。
アレコレできるようになった反面、縛りは入れないと非常に読みづらくなります。例えばEmotionは最後発なのでかなり色々な書き方ができるのですが、以下を見てください。
/** @jsx jsx */ import { css, jsx } from '@emotion/core' const text = css` font-size: 20px; padding: 10px; ` const P = props => ( <p css={{ margin: 0, fontSize: 12, lineHeight: '1.5', fontFamily: 'Sans-Serif', color: 'black' }} {...props} /> ) render( <div css={{ backgroundColor: 'hotpink', '&:hover': { color: 'lightgreen' } }} > <P css={text}>This has a hotpink background.</P> </div> )最終的にどんなスタイルになるのか全然わかりませんよね?
自分にも分かりません。書いている本人ですらシミュレートするのに一苦労なのですから、後から読んだ人には分かるはずもありません。
なので初めにチームでどの機能・オプションを使うのかをしっかり決めておくことが大事です。これまでの設計から変わらないこと
既存のCSS設計(あるいはコーディングルール)から変わらないことも多くあります。
まずは、セレクタのスコープが絞られるようになったからと言って、要素セレクタや過度な入れ子はよろしくないということです。
Shadow DOMが実現出来ているわけではありませんので、要素セレクタでスタイルを宣言すると大抵何かと衝突します。
入れ子については記述が複雑になる他、パフォーマンスの観点でも良くありません。あとは、最終的にアウトプットされるのはあくまでCSSです。
marginの相殺なんかはローカルスコープがあろうが発生してしまうもの。
そのためまだまだ最終的なCSSをイメージしながら書く必要はあります。具体的なルール
ここまでは概念的な話がほとんどでした。
詳しく書きたいところなのですが、色々なライブラリが存在するので「これだ!」というものは無いと思います。そんな中でもEmotionを使った詳細な書き方はこちらの記事で紹介しているので良ければ一緒に見てください。
まとめ
CSS in JSにおけるCSS設計の概念をまとめてみました。
まだベストプラクティスが出揃っていない分野だとは思うので、これから使う人にとって少しでも参考になれば幸いです。Ateam Lifestyle Advent Calendar 2019 の2日目は、@tatsumin0206がお送りします!!どんなネタを用意してくるのか楽しみです!!
“挑戦”を大事にするエイチームグループでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
https://www.a-tm.co.jp/recruit/