1
5

More than 1 year has passed since last update.

【HTML/CSS】Udemyコースで学んだ良い感じなデザインの共通点をまとめてみる

Last updated at Posted at 2022-03-08

この記事は何?

Udemyで20 Web Projects With Vanilla JavaScriptというコースを受講しました。

HTML/CSS/VanillaJSで良い感じなデザインのアプリを20個作っていく、フロントエンド初学者向けのコースです。

コースを進めていく中で、デザインに共通点が多い事に気が付きました。

そこで、今後の自分のためにこのコースで登場するデザインの共通点をまとめることにしました。

受講の動機

HTML/CSS/JavaScriptで10個(くらい)何かを作ってみるチャレンジの一環として受講しました。

何か作ってみるチャレンジの目的は、HTML/CSS/Vanilla JSを使ってとりあえずなにか作ること、手を動かすことです。

プログラミングにおいて手を動かすに勝る学習方法はないと思います。
実感としてもそうですし、そう言っているエンジニアの方も多くいます。
また、質を高めるためにも、まずは絶対的な量が必要とよく言います。

というわけで、色々作ってみることにしました。

しかしその中で、文法はある程度わかっていてもサイトのデザインやレイアウトをどのように考え・作っていけば良いのか全くと言っていいほどわからないことに気が付きました。

そこで、まずは良いデザインとはどういったものなのか?を学びつつ、手を動かせる教材を選びました。


チャレンジのリポジトリ


注意点

  • 初心者向けの記事です。
    • そんなの常識やん、という内容が多々含まれる恐れがあります。
  • 細心の注意を払ってはいますが、勘違い・ミスがあるかもしれません。見つけたらそっと指摘していただけると幸いです。
  • 「この方法が最適解!」というわけではないです。

本題の前に

VSCodeのTips

いくつか講座内で紹介されていたVSCodeのTipsを紹介します。

拡張機能 Auto Rename Tag

ペアになっているタグを自動でリネームしてくれる拡張機能です。
普通に便利。

拡張機能 Lite Server

VSCode限定というわけではありませんが、VSCodeなら簡単に拡張機能として利用可能なので紹介します。
ファイルの変更を監視・ブラウザに反映してくれる軽量なローカルWebサーバです。

  • BrowserSyncをSPAに対応出来るようにしたラッパーです。
  • HTML/CSS/JSファイルの変更を監視、変更されたら即ブラウザに反映してくれます。
  • Liteというだけあって、ロードが超早いです。

拡張機能の検索欄で「Lite Server」と検索、インストールするだけで導入できます。

HTMLの入力

VSCodeでHTMLを書くときは下の表のように入力すると効率良く入力出来ます。

入力 結果
.active <div class="active"></div>
タグ.class-name#id-name <タグ class="class-name" id="id-name"></タグ>

vscode-html

Google Fontの利用

Browse Fonts - Google Fontsから好きなフォントを選んで導入します。

今回はCSSの@importにより利用します。

@import url('https://fonts.googleapis.com/css2?family=Lato:wght@100&family=Roboto:wght@100&display=swap');

導入の参考になりそうな記事

Font Awesomeの利用

Font Awesomeから好きなアイコンを選んで導入します。

headlinkを追加して利用出来るようにします。

<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css" rel="stylesheet">

HTMLで下のように書くだけでアイコンが表示されます!
無料プランだと使用できるアイコンに制限があるようです。

<i class="fas fa-search"></i>
<i class="fas fa-random"></i>

導入の参考になりそうな記事

CSSセレクタ

動画内で多用されていた基本的なセレクタについておさらいします。
実際使うときはネストが深くなりすぎないように注意。

<ul class="showcase">
    <li>
        <div class="seat"></div>
        <small>N/A</small>
    </li>
    <li>
        <div class="seat selected"></div>
        <small>Selected</small>
    </li>
    <li>
        <div class="seat occupied"></div>
        <small>Occupied</small>
    </li>
</ul>
.seat.selected {
    background-color: #6feaf6;
}

.seat.selected を持つ要素が選択される

.seat:not(.occupied):hover {
    cursor: pointer;
    transform: scale(1.2);
}

.seat の内、 .occupied を持たない要素が選択される

.showcase .seat:not(.occupied):hover {
    cursor: default;
    transform: scale(1);
}

