CSS千本ノック~国旗を作ろう~

  • プロダクション
CSS千本ノック~国旗を作ろう~

目次

私たちが住むこの世界にはたくさんの国があり、たいていの国には国旗があります。そして、多くの国旗は少ない色とシンプルな図形で幾何学的にデザインされています。

ということは、CSSでお絵描きができそうだと思いませんか?

CSSコーディングの練習、腕だめしにぴったり

HTML/CSSで図形を描くのはWebコーディングの基本技能のひとつ。国旗の再現はそのような技能の鍛錬にちょうどいい練習台になります。2色や3色に分かれているだけの単純なものから、再現方法がちょっと思いつかないような複雑ものまで、バラエティも豊かです。仕事の合間の息抜きや頭の体操に、パズル感覚で取り組んでみてはいかがでしょう。

ちなみに、国旗のデザインをCSSだけで再現しようという試み(というか遊び)はすでに世界中のエンジニアたちが趣味で取り組んでいます。とはいえ、CSSの仕様は日進月歩ですし、同じ図柄を表現するにもさまざまなアプローチがありますから、ほかの誰も思いつかなかったようなあなただけのやり方で国旗が描けるかもしれませんよ。

縛りプレイ

コーディングに自分なりの制約を設けると、難易度を調整できます。たとえば、

  • div要素1個のみ使用可1
  • before/after擬似要素は使用禁止
  • clip-pathプロパティは使用禁止
  • 相対サイズのみ使用可

などの制約は、きっとこのゲームを(もうゲームと言ってしまいますが)格段に面白くしてくれることでしょう。

国旗には仕様がある

さて、多くの国旗は詳細な仕様が決められています。寸法、使う色などの設計図です。”国名 national flag specifications”といった条件でWebを検索すると探し出すことができます。たとえば日本国旗(日章旗)の場合は「国旗及び国歌に関する法律」で、以下のように定められています。

  • 縦横比は縦が横の2/3
  • 円の直径は縦の3/5
  • 円の中心は旗の中心
  • 地の色は白、円の色は紅色
  • 図に起こすとこのような感じでしょうか
    図に起こすとこのような感じでしょうか

意外とざっくりなことに驚きます。「紅色」はJISの慣用色名表では#BD1E48となっていますが、このままだと少し暗い感じがします(布に染められて空に掲揚されるとちょうどよい赤なのかもしれません)。もし明示されていない仕様があれば、そこは自分なりにアレンジしてもよいでしょう。

実際に作ってみよう

上のような仕様をデザインカンプとしてCSSをコーディングしてみましょう。日章旗を例に、いくつかのアプローチで描画してみます。

日章旗の作例1

.japan {
    background-color: #fff;
    aspect-ratio: 3/2;
    position: relative;
    &::before {
        background-color: #c00;
        content: '';
        display: block;
        height: 60%;
        aspect-ratio: 1;
        border-radius: 100%;
        position: absolute;
        top: 20%;
        left: 30%;
    }
}

擬似要素と絶対配置を用いたトラディショナルな実装例です。比較的新しいプロパティはaspect-ratioくらいでしょう。

作例2

.japan {
    background-color: #fff;
    aspect-ratio: 3/2;
    display: grid;
    place-content: center;
    container-type: size;
    &::before {
        background-color: #c00;
        content: '';
        display: block;
        width: 60cqh;
        aspect-ratio: 1;
        border-radius: 100%;
    }
}

擬似要素を使っている点では同じですが、配置や寸法に無理してモダンなプロパティを使っています。新しいオモチャを手に入れたら使ってみたくなる心理です。

作例3

.japan {
    background-color: #fff;
    aspect-ratio: 3/2;
    &::before {
        background-color: #c00;
        margin: auto;
        content: '';
        display: block;
        height: 100%;
        aspect-ratio: 1;
        clip-path: circle(30%);
    }
}

clip-pathを用いた作例です。clip-pathは、複雑なパスを描くSVGのような機能まで備えた強力なツールです。これに頼りすぎると創意工夫を凝らす愉しみを損ないかねませんから、行き詰まった時の最終手段くらいにしておいたほうがよいかもしれません。

作例4

.japan {
    --red: #c00;
    --white: #fff;
    --radius: 60%;
    aspect-ratio: 3/2;
    background-image: 
        radial-gradient(
            circle closest-side,
            var(--red) var(--radius),
            var(--white) var(--radius));
}

図柄の描画にbackground-imageだけを使った実装です。擬似要素を使わないぶん、記述が少しすっきりしますね。同心円グラデーションradial-gradient()で、半径が高さに対して60%の正円を描いています。

ユニオンジャック

日章旗の例に限らず、国旗のCSS再現ではグラデーション関数を組み合わせて図柄を表現するアプローチがメインになると思います。クリッピングした擬似要素などだけでは表現しきれない国旗がたくさんあるからです。タイトルこそCSS千本ノックと銘打ったものの、CSS国旗チャレンジは不可避的にグラデーション関数のドリルになっていくはずです。

そこで、linear-gradient()をごりごり使ってイギリス国旗(ユニオンジャック)を描いてみましょう。

.uk {
    --blue: #012169;
    --white: #fff;
    --red: #c8102e;
    --angle: atan2(3, 5);
    --background-stripe:
        transparent calc(50% - 6cqi),
        var(--white) calc(50% - 6cqi) calc(50% - 4cqi),
        var(--red) calc(50% - 4cqi) 50%,
        var(--white) 50% calc(50% + 6cqi),
        transparent calc(50% + 6cqi);
    --stripe1:
        linear-gradient(
            var(--angle),
            var(--background-stripe)
        ) left top / 50% 50%;
    --stripe2: 
        linear-gradient(
            calc(180deg - var(--angle)),
            var(--background-stripe)
        ) right top / 50% 50%;
    --stripe3: 
        linear-gradient(
            calc(180deg + var(--angle)),
            var(--background-stripe)
        ) right bottom / 50% 50%;
    --stripe4: 
        linear-gradient(
            calc(var(--angle) * -1),
            var(--background-stripe)
        ) left bottom / 50% 50%;
    --stripe5: 
        linear-gradient(
            90deg, 
            transparent 40cqi, 
            var(--white) 40cqi 60cqi, 
            transparent 60cqi
        );
    --stripe6: 
        linear-gradient(
            transparent 20cqi, 
            var(--white) 20cqi 24cqi, 
            var(--red) 24cqi 36cqi, 
            var(--white) 36cqi 40cqi, 
            transparent 40cqi
        );
    --stripe7: 
        linear-gradient(
            90deg, 
            transparent 44cqi, 
            var(--red) 44cqi 56cqi, 
            var(--white) 56cqi, 
            transparent 56cqi
        );
    background:
        var(--stripe7),
        var(--stripe6),
        var(--stripe5),
        var(--stripe4),
        var(--stripe3),
        var(--stripe2),
        var(--stripe1);
    background-color: var(--blue);
    background-repeat: no-repeat;
    height: 60cqi;
}

ネイビーブルーの背景の上に、順序に気をつけながらlinear-gradient()で描いた7種のストライプを重ねています。下の図はレイヤー別に分解したもの。数字が大きいほど手前のレイヤーになります。

4方向の斜めストライプ②~⑤は点対称の関係にありましたので、同じグラデーション成分の角度を変えるだけで表現できました。また、⑥と⑧はレイヤーを分ける必要があるが、⑦の白と赤は同じレイヤーでも大丈夫。こんな風に、図柄からコードを合理化できそうな特徴を探すのもCSS国旗チャレンジの楽しさのひとつかもしません。

この記事の執筆者

G・I フロントエンドエンジニア

CXコンサルティング事業部

この記事に関するご相談やご質問など、お気軽にお問い合わせください。

お問い合わせ

タグ一覧