.showcase の子要素、かつ .seat を持ち、 .occupied を持たない要素が選択される

本題

前置きが長くなりましたが、本題に入っていきます。

例として見ていくレイアウト

movie-seat-bokking.png

meal-finder.png

expense-tracker.png

Infinite-scroll.png

New-Year.png

詳細は講師の方のリポジトリを参照してください。

要素内に余白を作りたいときはpaddingを使う

要素内に適度な余白を作りたい時にはpaddingを使います。
中にテキストを持つ要素はほとんどpaddingを使っていました。

paddingあり
padding.png
paddingなし
non-padding.png

paddingあり
padding-2.png
paddingなし
non-padding-2.png

paddingあり
padding-3.png
paddingなし
non-padding-3.png

paddingありの方が圧倒的に良いですね。

要素間を離したい時はmargin

当然といえば当然ですが、要素サイズの大小に関わらず要素間の距離を開けたい時はmarginを上手く使います。

margin-big.png
margin-medium.png

大きなmarginよりも、小さい要素間の距離を少し開けたい時に使うmarginの方が難しく感じました。
margin-left.png
margin-small.png

詳しくは後述しますが、N番目の要素にのみmarginを適用することで映画館の座席っぽいデザインを作ることが出来ます。

movie-seats.png

レイアウトの構成

レイアウト構成については、この教材の場合flexの使用率が圧倒的でした。

レイアウト全体をいくつかの大きめな「ブロック」に分割して構成、bodyflexを適用して中央寄せ。
という流れが多かったです。

felx-1.png
flex-2.png
flex-3.png
flex-4.png

この流れでレイアウトを組んでいくと全体の構成がつかみやすく、どのように全体のレイアウトを組んでいけば良いのかわかりやすかったです。
また、勝手に中央寄せになってくれるので全体的にスッキリします。

border-radiusをよく使う

指定した長さを半径として、ブロックの四隅を丸くするプロパティです。

カクカクしたデザインよりも少し角を丸めたデザインが多かった印象です。

border-radiusあり
border-radius.png
border-radiusなし
border-radius-none.png
border-radiusあり
border-radius-2.png
border-radiusなし
bouder-radius-none-2.png

また、border-radiusというよりborderの使い方になりますが、下のように画像をborderで囲んでいます。
ただ画像を表示するよりもよりカードっぽく表示することが出来ます。
images-good.png

1番上/下の要素は上/下に余白を作る

1番上/下にいる要素は上/下にmarginを設定することで、不自然に上下に寄らない程度の余白を作っていました。

margin-top.png
margin-top-buttom.png

開発の流れ

JavaScriptによるDOM操作でレイアウトを作る場合、以下の流れが共通していました。
「チュートリアルでやるような小規模なアプリケーションだとこの方がわかりやすい」という話かもしれませんが、実際この流れだと理解しやすかったです。

  1. まずダミーHTML(JavaScriptで作る予定のレイアウト)を書く
  2. ダミーHTMLに対してCSSを書いてスタイルを設定
  3. 最後にJavaScriptを書き、DOM操作でレイアウトを作っていく

使えそうなデザイン達

何かしら使えそうなデザイン達をまとめていきます。

映画館の座席っぽく

movie-seat

<div class="row">
  <div class="seat"></div>
  <div class="seat"></div>
  <div class="seat"></div>
  <div class="seat occupied"></div>
  <div class="seat occupied"></div>
  <div class="seat"></div>
  <div class="seat"></div>
  <div class="seat"></div>
</div>
.row {
    display: flex;
}
.seat {
    background-color: #444451;
    height: 12px;
    width: 15px;
    /* 要素を切り離す */
    margin: 3px;
    /* 左右上側を丸めてシートっぽくする */
    border-top-left-radius: 10px;
    border-top-right-radius: 10px;
}

四角を作る → marginで切り離す → 左右上側を丸める
ことで作ることができます。

N番目の子要素を選択

映画館の座席なので、下のように端2列は中心4列から少し離したいです。

movie-seat-2

そこで、 nth-of-typeを使います。

.seat:nth-of-type(2) {
    margin-right: 18px
}

.seat:nth-last-of-type(2) {
    margin-left: 18px
}

参考

:nth-of-type()
「指定した要素の親要素」の子要素のうち、指定したセレクタの「N番目」の要素を選択する。

:nth-child()
「指定した要素の親要素」の子要素を見て、セレクタ関係なしに「N番目」の要素を選択する。

カーソルされた時に強調

movie-seat-cursole

.seat:not(.occupied):hover {
    cursor: pointer;
    transform: scale(1.2);
}

立体的なスクリーン

.screen {
    background-color: #fff;
    height: 70px;
    width: 100%;
    margin: 15px 0;
    transform: rotateX(-45deg);
    box-shadow: 0 3px 10px rgba(255, 255, 255, 0.7);
}
.container {
        perspective: 1000px;
        margin-bottom: 30px;
    }

transform でX軸を基準に-45度回転させ、
perspective で3D配置された子要素に遠近感を与えます。

回転・遠近なし
image.png

回転・遠近あり
X軸を基準に若干傾き、3D風になっています。
image.png

検索欄

<div class="flex">
    <form class="flex" id="submit">
        <input type="text" id="search" placeholder="Search for meals or keywords">
        <button class="search-btn" id="submit" type="submit">
            <i class="fas fa-search"></i>
        </button>
    </form>
    <button class="random-btn" id="random">
        <i class="fas fa-random"></i>
    </button>
</div>

完成形
image.png


.flex {
    display: flex;
}

input,
button {
    border: 1px solid #dedede;
    border-top-left-radius: 4px;
    border-bottom-left-radius: 4px;
    font-size: 14px;
    padding: 8px 10px;
    margin: 0;
}

input[type="text"] {
    width: 300px;
}

image.png

  • input 、2つの button.flex で囲って横並びに
  • 共通でborder をセット、左側の角を丸める

.search-btn {
    cursor: pointer;
    border-left: 0;
    border-radius: 0;
    border-top-right-radius: 4px;
    border-bottom-right-radius: 4px;
}

image.png

  • .search-btnborder を削除、右側だけ丸める

.random-btn {
    cursor: pointer;
    margin-left: 10px;
    border-top-right-radius: 4px;
    border-bottom-right-radius: 4px;
}

image.png

  • random-btn は検索欄から少しだけ離し、右側も丸める。共通で左側を丸めてあるので、両側が丸められる。

画像をカード風に表示する

<div id="meals" class="meals">
    <div class="meal">
        <img src="https://www.themealdb.com/images/media/meals/ysxwuq1487323065.jpg" alt="Fish pie">
        <div class="meal-info" data-mealid="52802">
            <h3>Fish pie</h3>
        </div>
    </div>

    <div class="meal">
        <img src="https://www.themealdb.com/images/media/meals/a15wsa1614349126.jpg" alt="Fish fofos">
        <div class="meal-info" data-mealid="53043">
            <h3>Fish fofos</h3>
        </div>
    </div>
</div>

image.png

.meals {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    /* grid 同士の距離 */
    grid-gap: 20px;
    margin-top: 20px;
}
  • grid で4列表示にして間隔を離す。
.meal {
    cursor: pointer;
    position: relative;
    height: 180px;
    width: 180px;
    text-align: center;
}
  • 元画像のサイズで表示されないようにサイズに制限をかける
  • absoluteを子要素で利用するため、 relative にしておく
.meal img {
    width: 100%;
    height: 100%;
    border: 4px #fff solid;
    border-radius: 2px;
}
  • 画像の周りをボーダーで囲って丸める → 画像オンリーよりもカードっぽく
  • 幅と高さを親要素 meal に対する100%に
.meal-info {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    background: rgba(0, 0, 0, 0.7);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.2s ease-in;
    opacity: 0;
}

.meal:hover .meal-info {
    opacity: 1;
}

meal > img & meal-infoなので、 meal-info は本来画像の下側に表示される。

今回はホバーしたら meal-info が表示される形にしたいので、 absolute を使って親要素の真上に meal-info を持ってくる。

そして、ホバーされた時に opacity が1になるようにする。

hover

メディアクエリ

@media(max-width: 800px) {
    .meals {
        grid-template-columns: repeat(3, 1fr);
    }
}
@media(max-width: 700px) {
    .meals {
        grid-template-columns: repeat(2, 1fr);
    }

    .meal {
        height: 200px;
        width: 200px;
    }
}
@media(max-width: 500px) {
    input[type="text"] {
        width: 100%;
    }
    .meals {
        grid-template-columns: repeat(1fr);
    }
    .meal {
        height: 300px;
        width: 300px;
    }
}

幅に応じて gridmeal の幅を変更することでレスポンシブに。

材料の一覧表示(整列されていないリスト)

displayをいじってあえて整列していないリストにすることで、一覧性を高める事ができます。

image.png

ul {
    padding-left: 0;
    list-style-type: none;
}

ul li {
    border: 1px solid #dedede;
    border-radius: 5px;
    background-color: #fff;
    display: inline-block;
    color: #2d2013;
    font-size: 12px;
    font-weight: bold;
    padding: 5px;
    margin: 0 5px 5px 0;
}

2つの横並び要素をそれぞれの中央に配置

完成形
income-expense.png


INCOMEとEXPENSEをそれぞれ中央に配置したい。
image.png

<div class="inc-exp-container">
    <div>
        <h4>Income</h4>
        <p id="money-plus" class="money plus">+$0.00</p>
    </div>
    <div>
        <h4>Expense</h4>
        <p id="money-minus" class="money minus">-$0.00</p>
    </div>
</div>
.inc-exp-container {
    background-color: #fff;
    box-shadow: var(--box-shadow); /* 変数を利用 */
    padding: 20px;
    display: flex;
    justify-content: space-between;
}

flex + space-between でコンテナの両サイドに表示。


image.png

.inc-exp-container div {
    flex: 1;
    text-align: center;
}

.inc-exp-container div:first-of-type {
    border-right: 1px solid #dedede;
}

flex: 1 で隙間を埋めることで中央寄せする。

flex: 1;は一括指定プロパティ。
値が一つの場合は grow (空いた幅を埋める)を設定したことになる。

ホバーすると表示される削除ボタン

hover-delete

.delete-btn {
    cursor: pointer;
    background-color: #e74c3c;
    border: 0;
    color: #fff;
    font-size: 20px;
    line-height: 20px;
    padding: 2px 5px;
    position: absolute;
    top: 50%;
    left: 0;
    transform: translate(-100%, -50%);
    transition: opacity 0.3s ease;
    opacity: 0;
}

.list li:hover .delete-btn {
    opacity: 1;
}

transform: translate(-100%, -50%);でXY位置を調整している。

丸数字を表示

circle-number.png

<div class="post">
  <div class="number">1</div>
  <div class="post-info">
    <h2 class="post-title">sunt aut facere repellat provident occaecati excepturi optio reprehenderit</h2>
    <p class="post-body">quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto</p>
  </div>
</div>
.number {
    position: absolute;
    top: -15px;
    left: -15px;
    font-size: 15px;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: #fff;
    color: #296ca8;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 7px 10px;
}

image.png
post に対して absolute + -15px → 左上に固定
flex で中央寄せ → numberの中身を中央に寄せる

丸がバウンドするアニメーション

bounce-animation

.circle {
    background-color: #fff;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin: 5px;
    animation: bounce 0.5s ease-in infinite;
}

.circle:nth-of-type(2) {
    animation-delay: 0.1s;
}

.circle:nth-of-type(3) {
    animation-delay: 0.2s;
}

@keyframes bounce {
    0%,
    100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-10px);
    }
}

丸を作る → アニメーションを設定 → ディレイを入れるだけです。

背景を画像にする

image.png

body {
  background-image: url('https://images.unsplash.com/photo-1467810563316-b5476525c0f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1349&q=80');
  /* 背景画像を1枚のみにする */
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center center;
  height: 100vh;
  color: #fff;
  font-family: "Lato", sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  margin: 0;
  overflow: hidden;
}

背景画像を暗くする

image.png

body::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
}

疑似要素に対して background-color を割り当てることで暗くします。

文字まで暗くなってしまっているので修正します。

image.png

body * {
  z-index: 1;
}

z-index の指定により背景以外が暗くならないようにします。

まとめ

  • 余白は大事!!
    • paddingmarginを上手く使う
    • 最初はパクるところから
  • 最初にざっくり全体のレイアウトを決めてしまうと楽。
  • よく使うデザインの早引き的なものがあると良さげ。
1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5