Quantcast
Channel: CSSタグが付けられた新着記事 - Qiita
Viewing all 8496 articles
Browse latest View live

ProgateでHTML&CSS&JavaScript完全に理解した(笑)

$
0
0

2019年8月某日、僕は愕然としていた。Pythonを使うと聞いて応募したアルバイト、時給も良いし、交通費も出るしで喜び勇んで職場へ向かったのだが...
バイト先「ちょっとこのWebページ、いい感じにしてくれない?」
僕「Pythonしか書いたことないので、時間かかるかも知れません。」
バイト先「大丈夫、JavaScriptなんてPythonみたいなものだし。」
僕(流石にそれは違うのでは...?)
僕「HTMLもCSSもJavaScriptも触ったことないですよ?」
バイト先「まあ、腕試しだと思ってさ。明後日までによろしく」
僕「明後日ですか!?流石に間に合わない気がするんですが、それにいい感じってどんな感じですか!?」
バイト先「なんかこう、モダンな感じ! じゃ、よろしく!!」
僕(無茶振りすぎるだろ...。これか、最近流行りの異世界転生ってやつは。「転生したらフロントエンドエンジニアでした」とか、「私、能力はPythonって言ったよね!」そういうやつなのか!?)
とは言え、背に腹は変えられない。ここでバイト代がでなければ困る。
だが今、持っている知識は、

  • HTML:なんかWebのガワ作るやつ
  • CSS:なんか色つけるやつ
  • JavaScript:なんか動かすやつ

くらいしかない。詰んだかもしれない。
そうだ、Progateだ。あれで基礎固めすれば、とりあえず動かせるものが作れるはずだ。
猛暑まっただ中、蝉の声を聞きながら、Webの世界へと足を踏み出した。

はじめに

これまでPythonしか書いたことがなかった筆者がProgateでフロントエンドを完全に理解(笑)し、その後、谷底に突き落とされるまでを描いたポエムです。

完全に理解したという言葉をご存知でしょうか?
エンジニアの世界では、何かの初歩をマスターし、ある種の万能感に満たされている状態を指すことが多いです。
完全に理解できるほど単純なことしか学んでいないがゆえの帰結なのですが、ここから歩みを進めることが難しかったりします。
これはちょうど、MMMORPGのキャラクタークリエイトが終わった瞬間に似ています。この瞬間が最も期待感と幸福感が高いかもしれません。
下のツイートが参考になると思います。

Progateを何周もしてしまう人がいるのも、こうした心理が働くからかも知れません。私はProgateを批判したいわけではありません。Web系知識の取っ掛かりとしては非常に分かりやすくまとめられていると思っています。
ですが、この先にこそ、本当の面白いが待っているとも思います。ぜひ、一緒にめくるめく天国と地獄のフロントエンドロードに足を踏み入れましょう!

この記事の目的は以下の3つです。
1. ProgateのHTML&CSS&JavaScriptで習得できる内容を紹介して、未履修の方にProgateをやるモチベーションを高めてもらう
2. Progateは終わったが、次に何をすべきかわからない方に、次に取り組むと良い内容を紹介する
3. 現役フロントエンドエンジニアの方からのアドバイスを期待する(助けてください、何でもしますから!!!)

記事は「Progateで完全に理解した」と「何もわからない」の2段構成になっています。
前半を読めばProgateで何が得られるのか大雑把に把握できます。
後半ではProgate後にやると良いことや、知識不足で失敗したことなどをまとめました。

Progateで完全に理解した(笑)

この章ではProgateを通して学んだことを紹介していきます。すでに学んだ方は読む必要がないと思われますので、何もわからないまで飛ばしていただければと思います。

HTML&CSS完全に理解した(笑)

ProgateのHTML&CSSで学べる内容についてまとめました。

HTML

HTMLとはHyperText Markup Languageの略で、ウェブページの内容や構造を記述する言語です。
HTMLは要素(タグ)と属性の大きく分けて2つの構造から成り立ちます。タグで表示したい内容を囲みながら、見た目を変えたい部分に属性を指定します。
例えばtestという文字を表示するには次のようにします。

<divid="hoge">
  test
</div>

この例ではdivが要素で、idのhogeが属性です。

ブラウザで表示できるようなHTMLファイルにするには次のようにします。

<!DOCTYPE html><html><head><metacharset="UTF-8"/><metaname="viewport"content="width=device-width"/><title>test page</title></head><body><divid="hoge">
      test
    </div></body></html>

この内容をindex.htmlなどに保存してブラウザで開けば、下の画像のように表示されます。
Screenshot from 2019-11-02 10-36-12.png
2行目移行の<html>内がHTMLの内容です。それぞれの要素について説明します。
<html>:HTMLの内容を記述していく要素です。<html>は全ての要素の基点となる要素なので、ルート要素とも呼ばれています。HTMLでの全ての要素はこのタグ内に書かなければいけません。
<head>:HTMLファイルに関する情報(メタデータ)を記述する要素です。ここにはファイルの文字コードやページタイトル、CSSやJavaScriptへのパスなどを記述します。
<body>:HTMLファイル内のコンテツを入れる要素です。ファイル内にひとつだけ書くことができます。
<div>:要素のレイアウトを指定するための要素です。要素を囲ってひとまとめにしたり、大きさや色を変える時に使います。
他にも段落や見出しなど様々な要素があります。詳しくはこちらで説明します。

CSS

CSSとはCascading Style Sheetsの略でスタイルシートとも呼ばれます。HTMLがウェブページの構造を作る言語であるのに対し、 CSSはウェブページの見た目を整える役割を持っています。
CSSはセレクタ、プロパティ、プロパティの値の3つで成り立ちます。

セレクタ{プロパティ:値;}

例えばdiv要素の文字色を赤に変えるには次のようにします。

div{color:red;}

代表的なCSSプロパティ

代表的なCSSプロパティに関して軽く説明します。

padding&margin

paddingは要素から要素の境界(border)までの余白を指定できます。下の例ではオレンジ色の点線が境界(border)です。


See the Pen
padding.css
by tombo gokuraku (@tombo_gokuraku)
on CodePen.



paddingは値の指定方法が4つあり、値が1つなら4辺全てに同じ値、2つなら上下|左右、3つなら上|左右|下、4つなら上|右|下|左(時計回り)に指定できます。
またpadding-top,padding-bottom,padding-left,padding-rightなどを使うと個別に設定することもできます。

marginは要素の境界(border)から要素の外側までの余白を設定できます。marginを設定することで、下の例のようにオレンジ色境界線に対して、緑色の要素の外側までの余白が指定できます。


See the Pen
margin.css
by tombo gokuraku (@tombo_gokuraku)
on CodePen.



指定方法はpaddingの場合と同じです。またpaddingと同じようにmargin-top,margin-bottom,margin-left,margin-rightのように個別に指定することができます。
height&width

heightとwidthで要素の高さと幅を指定できます。指定できる値の単位はpx,em,%,autoの4種類です。%は親要素に対する割合で大きさが決まります。autoはwidthに指定した場合は親要素いっぱいに広がります。heightに指定した場合は要素内のコンテンツを表示するのに最適な高さになります。


See the Pen
height_width.css
by tombo gokuraku (@tombo_gokuraku)
on CodePen.


color

colorで文字の色を設定できます。color: #ff0000;のように16進数のカラーコードで色を指定します。よく使われる色に関してはredやblueなどの文字列で指定することができます。


See the Pen
color.css
by tombo gokuraku (@tombo_gokuraku)
on CodePen.


CSSセレクタ

CSSではHTMLで書いた属性をCSSセレクタで指定することができます。以下はその一例です。

div{/* div要素を指定 */}div.hoge{/* div要素でありクラス('hoge')を持っている要素を指定 */}div#hoge{/* div要素でありID('hoge')を持っている要素を指定 */}div,p{/* div要素とp要素を指定 */}divp{/* div要素を祖先に持つp要素を指定 */}

HTML&CSSのレッスンを全て終えると下のようなWebサイトが作れるようになります! ぜひこの完成形を目指して完走してください。
progate_product.gif

JavaScript完全に理解した(笑)

ProgateのJavaScriptで学べる内容についてまとめました。

JavaScriptとは?

JavaScriptとはWebページに動きをつけるためのプログラミング言語です。JavaScriptを使うことで地図やカレンダー、ゲームなどユーザーの入力に応じて動的に変化するページを作ることができます。

JavaScriptの書き方

簡単にJavaScriptの書き方を説明します。

文はセミコロンで区切る

JavaScriptは、文ごとに処理していき、文は;で区切られます。処理が1行のみの場合は;を省略することもできますが、書き忘れや処理の追加時に書き足すことを考えると、普段から書いておく方が無難です。

コメントアウト

JavaScriptでのコメントアウトは次のように書きます。

// 1行のコメントアウト/* 複数行の
   コメントアウト
*/

変数

JavaScriptでは定数をconst,変数をletで宣言します。

constimmutableValue='hoge';letmutableValue=3;

制御文

主な制御文(if,for,while)を説明します。
条件分岐させたい時はifを使います。

if(条件式){実行する文}

一致しなかった場合の処理はelseを使って書きます。

letname='千尋'if(name===''){console.log(`${name}!`);}else{console.log(`フン。 ${name}というのかい? 贅沢な名だねぇ。`);name='';console.log(`今からおまえの名前は${name}だ。いいかい、${name}だよ。分かったら返事をするんだ、${name}!!`);}

繰り返し処理はforかwhileを用います。繰り返しの回数が分かっている場合はforを使います。

for(初期化式;条件式;増分式){実行する文;}

条件を満たすまで繰り返したい場合はwhileを使います。

while(条件式){実行する文;}

関数

関数は一連の手続きをひとまとめにする機能です。JavaScriptには関数の宣言方法が3通りあります。

// 通常の関数宣言functionnormalFunction(){return'normal function'}// 関数式を使った関数宣言constfunctionExpression=function(){return'function expression'}// Arrow FunctionconstarrowFunction()=>{return'arrow function'}

通常の関数宣言は他のプログラミング言語と同じようにnormalFunction()のように呼び出すことができます。
関数式ではfunction()のように関数名を省略して宣言できます。このような関数のことを匿名関数(または無名関数)といいます。名前を持たないため、functionExpression()のように代入した変数を使って関数を呼び出します。
Arrow Functionはfunctionすら省略して関数を書く方法で、さらに他の関数宣言にはない特徴を持っています。JavaScriptはthisを使って呼び出し元のオブジェクトを参照することができますが、普通の関数の場合はどこから呼び出されたかによって、thisの値が変化します。一方でArrow Functionは呼び出し方に依らず、常にthisが静的に決まるという性質を持っています。

配列

配列とは値に順序をつけて格納できるオブジェクトです。 配列に格納した値を要素、要素の位置をインデックス(index)と呼びます。 インデックスは0から始まる連番となります。JavaScriptでは[]を使って配列を作ることができます。

letnumbers=[1,2,3,4,5]//indexを指定して配列にアクセスconsole.log(numbers[0])//1//lengthプロパティで配列の長さがわかるconsole.log(numbers.length);//5//push()で末尾に要素を追加、pop()で末尾から要素を削除numbers.push(6)console.log(numbers);//[1,2,3,4,5,6]lonsole.log(numbers.pop());//6

何もわからない

ここからはProgate修了後から実際にコーディングしていく過程で苦しんだこと、早く知っておけば良かったことなどについてまとめました。

HTML何もわからない

「Progate終わったし、もう何も怖くない!」

何だこのタグ?俺は聞いてねえぞ?(<table>,<form>)

「何だこのタグ? Progateには出てこなかったぞ。『これゼミでやったやつだ!』って言えないじゃん!!」
HTML「いつからHTMLをマスターしたと錯覚していた」

意外と使うのにProgateでは紹介されないタグについて紹介します。

<table>

<table>は表を作ることのできる要素です。例えば下のように書きます。

See the Pen table-example by tombo gokuraku (@tombo_gokuraku) on CodePen.

要素は上から順に次のような役割を持っています。
<table>:表を作成する要素
<caption>:キャプションをつける要素
<tr>:表の行データを格納する要素
<th>:表のヘッダーを作る要素
<td>:表のデータを格納する要素

表の罫線を追加するには次のようにborderを追加します。border-collapseを設定すると隣接する境界が折り畳まれて、境界線が1本になります。

table,th,td{border:1pxsolidblack;border-collapse:collapse;}

<form>

formはログイン画面やアンケート入力など、ユーザーからの入力をサーバーに送信するために使います。

See the Pen form-example by tombo gokuraku (@tombo_gokuraku) on CodePen.

actionにはフォーム経由で送信された情報を処理するためのURIを指定します。
methodにはフォームを送信する際にブラウザが使用するHTTPメソッドを指定します。
<form>中の<input>には<label>を使ってラベルを貼ることができます。予め<input>にidを指定して、<label>内のfor属性に<input>のidを指定すると、ラベリングできます。

タグをちゃんと閉じなくても表示されるという恐怖(Linter/Validator)

「タグ閉じてなかったり、抜けてたりしても表示されちゃうのだが?」
HTML「所詮はマークアップ言語ですから...」

HTMLは良くも悪くもブラウザ(のHTMLパーサー)が優秀なため、壊れたHTMLでも問題なく開けてしまいます。見た目にはなんの問題もないのに、いざコーディングを始めてみたら、タグが対応していなかったり、抜けてたり、なんてことがあります(そういうコードのリファクタリングをしなければならない時は発狂します)
例えば先程の表を作るコードは<tr>を適当に抜いたり、タグを閉じなかったりしてもうまく表示されます。

See the Pen broken-html by tombo gokuraku (@tombo_gokuraku) on CodePen.

この手のコードを書かないために、LinterやValidatorが使えます。
W3CのMarkup Validation Serviceを使うと手軽にHTMLのvalidationができます。上のコードをバリデーションすると下のような結果がでてきます。
validator.png

あるいはエディタにLinterというコードを解析してバグを検出するプログラムを導入するのもありです。VSCodeで使えるhtmlhintなどがオススメです。

CSS何もわからない

「CSSなんて、色つけて、レイアウトして終わりっしょ」
そう思っていた時期が僕にもありました...。

なぜ俺のイカしたスタイルが適応されないのか?(CSSの優先順位)

「なぜだ!?なぜ俺のイカしたスタイルが適応されないんだ!?」
CSS「お前には伝えていなかったが、CSSには優先順位があるのだよ」

Progateではあまり触れられていませんが、CSSにはスタイル適応に優先順位があります。
例えば下のようにp要素の色を設定したとします。最後のp{color:black;}で文字色を黒にしようとしていますが、反映されていません。


See the Pen
css-specificity-example
by tombo gokuraku (@tombo_gokuraku)
on CodePen.



ここではp.item#highlightのCSSが優先されています。
大雑把に書けばCSSには次のような優先順位があります。
div#highlight.container>div#highlight>#highlight>div.container>.container>div>*

全称セレクタが最も優先順位が低く、IDやクラスを指定するごとに優先順位が高くなっていきます。
より正確にはCSSセレクタにはSpecificityと呼ばれる数値が設定されていて、タイプ(要素の指定)で+1、クラスの指定で+10、IDの指定で+100のようにセレクタの数と種類に応じて数値が計算されます。Specificityが高ければ高いほどより優先的にCSSが適応されます。
詳しくはこちらのドキュメントをご覧ください。

CSSって入れ子にできないの?(SASS)

「HTMLは入れ子で書いていくのに、なんでCSSは入れ子じゃないんだ?」
SASS「CSSを入れ子で書きたいと聞いて」

SASSはSyntactically Awesome Style Sheetの略でCSSを入れ子にしたり、変数を定義したりできます。
SASSはコンパイルしてCSSに変換することで、通常のブラウザでも読み込めるようになります。
本来は開発環境を構築しなければなりませんが、CodePenなどのサービスで手軽に試すことができます。
例えば先程のCSSは下のように書いていました。

div.container{background-color:#eee;color:black;}.item{color:blue;}#highlight{color:red;}

これをSASS(SCSS記法)で書き直すと下のようになります。


See the Pen
scss-example
by tombo gokuraku (@tombo_gokuraku)
on CodePen.


上の例ではクラスやIDの指定部分を入れ子にしたり、背景色の値を$material-gray-200: #eee;のように変数化したりしています。

SASSにはSASS記法とSCSS記法の2種類があります。SCSS記法は{}や;を使ってCSSっぽくスタイリングする方法で、SASS記法は{}や;を使わずにインデントのみで、階層関係を記述する記法です。

SASSは他にも@extendでスタイルを継承したり、@mixinで引数を受け取ってスタイルを展開したりできます。
SASSのインストールはこちら使い方はこちらが参考になります。困った時はドキュメントも使えます。
サクッと学ぶならProgateもオススメです。

CSSの名前ってどうしたらいいの?(BEM)

「.container.component.wrapperとかいうすごくバカっぽいクラスを書き始めちゃったんだがどうしたらいい?」
BEM「Block-Element-Modifierの規則で名付ければ一貫性が出るで」

BEMはBlock-Element-Modifierの略で、CSSの命名規則の1つです。クラス名をBlock__Element--Modifierのようにつけて、親子関係や強調表示などをクラス名で表します。Blockは基本となる大きな塊、ElementはBlock直下の子要素、Modifierは選択されている要素や強調したい要素などを表します。
例えばBEMではHTMLを以下のように書きます。

<divclass="block"><divclass="block__element">hoge</div><divclass="block__element--modifier">piyo</div><divclass="block__element">foo</div></div>

これを装飾するCSSは次のようになります。

.block{background-color:#eee;}.block__element{font-size:18px;color:#212121;}.block__element--modifier{font-size:18px;color:#C62828;}

BEMを使って書くと、クラス名からHTMLの構造が想像できるようになります。要素を別の要素に変更した場合もスタイルが適応できるのもメリットの1つです。
さらにSASSを使うとクラス名を省略することができます。上のCSSをSCSSで書き直すと下のようになります。

$material-gray-200:#eee;$material-gray-900:#212121;$primary:#C62828;.block{background-color:$material-gray-200;%__element{font-size:18px;}&__element{@extend%__element;color:$material-gray-900;&--modifier{@extend%__element;color:$primary;}}}

SCSSで書くと、入れ子の中で&を使うだけで、blockやelementなどのクラス名を省略できます。BEMで冗長になりがちなクラス名が省略できるのは大きなメリットです。
また変数定義$やプレースホールダー%を使って、要所要所でCSSを使い回せるのもSCSSの良いところです。

BEMの概要をつかむにはこちらの記事チュートリアルはこちらが参考になります。

そもそもCSSにスコープがないのが問題なんじゃないの?(styled-components)

「SASSとBEMで再利用性の高いHTMLとCSSが書けるのは分かったけどさ、やたらクラス名長くなるし、ElementとかBlockの名前を工夫しないと、他と衝突するんだけど? そもそもなんでCSSってグローバルスコープなわけ? こういうのがだるいから人類はオブジェクト指向を生み出したんじゃなかったの?」
styled-components「気づいてしまったか...」

styled-componentsはCSS in JSと呼ばれるものの1つで、JavaScriptの中にスタイルを書くことができます。Webページの要素をコンポーネントと呼ばれる特定の機能を実現する単位に区切ることで、スタイルが適応される範囲をコンポーネント内に限定することができます。これによって複雑な命名の問題を解消することができます。
styled-componentsは通常、React(後述します)などのフレームワークと一緒に用いられます。
例えばカードコンポーネントのスタイルは次のように書きます。


See the Pen
react-example
by tombo gokuraku (@tombo_gokuraku)
on CodePen.


前半のTitle, Card変数を宣言している部分にstyled-componentsが使われています。

constTitle=styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: Black;
`;

上のように書くことで、render関数内で<Title>と書くだけで、スタイル済みのh1要素を出力させることができます。
コンポーネント単位で管理することで、命名の煩雑さが避けられると同時に、再利用性も向上します。

styled-componentsの公式チュートリアルはこちらstyled-componentsを使ったCSSの設計はこちらが参考になります。

JavaScript何もわからない

「ProgateやったらWebページヌルヌル動かせるようになるだろ」
そう思っていた時期がワイにもありました...。

DOMって何ぞ?

「Progateやったのに、ページ内の要素ヌルヌル動かせないんだが?」
DOM「まずはDOMを理解せよ」

Progateでは主にProgateが用意したコンソール上にJavaScriptを書いて実行することでJavaScriptの学習を進めていきます。最後の方にNode.jsを使った開発環境構築が説明されますが、これだけではWeb上の要素を自由に動かすことはできません。そこで必要になってくるのがDOMに対する理解です。

DOMとはDocument Object Modelの略で、HTMLの要素をJavaScriptからアクセスできるようにツリー状に再構成したもののことです。
DOMを扱えるようになると下のように動きがあるページを作るのが簡単になります。

See the Pen dom-example by tombo gokuraku (@tombo_gokuraku) on CodePen.

このコードは1秒毎にFlexboxのCSSを書き換えて、配置を変更しています。
JavaScriptではdocument.querySelector()を使うことで、CSSを使ってDOMにアクセスできます。
querySelector()Elementを返すので、Element.styleElement.innerTextなどを使って、要素のスタイルや要素の内容にアクセスし、書き換えられます。

DOM操作やJavaScriptのクラス、非同期処理(コールバック/Promise/Async)、Event等の概念を理解するためにオススメなのが、jsprimerです。JavaScriptの初歩からTodoアプリの作成まで網羅しているので、これをやっておけば大抵のJavaScriptは書けるようになります。

jQueryはオワコン?

「DOMを扱う時によくjQueryのコードが出てくるけど、ググってると"jQueryはオワコンだ"とか、"いいや、まだ世界中で使われてる"とか、出てきて賛否両論なんだけど、どっちなの?」
jQuery「昔はお前のような冒険者だった。膝に矢を受けてしまってな...」

ここは私自身も判断がつかなかったところです。オワコンと言うには未だに多くのサイトで使われていますし、かと言って新規開発で使いたいライブラリではない、そんな印象を受けました。肯定派、否定派それぞれの意見をまとめてみました。

肯定派

  1. 簡単に書けるのでサクッとWebサイトが作れる
  2. 多くのサイトでまだ現役で使われている
  3. 学習コストが低い

否定派

  1. SPA作るのはほぼ無理
  2. 宣言的UIにならない
  3. Vanilla JavaScriptでほぼ同じ内容が書ける

肯定派の方がJavaScriptに求めているのが、CSSでは書けないアニメーションやちょっとした状態の保存や書き換え、サーバーとの通信といったタスクであるのに対し、否定派の方が求めているのはSPAの開発や高度な状態遷移、コンポーネント化による再利用性の向上などであると予想しています。お互いに開発したい対象や求めている機能が違うので、意見の食い違いが発生しているのではと考えています。
一方で、ここからは私見なのですが、jQueryが提供している手軽にリッチな見た目のWebページを作れるという機能は今後、NoCode(後述します)で提供される可能性が高く、そうなった時は正真正銘、jQueryはお役御免になると考えています。

jQueryに関する議論はこちらの記事(主にコメント欄)を参考にしました。
jQueryで書かれたコードをVanilla JavaScriptにしたい時はこちらのサイトが参考になります。

まだ生DOM触ってんの? 時代はフレームワークだぜ(React)

「イベントのコールバックで死にそう。どこでaddEventListenerしたっけ? そもそもこのDOM、いつどこで書き換えた? もう嫌だ、俺はUI1つまともに書けない、俺はこんなにも無力だ。」
React「チカラガホシイカ?」

ReactはFacebookが作成したUser Interface用のJavaScriptライブラリです。Reactの一番の特徴は宣言的UIです。
宣言的UIの説明するために、まず宣言的の対義語である命令的について説明します。
命令的とは"何をするか"を記述していく方法で、最終的な結果が前回の実行結果に依存する状態をいいます。
例えばボタンを押すと文字の色が変わるコードを命令的に書いてみます。

See the Pen imperative-ui by tombo gokuraku (@tombo_gokuraku) on CodePen.

命令的UIではif(this.classList.contains('red'))のように、まずボタンが以前どのような状態であったかを確認します。
その上でボタンの状態に合わせて、this.classList.remove('red');のようにDOMそのものを操作して、状態を変更します。

逆に宣言的とは"状態に対する反応"を記述していく方法で、最終的な結果が前回の結果に依存しません。
上の例をReactを使って宣言的に書くと次のようになります。

See the Pen declarative-ui by tombo gokuraku (@tombo_gokuraku) on CodePen.

Reactを使った例ではDOMを直接変更することはなく、render()内で現在の状態に基づいて描画するように宣言するだけです。こうすることで、状態を"いつ"変更したかを考えなくて済むようになります。
さらに状態自体もDOMで管理するのではなく、クラスで管理しています。これによって、どこで状態を変更したかも探しやすくなりました。命令的にDOMを直接変更する場合は、どこからでも変更できていました。Reactのようにコンポーネントの中に状態とそれを変更する関数を閉じ込めることによって、デバッグが楽になり、再利用性も高まりました。

宣言的UIはこちらの記事を参考にしました。

Reactを学ぶにはまずは公式の日本語チュートリアルレファレンスなどが参考になります。
また公式のExampleがReactでプロダクトを作るときの助けになります。
jQuery使いの方がざっくりとReactの利点が分かる記事(Reactを使うとなぜjQueryが要らなくなるのか)もあります。

NoCodeの登場でフロントエンドエンジニアの存在意義が何もわからない

NoCode「コーディングなんかしなくても、俺がいればデザインがそのままコードになるよw」
「そんな、俺は何のために今までコードを書いてきたんだ!? これまでの時間を返せ!」

NoCodeとはコーディング無しでウェブサイトやアプリなどを作成できるツールの総称です。
以下はその一例です。

Webサイト構築系

アプリ作成系

iPaaS(サービス同士の接続)系

他にも多くのNoCodeツールがあります。こちらのサイトにそれぞれの分野ごとにNoCodeツールがまとめられています。

Webflowで作られたイケてるサイトがあったので、ここでご紹介します。
Happy Huesというサイトで、デザイン用のカラーテンプレートが紹介されています。単純にカラーパレットを紹介するだけでなく、UIコンポーネントのどこでどの色を使ったら良いかまで載っています。サイトは左のナビゲーションドロワーでパレットが選択でき、ボタンを押せばカラーをコピーできます。
ezgif.com-video-to-gif.gif

「このレベルのサイトがコーディング無しで作れるなら、俺、要らなくない?」

NoCodeとどう向き合うか
ここからは私見ですが、NoCodeがフロントエンドエンジニアを置き換えるとか、プログラミングが不要になるといった対立構造を生むのかと言われるとそうとも言い切れないと考えています。NoCodeによってデザインがすぐに製品になるというメリットが得られる一方で、サービス側で提供されている以上の機能を実現することはできないというデメリットも一緒に引き受ける必要がでてきます。
大切なのはNoCodeと戦うのではなく、NoCodeのもつメリットをいかに活かすかを考えることだと思います。NoCodeを使えば、手軽に早くモックが作れるのでアイディアが市場で通用するものなのか、低コストで試すことができます。以前は、市場の反応をみるために早く動くもの開発することが求められていましたが、今後はNoCodeで手っ取り早くテストが行えるようになるかもしれません。
さらにこれまでプログラミングという障壁のためにサービス開発に参入できなかった層が、市場に参入できるようになったり、本来であれば、何人ものエンジニアを雇い、何ヶ月もかけて作っていたサービスを個人が数週間でローンチできるものになったりするかもしれません。
つまり、NoCodeがサービス、アプリ開発の大衆化をもたらしてくれるという可能性もみることができます。

終わりに

フロントエンドについて学び始めてまだ4ヶ月ですが、ちょっと調べただけでも様々な技術があって、そこがフロントエンドの良さであり、悪さでもあると思いました。これまでPythonで適当なクローラーやロボットの制御プログラムを書いていた自分としては、この4ヶ月間はまさに激動の4ヶ月でした。
最初はフロントエンド技術全体を俯瞰してみるつもりで調べ始めたのですが、まんまとドツボにはまり、最近は自分でアプリを作ってみたいと思うようになりました。この出会いに関してはバイト先に感謝したいです。
まだまだフロントエンド初心者なので記事内に書かれていることが間違っていたり、語弊を生む記述になっている可能性が多々あります。よろしければ、コメント等で教えていただけると助かります。「〇〇がない!やり直し!!」等のコメントも受け付けています(笑)。


JSでDVDのロゴが動くやつ作ってみた

$
0
0

JSでDVDのロゴが動くやつを作りたくなったので作ってみました。

ezgif.com-video-to-gif.gif

デモ

dvd.pug
#container
  #box(style="width: 100px; height: 100px; background: red;") DVD
button#play-button 再生
dvd.scss
*{box-sizing:border-box;}body{margin:0;}#container{width:500px;height:500px;background-color:black;#box{font-size:44px;transition:transform1slinear0s;}}
dvd.ts
// 色の文字列を格納した配列constcolors=['red','blue','yellow','green'];// 現在位置の方向enumDirection{Top,Right,Bottom,Left}// boxのHTML要素constbox=document.getElementById("box");// boxのwidth(数値)constboxWidth:number=Number(box.style.width.replace('px',''));// containerのHTML要素constcontainer=document.getElementById("container");// HTML要素の現在位置を取得するfunctiongetCurrentPosition(element:HTMLElement){return{top:element.getBoundingClientRect().top,right:element.getBoundingClientRect().right,bottom:element.getBoundingClientRect().bottom,left:element.getBoundingClientRect().left};}// boxの初期位置constboxInitialPosition=getCurrentPosition(box);// containerの位置constcontainerPosition=getCurrentPosition(container);// boxの現在位置letboxCurrentPosition=boxInitialPosition;// boxの左上の頂点が移動できるx座標の最小値constminimumX=containerPosition.left;// x座標の最大値constmaximumX=containerPosition.right-boxWidth;// y座標の最小値constminimumY=containerPosition.top;// y座標の最大値constmaximumY=containerPosition.bottom-boxWidth;// x座標の可動域(range of motion)の距離constromX=maximumX-minimumX;// y座標の可動域の長さconstromY=maximumY-minimumY;// boxを指定した絶対位置に移動させるfunctionchangeTranslate(x:number,y:number):void{box.style.transform=`translate(${x-boxInitialPosition.left}px, ${y-boxInitialPosition.top}px)`;}// boxを現在位置から指定した距離だけ移動させるfunctionchangeTranslateFromCurrent(x:number,y:number):void{box.style.transform=`translate(${getCurrentPosition(box).left+x-boxInitialPosition.left}px, ${getCurrentPosition(box).top+y-boxInitialPosition.top}px)`;}// 配列の要素をランダムに取り出すfunctiongetRandomFromArr<Textendsany[],Kextendsnumber>(arr:T):T[K]{returnarr[Math.floor(Math.random()*arr.length)];}// ピタゴラスの定理functionpythagorasTheorem(x:number,y:number){returnMath.sqrt(x**2+y**2);}// boxの移動する速さ[px/s]constboxSpeedPerSecond=200;// 再生中かletisPlaying=false;// boxに付与する、transitionendイベント用のイベントハンドラfunctiononTransitionEnd(){// boxの背景色を現在の色以外のランダムな色に変えるconstfilteredColors=colors.filter(color=>color!==box.style.backgroundColor);box.style.backgroundColor=getRandomFromArr(filteredColors);// 前回の位置constboxPrevPosition=boxCurrentPosition;// 現在位置boxCurrentPosition=getCurrentPosition(box);// 現在位置が上辺、右辺、下辺、左辺のどの方向にあるかconstdirection:Direction=(()=>{switch(boxCurrentPosition.top){caseminimumY:returnDirection.Top;casemaximumY:returnDirection.Bottom;}switch(boxCurrentPosition.left){caseminimumX:returnDirection.Left;casemaximumX:returnDirection.Right;}})();// 前回の位置と現在位置の間の、x軸方向の距離とy軸方向の距離constprevToCurrentLength={x:Math.abs(boxCurrentPosition.left-boxPrevPosition.left),y:Math.abs(boxCurrentPosition.top-boxPrevPosition.top)};// yに対するxの割合constXYrate=prevToCurrentLength.x/prevToCurrentLength.y;// 現在位置の方向によって場合分けif([Direction.Top,Direction.Bottom].includes(direction)){// 現在位置に対して向かい側に跳ね返るかconstisBounceOppositeSide=(()=>{if(boxCurrentPosition.left>boxPrevPosition.left){// 左から右に移動した場合returnboxCurrentPosition.left+romY*XYrate<maximumX;}else{// 右から左に移動した場合returnminimumX<boxCurrentPosition.left-romY*XYrate;}})();// 現在位置と次回の位置の間の、x軸方向の距離とy軸方向の距離constcurrentToNextLength=(()=>{if(isBounceOppositeSide){consty=romY;return{x:y*XYrate,y};}else{constx=boxCurrentPosition.left>boxPrevPosition.left?maximumX-boxCurrentPosition.left:boxCurrentPosition.left-minimumX;return{x,y:x/XYrate};}})();// 移動する時間を調整constcurrentToNextRLength=pythagorasTheorem(currentToNextLength.x,currentToNextLength.y);box.style.transitionDuration=`${currentToNextRLength/boxSpeedPerSecond}s`;// 計算した距離だけ移動させるchangeTranslateFromCurrent((boxCurrentPosition.left>boxPrevPosition.left?1:-1)*currentToNextLength.x,(direction===Direction.Top?1:-1)*currentToNextLength.y);}else{// 現在位置に対して向かい側に跳ね返るかconstisBounceOppositeSide=(()=>{if(boxCurrentPosition.top>boxPrevPosition.top){// 上から下に移動した場合returnboxCurrentPosition.top+romX/XYrate<maximumY;}else{// 下から上に移動した場合returnminimumY<boxCurrentPosition.top-romX/XYrate;}})();// 現在位置と次回の位置の間の、x軸方向の距離とy軸方向の距離constcurrentToNextLength=(()=>{if(isBounceOppositeSide){constx=romX;return{x,y:x/XYrate};}else{consty=boxCurrentPosition.top>boxPrevPosition.top?maximumY-boxCurrentPosition.top:boxCurrentPosition.top-minimumX;return{x:y*XYrate,y};}})();// 移動する時間を調整constcurrentToNextRLength=pythagorasTheorem(currentToNextLength.x,currentToNextLength.y);box.style.transitionDuration=`${currentToNextRLength/boxSpeedPerSecond}s`;// 計算した距離だけ移動させるchangeTranslateFromCurrent((direction===Direction.Left?1:-1)*currentToNextLength.x,(boxCurrentPosition.top>boxPrevPosition.top?1:-1)*currentToNextLength.y);}}// onTransitionEndイベントハンドラを付与box.addEventListener("transitionend",onTransitionEnd);constplayButton=document.getElementById('play-button');playButton.addEventListener("click",function(){if(!isPlaying){isPlaying=true;playButton.innerText="リセット";// onTransitionEndイベントハンドラを付与box.addEventListener("transitionend",onTransitionEnd);// x座標の最小値から最大値未満までの数字の連番が格納された配列constrandomXArr=(()=>{letarr:number[]=[];for(leti=minimumX;i<maximumX;i++){arr.push(i);}returnarr;})();// y座標の最小値から最大値未満までの数字の連番が格納された配列constrandomYArr=(()=>{letarr:number[]=[];for(leti=minimumY;i<maximumY;i++){arr.push(i);}returnarr;})();constrandom=Math.random();// 右辺に移動させるか、下辺に移動させるかをランダムに決めるif(random<0.5){// x座標の最小値から最大値までの数字をランダムに取り出すconstrandomY=getRandomFromArr(randomYArr);// 斜辺の長さを求めるconstr=pythagorasTheorem(maximumX,randomY);// 移動する時間を調整box.style.transitionDuration=`${r/boxSpeedPerSecond}s`;// 右辺のランダムな位置に移動させるchangeTranslate(maximumX,randomY);}else{// y座標の最小値から最大値までの数字をランダムに取り出すconstrandomX=getRandomFromArr(randomXArr);// 斜辺の長さを求めるconstr=pythagorasTheorem(randomX,maximumY);// 移動する時間を調整box.style.transitionDuration=`${r/boxSpeedPerSecond}s`;// 下辺のランダムな位置に移動させるchangeTranslate(randomX,maximumY);}}else{isPlaying=false;playButton.innerText="再生";// 色を赤に戻すbox.style.background='red';// onTransitionEndイベントハンドラを削除box.removeEventListener("transitionend",onTransitionEnd);// トランジションをOFFにするbox.style.transitionDuration="0s";// 左上に移動させるchangeTranslate(minimumX,minimumY);// 現在位置をリセットboxCurrentPosition=getCurrentPosition(box);}});

ずっと見てられますね笑

Webブラウザでも縦書きの美しい日本語入力を。

$
0
0

image.png

三行まとめ

  • Webでも縦書きで美しい日本語の「入力」ができるか試したかった
  • contenteditablewriting-modeで実装した
  • ついでにMarkdownで書けるようにした

実装方法

contenteditable

contenteditableとは、ページ利用者にDOMの編集を許可することができる属性です。デフォルト状態ではfalseを取ります。また、未指定の場合は親要素の値を継承するため、親要素でcontenteditableを有効にした場合は子要素の編集も併せて可能となります。

html
<divcontenteditable="true"><p>編集が可能な要素</p><pcontenteditable="false">編集が不可能な要素</p></div>

この記述だけでスタイルを保持したままテキストの編集が可能となります。

writing-mode

cssのwriting-modeとは、テキスト行(垂直あるいは平行)とテキストのフロー方向(左向きあるいは右向き)を選択する際に用いるプロパティです。デフォルト状態ではhorizontal-tb(テキスト行は左から右方向の水平、フロー方向は上から下)を取ります。今回は右上から左下へ進むように組みたかったため、vertical-rlを指定しました。

css
.vertical-text{writing-mode:vertical-rl;-webkit-writing-mode:vertical-rl;-ms-writing-mode:vertical-rl;}

これらのcontenteditablewriting-modeを指定し、最低限のスタイルを定義するだけでも、このように縦書き入力を実現することができます。とても簡単ですね。

See the Pen Vertical Editor_alpha by oreo (@oreo) on CodePen.

実装(その他)

  • テキストのスタイル
    • 以下のように指定しました。
css
.vertical-text{-webkit-writing-mode:vertical-rl;-ms-writing-mode:tb-rl;writing-mode:vertical-rl;font-size:20px;font-family:"Noto Serif JP",serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-font-feature-settings:"palt";font-feature-settings:"palt";color:#2c3e50;line-height:2em;text-indent:1em;}
  • フォント
    • 今回はGoogle FontsのNoto Serif JPにお世話になりました。
  • 入力書式
    • せっかくcontenteditableを用いて実装したという背景もあり、見出しやリストも出力すべく、Markdownへの対応を行いました。
    • 今回はリッチテキストライブラリ「ProseMirror」のVue.js向けラッパー「tiptap」にお世話になりました。

これらの工程を経て、今回の縦書きエディタの試作が完成しました。

成果物

Dec-25-2019 05-00-32.gif
https://ore0.github.io/verticalEditor/※Chrome推奨です。

おわりに

「縦書き」かつ「日本語」かつ「Web」の入力方式は非常にニッチであるが故に先行事例が非常に少ないですが、実装してみると数行程度の記述で簡単に実現できましたね。一方でカーソルキーでの操作がしづらいことや、ブラウザでは細かな文字組み対応が難しいことが課題として挙げられます。これからも引き続き調査や改良を進めながら、縦書き入力を日常的に使えるように活用方法やよりよい実装パターンを見いだせればと思います。

参考リンク

aタグの中にaタグをJSを使わずに配置したい

$
0
0

Qiita記事を見ていると「なんとなくで書かないで!HTML5を書く時に気にしてみたいタグごとのお約束 - Qiita」で、HTMLを書くときの注意点などが紹介されていました。

ただ「aタグの中にaタグ」の箇所で、JSを使う方法が紹介されていました。
これはJSは使わなくてもできます。
気になったので書いてみました。

まず、aタグの中にaタグはどういう状況か?

例えば、カード全体がクリッカブルエリアになっており、子の要素にもリンクが必要な時です。
HTMLで表現するなら、下記の状態。

しかしHTMLの仕様上、aタグの中にaタグは含められません。
仕様を無視していれても、動作しません。

<ahref=""class="card"><divclass="card-inner"><h1class="card-title">Title Text</h1><ulclass="card-tags"><li><ahref="">tag name</a></li><li><ahref="">tag name</a></li></ul><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nam, dolorum. Facilis assumenda, itaque tempore iste minus, delectus</p></div></a>

画像でみてみましょう。

custom – 1@2x.png

右の赤いエリアの中に、緑のエリアを配置したいのです。
そう、やりたいことの本質は「aタグの中にaタグを配置する」ことではなく、
「クリッカブルエリアの中にクリッカブルエリアを配置したい」です。

対応方法

クリッカブルエリアの中にクリッカブルエリア配置したいのであれば、HTMLをaタグでカードを全体を囲むのをやめます。
見出しなどを囲むのがいいでしょう。

<divclass="card"><divclass="card-inner"><!-- aタグをここに移動 --><h1class="card-title"><ahref="">Title Text</a></h1><ulclass="card-tags"><li><ahref="">tag name</a></li><li><ahref="">tag name</a></li></ul><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nam, dolorum. Facilis assumenda, itaque tempore iste minus, delectus</p></div></div>

次は、CSSです。
クリッカブルエリアを広げたい領域の .cardと子のクリッカブルエリアになる .card-tags aposition: relative;宣言を指定します。
ただ子のクリッカブルエリアになるaタグに positionプロパティを指定しても、反映されないのでボックスの整形モデルを変更しておきましょう。

.card,.card-tagsa{position:relative;}.card-tagsa{display:inline-block;}

今度は .card-title aを親のクリッカブルエリアまで広げてみましょう。
これは擬似要素を使用します。

.card-titlea:before{content:'';position:absolute;top:0;right:0;bottom:0;left:0;}

これで完成です。
完成したコード - CodePen

このやり方を魔法のように感じる方もいらっしゃると思いますが、CSSの位置決めスキームを利用した方法です。
positionプロパティとスタックコンテキストがわかれば、理解しやすくなるでしょう。

Laravel で Christmas Illumination

$
0
0

Laravel で Christmas Illumination

こんにちは!アドベントカレンダー最終日ですが, #2 のほうが空いてたので急遽一発ネタをぶち込むことにしました!!!

発想(アホ)

Laravel といえば Illuminateだよね?
クリスマスといえばイルミネーションだよね?

Laravel でイルミネーションをやろう(意味不明)

完成品

Dec-25-2019 10-41-51.gif

https://jsfiddle.net/e2Lk9zwt/

やり方

1. Laravel をインストール

user@host: ~$ laravel new illumination
user@host: ~$cd illumination

2. パッケージ名を取得して welcome.blade.phpに渡す

routes/web.php
diff --git a/routes/web.php b/routes/web.php
index 810aa34..80e8787 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -12,5 +12,10 @@
 */

 Route::get('/', function () {
-    return view('welcome');
+    $packages = [];
+    foreach (glob(base_path('vendor/laravel/framework/src/Illuminate/*/composer.json')) as $manifest) {
+        $manifest = json_decode(file_get_contents($manifest));
+        $packages[] = $manifest->name;
+    }
+    return view('welcome', compact('packages'));
 });

3. Google 先生から CSS 職人の一発芸をもらう

image.png

image.png

4. いい感じに移植

resources/sass/app.scss
diff --git a/resources/sass/app.scss b/resources/sass/app.scss
index 8337712..959e48a 100644
--- a/resources/sass/app.scss
+++ b/resources/sass/app.scss
@@ -1 +1,101 @@-//
+$globe-width:   12px;
+$globe-height:  28px;
+$globe-spacing: 40px;
+$globe-spread:  3px;
+$light-off-opacity: 0.4;
+
+body {
+    background: #000;
+}
+.lightrope {
+    text-align: center;
+    white-space: nowrap;
+    overflow: hidden;
+    position: absolute;
+    z-index: 1;
+    margin: -15px 0 0 0;
+    padding: 0;
+    pointer-events: none;
+    width: 100%;
+    li {
+        position: relative;
+        animation-fill-mode: both;
+        animation-iteration-count:infinite;
+        list-style: none;
+        margin: 0;
+        padding: 0;
+        display: block;
+        width: $globe-width;
+        height: $globe-height;
+        border-radius: 50%;
+        margin: $globe-spacing/2;
+        display: inline-block;
+        background: rgba(0,247,165,1);
+        box-shadow: 0px $globe-height/6 $globe-width*2 $globe-spread rgba(0,247,165,1);
+        animation-name: flash-1;
+        animation-duration: 2s;
+        &:nth-child(2n+1) {
+            background: rgba(0,255,255,1);
+            box-shadow: 0px $globe-height/6 $globe-width*2 $globe-spread rgba(0,255,255,0.5);
+            animation-name: flash-2;
+            animation-duration: 0.4s;
+        }
+        &:nth-child(4n+2) {
+            background: rgba(247,0,148,1);
+            box-shadow: 0px $globe-height/6 $globe-width*2 $globe-spread rgba(247,0,148,1);
+            animation-name: flash-3;
+            animation-duration: 1.1s;
+        }
+        &:nth-child(odd) {
+            animation-duration: 1.8s;
+        }
+        &:nth-child(3n+1) {
+            animation-duration: 1.4s;
+        }
+        &:before {
+            content: "";
+            position: absolute;
+            background: #222;
+            width: ($globe-width - 2);
+            height: $globe-height/3;
+            border-radius: 3px;
+            top: (0 - ($globe-height/6));
+            left: 1px;
+        }
+        &:after {
+            content: "";
+            top: (0 - $globe-height/2);
+            left: $globe-width - 3;
+            position: absolute;
+            width: $globe-spacing + 12;
+            height: ($globe-height/3 * 2);
+            border-bottom: solid #222 2px;
+            border-radius: 50%;
+        }
+        &:last-child:after {
+            content: none;
+        }
+        &:first-child {
+            margin-left: -$globe-spacing;
+        }
+    }
+}
+
+@keyframes flash-1 {
+    0%, 100% { background: rgba(0,247,165,1);
+        box-shadow: 0px $globe-height/6 $globe-width*2 $globe-spread rgba(0,247,165,1);}
+    50% { background: rgba(0,247,165,$light-off-opacity);
+        box-shadow: 0px $globe-height/6 $globe-width*2 $globe-spread rgba(0,247,165,0.2);}
+}
+@keyframes flash-2 {
+    0%, 100% { background: rgba(0,255,255,1);
+        box-shadow: 0px $globe-height/6 $globe-width*2 $globe-spread rgba(0,255,255,1);}
+    50% { background: rgba(0,255,255,$light-off-opacity);
+        box-shadow: 0px $globe-height/6 $globe-width*2 $globe-spread rgba(0,255,255,0.2);}
+}
+@keyframes flash-3 {
+    0%, 100% { background: rgba(247,0,148,1);
+        box-shadow: 0px $globe-height/6 $globe-width*2 $globe-spread rgba(247,0,148,1);}
+    50% { background: rgba(247,0,148,$light-off-opacity);
+        box-shadow: 0px $globe-height/6 $globe-width*2 $globe-spread rgba(247,0,148,0.2);}
+}
resources/views/welcome.blade.php
diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php
index 3fb48cc..66ad194 100644
--- a/resources/views/welcome.blade.php
+++ b/resources/views/welcome.blade.php
@@ -8,93 +8,83 @@<!-- Fonts -->
         <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
+        <link href="{{ mix('/css/app.css') }}" rel="stylesheet">
<!-- Styles -->
         <style>
-            html, body {
-                background-color: #fff;
-                color: #636b6f;
-                font-family: 'Nunito', sans-serif;
-                font-weight: 200;
-                height: 100vh;
-                margin: 0;
+            .fadeIn1 {
+                display: none;
+                color: rgba(0,247,165,1);
+                animation-name: fadeIn-1;
+                animation-duration: 2s;
             }
-
-            .full-height {
-                height: 100vh;
-            }
-
-            .flex-center {
-                align-items: center;
-                display: flex;
-                justify-content: center;
+            .fadeIn2 {
+                display: none;
+                color: rgba(0,255,255,1);
+                animation-name: fadeIn-2;
+                animation-duration: 0.4s;
             }
-
-            .position-ref {
-                position: relative;
+            .fadeIn3 {
+                display: none;
+                color: rgba(0,255,255,1);
+                animation-name: fadeIn-3;
+                animation-duration: 1.1s;
             }
-
-            .top-right {
-                position: absolute;
-                right: 10px;
-                top: 18px;
+            @keyframes fadeIn-1 {
+                0%, 100% { color: rgba(0,247,165,1); }
+                50% { color: rgba(0,247,165,0.4); }
             }
-
-            .content {
-                text-align: center;
+            @keyframes fadeIn-2 {
+                0%, 100% { color: rgba(0,255,255,1);}
+                50% { color: rgba(0,255,255,0.4);}
             }
-
-            .title {
-                font-size: 84px;
-            }
-
-            .links > a {
-                color: #636b6f;
-                padding: 0 25px;
-                font-size: 13px;
-                font-weight: 600;
-                letter-spacing: .1rem;
-                text-decoration: none;
-                text-transform: uppercase;
-            }
-
-            .m-b-md {
-                margin-bottom: 30px;
+            @keyframes fadeIn-3 {
+                0%, 100% { color: rgba(247,0,148,1);}
+                50% { color: rgba(247,0,148,0.4);}
             }
         </style>
     </head>
     <body>
-        <div class="flex-center position-ref full-height">
-            @if (Route::has('login'))
-                <div class="top-right links">
-                    @auth
-                        <a href="{{ url('/home') }}">Home</a>
-                    @else
-                        <a href="{{ route('login') }}">Login</a>
+        <ul class="lightrope">
+            @for ($i = 0; $i < 42; ++$i)
+                <li></li>
+            @endfor
+        </ul>
+        @for ($i = 0; $i < 6; ++$i)
+            <div class="fadeIn fadeIn{{ ($i % 3) + 1 }}"></div>
+        @endfor
+        <script
+            src="https://code.jquery.com/jquery-3.4.1.min.js"
+            integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
+            crossorigin="anonymous"></script>
+        <script>
+            var packages = {!! json_encode($packages, JSON_UNESCAPED_SLASHES) !!};

-                        @if (Route::has('register'))
-                            <a href="{{ route('register') }}">Register</a>
-                        @endif
-                    @endauth
-                </div>
-            @endif
+            (function fadeInDiv(){
+                var divs = $('.fadeIn');
+                var divsize = ((Math.random()*100) + 50).toFixed();
+                var posx = (Math.random() * ($(document).width() - divsize)).toFixed();
+                var posy = (Math.random() * ($(document).height() - divsize)).toFixed();
+                var maxSize = 60;
+                var minSize = 15;
+                var size = (Math.random()*maxSize+minSize)

-            <div class="content">
-                <div class="title m-b-md">
-                    Laravel
-                </div>
+                var elem = divs.eq(Math.floor(Math.random()*divs.length));

-                <div class="links">
-                    <a href="https://laravel.com/docs">Docs</a>
-                    <a href="https://laracasts.com">Laracasts</a>
-                    <a href="https://laravel-news.com">News</a>
-                    <a href="https://blog.laravel.com">Blog</a>
-                    <a href="https://nova.laravel.com">Nova</a>
-                    <a href="https://forge.laravel.com">Forge</a>
-                    <a href="https://vapor.laravel.com">Vapor</a>
-                    <a href="https://github.com/laravel/laravel">GitHub</a>
-                </div>
-            </div>
-        </div>
+                if (!elem.is(':visible')){
+                    elem.fadeIn(Math.floor(Math.random()*1000),fadeInDiv);
+                    elem.css({
+                        'position':'absolute',
+                        'left':posx+'px',
+                        'top':posy+'px',
+                        'font-size': size+'px'
+                    });
+                    var pkg = packages[Math.floor(Math.random() * packages.length)];
+                    elem.text(pkg);
+                } else {
+                    elem.fadeOut(Math.floor(Math.random()*1000),fadeInDiv);
+                }
+            })();
+        </script>
</body>
 </html>

jQuery 使ってますけど何か問題でも??????????

5. ビルド

user@host: ~/illumination$ npm installuser@host: ~/illumination$ npm run dev

6. 完成!!!

image.png

WebとReact NativeのCSSの違いについて

$
0
0

この記事は CSS Advent Calendar 2019 24日目の記事です。

8月からアプリエンジニアとしてReact Nativeを触っているのですが、WebのCSSと比べて違う部分があったので記事にしようと思いました。

fixedが存在しない

個人的に、初めてReact Nativeをいじっていて衝撃的でした。
Webではある要素を固定したい場合、position: fixedを使うのが普通ですが、React Nativeではpositionで用意されているプロパティ値はrelativeabsoluteしかありません。

https://facebook.github.io/react-native/docs/layout-props#position

ではどうすれば要素を固定できるのかというと、
ScrollViewというものを使います。

コードは以下のような感じです。

<><Viewstyle={{position:'absolute',top:300,width:100,height:100,backgroundColor:'#FF0000'}}><Text>fixed</Text>
</View>
<ScrollView><Viewstyle={[styles.container,{justifyContent:'center'}]}><Text>hoge</Text>
<Text>hoge</Text>
<Text>hoge</Text>
<Text>hoge</Text>
<Text>hoge</Text>
</View>
</ScrollView>
</>
conststyles=StyleSheet.create({container:{flex:1,justifyContent:'center',alignItems:'center',}})

固定したい要素はScrollViewに含ませないようにしてあげます。
そうすることで、Fixedの要素はスクロールの対象外となるので固定されるようになります。

output.gif

このような感じになります。

margin/padding

例えばWebだと上下左右にmarginを20pxずつ開けたい場合は

.hoge:{margin:20px;padding:20px;}

と書いてあげれば上下左右にそれぞれ20pxずつmarginが指定されます。

React Nativeだと

.hoge:{marginTop:20px,marginRight:20px,marginBottom:20px,marginLeft:20px,paddingTop:20px,paddingRight:20px,paddingBottom:20px,paddingLeft:20px,}

という書き方になり、それぞれの方向にmarginを指定してあげないといけません。
ちょっと冗長ですがReact Nativeだとこのような書き方になります。

boxShadow

例えば
- 水平方向の影のオフセット距離 10px
- 垂直方向の影のオフセット距離 10px
- ぼかし距離 10px
- 広がり距離 10px
- 影の色 #000
- opacity 0.4
という指定のbox shadowを指定したい場合はWebだと

.hoge:{box-shadow:10px10px10px10pxrgba(0,0,0,0.4);}

のような書き方になるかと思います。

React Nativeだと

.hoge:{shadowColor:'#000',shadowRadius:10,shadowOpacity:0.6,shadowOffset:{width:10,height:10}width:100,height:100,backgroundColor:'#00ffff',}

となります。

shadowColorはWebのbox shadowでいう影の指定になります。
shadowOffsetはWebのbox shadowでいう水平方向の影のオフセット距離と垂直方向の影のオフセット距離の指定になります。
shadowRadiusはWebのbox shadowでいうぼかし距離になります。

広がり距離に関してはshadowのドキュメントみても見当たらなかったのでないのかも?

https://facebook.github.io/react-native/docs/shadow-props#__docusaurus

上記で書いたコードの出力は以下のような感じです。

スクリーンショット 2019-12-25 11.24.16.png

ちゃんと影がついてますね。

プロパティはコンマ区切り

cssの場合はプロパティの末尾にセミコロンをつけてプロパティを区切るのが一般的ですが、React Nativeですと基本コンマで区切ります。

基本の記述方法はキャメルケース

Webだと例えば、背景の色を変えたい場合はbackground-colorを使いますが、React Nativeだとケバブケースは使えません。
React NativeだとbackgroundColorと記述します。
基本的にはキャメルケースでの記述になってます。

まとめ

普段Webに慣れていた分、React Nativeでcssを初めて書いたときはすごい違和感がありました。
とくに要素の固定に関しては最初ちょっと使いづらかったですw

React Nativeはまだまだ発展途上のモバイルアプリケーションフレームワークですが、普段Webに慣れている方なら敷居はかなり低いと思いますので、興味ある方は是非触ってみてください。

実例で学ぶCSSアニメーション(vue)【第70回駒場祭公式ウェブサイトでの例】

$
0
0

第70回駒場祭公式ウェブサイト
こちらのサイトの、

  • お気に入りスター
  • ローディング画面

のCSSアニメーションをどう実装したかについて書きます。Qiitaで「CSSアニメーション」で検索したら1787件ヒットしてしまって「これどれくらいの人に役に立つのかな、、?」とびくびくしていますが、実例をコードと一緒に見ることのできる機会はいくらあっても(様々なレベルでの実装があるので)初学者にとっては参考になるかもなあと思い投稿いたした次第です。

お気に入りスター

星に名前はついてなかったので「お気に入りスター」という名称は僕が今ここで呼んでいるだけなのですが、企画の情報が載っているこいつの右下の星です。企画あるいはグッズの情報が載っているページ/コンポーネントすべてについています。ぽちぽちしてると楽しい。
無題.png
ブラウザが重かったりするとまわりのタピオカみたいなやつ点々が見えないかもしれません。

星のvueファイルにおけるhtml部分はこんな感じです。

Star.vue
<templatelang="pug">
.star
    svg(:class="starOn?'s-colored':'s-uncolored'" @click.prevent.stop="favorite" 以後省略)
        polygon(:fill="starOn? '#F5CE2F': '#CFD0D0'" points="省略")
    .particle(v-for="i in 10" :key="`particle${i}`" :id="starOn?`particle${i}`:''" :style="`background: ${particleColor[i-1]}`")
</template>

script部分はこんな感じです(要らないものは消しています)(localStorage部分が気になる方はこちらへ)

Star.vue
<script>exportdefault{methods:{favorite(){//localStorageを見てお気に入り登録がすでにされていたらstarOnをfalse、されていなかったらtrueにするコード}},data(){return{starOn:false,particleColor:['#f54e42','#42daf5','#f5d142','#42f596','#4242f5','#f59642','#9c42f5','#f5f542','#f542c2','#42adf5']}},}</script>

それでクリックしたときに星が大きくなるcssがこちら

Star.vue
@keyframesanim{from{transform:scale(0);}70%{transform:scale(1.3);}to{transform:scale(1);}}.s-colored{animation:anim0.3sease;}
Star.vue
@for$ifrom1through20{#particle#{$i}{opacity:1;animation:particleanim#{$i}0.3seaseforwards;}}@keyframesparticleanim1{from{transform:translate(0px,0px);opacity:1;}70%{transform:translate(0.98px*15,0.17px*15);opacity:1;}to{transform:translate(0.98px*15,0.17px*15);opacity:0;}}//particleanim2以降も同様のノリ。

まあつまり、星をクリックすると変数starOnが状況に合わせてtrueになったりfalseになったりして、それにあわせて星であるsvgにクラスが付与されたり点々であるdivにidが付与されたりした結果animationが始まる、という仕組みになっています。
keyframeのparticleanimですが、点々は36度(360°/10)ずつずれて飛んでいってほしいので、飛んでいく方向の角度を36度ずつずらしてそれぞれのx方向の変位、y方向の変位を計算して全部書くってことをやっていました。そのうちsin()とか使えるようになるみたいですね。楽しみです...!

ちなみにお察しかと思いますが点々である.particleはsvgではなくdivなのでcssはこんな感じです。ふつうにsvgのcircleタグを使えばよかったと思うのでアンチパターンですね。

Star.vue
.particle{width:1.6px;height:1.6px;border-radius:0.8px;position:absolute;top:/*省略*/;left:/*省略*/;z-index:-1;}

ローディング画面

次はこちら。他のサイトから遷移してきたときや再読み込み時に起動するこれです。
image.png
正直あまり書くことは無く、けっこうかんたんにできます。これコストパフォーマンスがいい、みたいな話になったりもしました。
このコンポーネントでは、(せっかくvueだし)親のタグとしてtransitionを設定しています。そして、子要素としてv-ifを設定しているdivを置き、その中にロゴタイプと七角形のsvgを置いています。

Star.vue
<templatelang="pug">
    transition(name="loading")
      .loading-anim(v-if="whethershow")
        img.logotype(src="略" alt="")
        svg.hepta(以後省略)
</template>

cssを使って、これらロゴタイプと七角形にposition: absoluteを設定してtop, left, transform:translate()またはdispay: flexを使って中央にそろえます。
そして、双方に一定周期で点滅するようなkeyframeを適用、七角形にだけ回転するkeyframeを適用します。

LoadingAnimation.vue
@keyframesanim1{0%{opacity:0;}100%{opacity:0.8;}}@keyframesanim2{0%{transform:translate(-50%,-50%)rotate(0deg);//translateの値も書いておかないと中央揃えが維持されない}100%{transform:translate(-50%,-50%)rotate(51.4286deg);//360/7}}.logotype{//略animation:anim10.9seaseinfinitealternateforwards;}.hepta{//略animation:anim21.8seaseinfinite,anim10.9seaseinfinitealternateforwards;}

transitionタグ(?)で囲っているのでコンポーネント自体のトランジションは以下のcssで設定します。

LoadingAnimation.vue
.loading-enter,.loading-leave-to{opacity:0;}.loading-enter-to,.loading-leave{opacity:1;}.loading-enter-active,.loading-leave-active{transition:opacity1sease-in-out;}

これで見た目はほぼ完了で、あとはページが読み込みおわるまで表示して読み込み終わったときに消す仕組みの作成ですが、vueさんはmountedというものを提供してくれているのでかんたん、

LoadingAnimation.vue
<script>exportdefault{data(){return{whethershow:true};},methods:{func(){this.whethershow=false}},mounted:function(){setTimeout(this.func,1000)}};</script>

これを書いてこのコンポーネントをlayout/default.vueに貼り付ければ、サイト全体がmountされた一秒後までこのコンポーネントが表示されて、消えていくということになります。ここはvueのものすごく便利なところだと思います。

おしまい!

CSSの複数のセレクター選択の話

$
0
0

CSSで複数クラスを指定してスタイルを適用する

HTMLで例えば "class1" と "class2" というクラスがあって、そのどちらにも同じスタイルを適用したい場合ってありますよね。(まぁ同じクラスにまとめちゃえばいいんじゃんって時もあるんですけど、それは置いといて笑)

そんな時は、CSSで複数のクラスを指定しましょう。

CSSで複数のクラスを選択

例えば、h1とpに同じスタイルを適用したい時。

2つのクラスの間にあるのは、、、"カンマ"です!!

stylesheet.css
h1,p{color:red;}

CSSで親要素の中の子クラスを選択

例えば、上で既にh1には "color: red;" が適用されていますよね。
でも、class = "bottom-container" のdivの中のh1だけは、h1を白にしたい!そんな時はどうするか。

2つのクラスの間にあるのは、、、"スペース"です!!
(※親要素と子要素の関係でのみ成立するため注意。)

stylesheet.css
h1,p{color:red;}.bottom-containerh1{color:white;}

ある1つのHTMLタグで複数CSSクラスを持つ要素を選択

これは複数のクラスを持つタグのみに特定のスタイルを適用する時。

例えば、class1で文字色RED、class2で文字色BLUEになっているけど、

のように両クラスを持つタグだけは違うスタイルを適用したい。って時はこれを使います。

2つのクラスの間にあるのは、、、"無"です!!
何もなく、そのまま2つ目のクラスを指定します。

stylesheet.css
.class1.class2{color:green;}

Codeplyでやってみると、こんな感じ。

スクリーンショット 2019-12-25 11.54.14.png


jQueryで擬似要素(::before,::afterなど)に変化を加える(風)!!

$
0
0

概要

jQueryで「擬似要素に変化を加えるのってどうやるんだろう」、「そもそも擬似要素って要素として取得できるのかな〜」と少々苦戦したため、備忘録として残します。
世間はクリスマスですが、Qiita2投稿目にトライしてみるので、温かい目で見てくださると嬉しいです:relaxed:

まずは、デモ動画をご覧下さい!!
Image from Gyazo

非常に細かい点ですが、CategoryColorの右端にがあり、イベント発火時(mouseover)、になっております。
この擬似要素::afterです。
変化が加わり、向きが変わっているように見えますが、実際は別のclassを作成し、イベントの発火に伴いclassの入れ替えをしているというものです。

::before, ::afterなどの擬似要素はDOM要素では無いため、JavaScriptで要素の取得や、変化を与えることが出来ないためです。
では、順を追ってご説明します。

※そもそも擬似要素って?という方は以下のリンクを参考にしてみてください:point_up:
https://saruwakakun.com/html-css/basic/before-after

1.Haml, CSS

left-bar.html.haml
.left-header.left-header__lists%ul.nav%li.select Category ※ここにカーソルが乗るとイベント発火
        %ul#option%li=link_toouter_items_pathdo=fa_icon"square-o"
              Outer
          %li=link_totops_items_pathdo=fa_icon"square-o"
              Tops
          %li=link_tobottoms_items_pathdo=fa_icon"square-o"
              Bottoms
          %li=link_toshoes_items_pathdo=fa_icon"square-o"
              Shoes
          %li=link_togoods_items_pathdo=fa_icon"square-o"
              Goods
left-bar.css
.left-header{width:250px;height:650px;padding:40px30px070px;position:relative;&__lists{width:120px;height:400px;}.nav{margin-bottom:30px;position:relative;cursor:pointer;}.select{color:$black;font-family:$main-font;@includeborder-line;font-size:X-large;font-weight:bold;}#option{text-decoration:none;list-style:none;font-size:large;display:none;font-family:$main-font;li{a{color:$black;font-size:21px;}.fa{color:$black;}}}} 今回のポイントはここです!!⇩.select:after{position:absolute;content:"▼";font-size:12px;right:0;bottom:1px;color:#9a8478;}.select_a:after{position:absolute;content:"▲";font-size:12px;right:0;bottom:1px;color:#9a8478;}

selectの擬似要素::afterを画像のように2種類用意しておくことがポイントです!
contenの中身だけを変更します!!

2.jQuery

以下jQueryのコードです。(jQueryが使用可能な環境になっているという前提で話を進めます。)

left-bar.js
$(function(){$(document).on("turbolinks:load",function(){varnav=$(".nav");$("li",nav).mouseover(function(e){$("ul",this).stop().slideDown("fast");varselect=$(this).children(".select")[0];$(select).toggleClass("select_a");}).mouseout(function(e){$("ul",this).stop().slideUp("fast");varselect=$(this).children(".select")[0];$(select).toggleClass("select_a");});})})

.nav%li、つまり.selectにマウスカーソルが乗った時、子要素の%ul#optionをスライドによって表示させます。

②mouseoverされた.selectのDOM要素を取得し、変数化します。
console.logで下記画像の様に取得出来ていればOKです!
Image from Gyazo

③変数化された.selectの擬似要素を.toggleClassで切り替えて実装完了です!:ok_hand:

mouseoutの時は、逆の動きをするのでslideDownslideUpを書き換えるだけでOKです!

まとめ

擬似要素には直接変化を与える事が出来ないので、classを切り替える事で変化を加える(風)に実装しました!
font-awesomeなどを用いていれば、もう少し簡単に実装出来たのかなとも思います。。。
最後まで読んで下さりありがとうございました:relaxed:

参考

https://idotdesign.net/blog/web/js/non-dom-before-after/

display:inline-blockこんな便利なものは是非とも使っていただきたい。

$
0
0

はじめに

どうも、NISHIKIです。
初めてなんで軽く自己紹介します。

僕は10月21日からテックエキスパートに通いはじめて、
12月26日に卒業します。
NISHIKIはその間に1回だけ呼ばれたあだ名です。

一通りHTML、CSS、Ruby、Javascriptなど学び終わったので、
今から学び始めるテックエキスパート生や
その他駆け出しのエンジニアになりたい人
向けに
わかるように色々書いていきます。

書いていく内容で、すでに卒業された方や、
受講途中の方でそんなん知っとるわっていう方も
いらっしゃるかと思いますので、
そういう方はトラックパッドを左にシャッとしてください。


今回は最終課題中に
「そこdisplay:inline-block;使ったらいいのになー」
って思うことがあったので


display:inline-blockの使い方について
書いていきます。
12月25日現在の67期生、68期生あたり向けです。

displayプロパティとは、たそ

HTMLを学ばれてる方なら、
要素(h1要素とかp要素)というものがあるということは
ご存知かと思いますが、


その要素の表示形式を指定する際に
使用します。


つまりは、blockにしたり、
inlineにしたり、
flexにしたりするときに使うプロパティです。
よく使うのはこの辺りかなと思います。


例えば以下のようなコードがあったとします。

index.html
<!DOCTYPE html><htmllang="ja"><head><metacharset="utf-8"><title>display</title><linkrel="stylesheet"href="styles.css"></head><body><divclass="main"><p>これは見出しです</p><p>とか言っちゃって〜</p></div></body></html>
styles.css
body{margin:0;padding:0;}.main{background-color:#333;padding:20px;margin-top:10px;}.mainp{color:#fff;margin:0;}

スクリーンショット 2019-12-25 14.49.57.png

上記のmainクラス内の
ブロック要素である
p要素をサクッと横並びにしたいな〜
ってときは、

styles.css
body{margin:0;padding:0;}.main{background-color:#333;padding:20px;margin-top:10px;}.mainp{color:#fff;margin:0;display:inline;}

上記のように
p要素のところに
display:inline;と
書くだけです。

スクリーンショット 2019-12-25 14.52.58.png

こんな感じに横並びに変わります。

これと同じようにインライン要素に
display:block;と書くと
インライン要素のなのに縦に配置できる
みたいな感じです。


そのへんはp要素をspan要素に変えたりして
試してみてください。

それで結局inline-blockいつ使うん?

それを説明するためにもうちょっとだけ
block要素とinline要素のwidthとheight
について説明します。


みなさんは、divタグ全てに
width: 100%;とつけたりしてないですか?


aタグにheight: 30px;して
高さ変わらんやんみたいな経験ないですか??


僕はあります。
わけわからずコード書いてたときは
よくやってました。笑


実は、block要素、inline要素は
デフォルトで縦幅、横幅が設定されています。


block要素はデフォルトで
widthは親要素の幅いっぱい
heightはコンテンツの高さになります。

上記の例の背景をつけると
こんな感じです。

Image from Gyazo


inline要素は
widthはコンテンツの幅
heightはコンテンツの高さになります。

Image from Gyazo

そしてblock要素は
heightとwidthの指定ができるのに対し、
inline要素はheightとwidthの指定ができません

上記の例でいくと、
p要素にheightを100px、
widthを150px指定すると、

Image from Gyazo

みたいな感じになります。
でも、p要素をインライン要素のspan要素に
変えるだけで、widthとheight設定してるのに

Image from Gyazo

になります。
span要素に変えずに、p要素のままで
display:inline;としても同じ結果です。

だから、inline-blockはいつ使うん?

お待たせしました。
inline-blockの説明からすると、
両方のいいとこ取りみたいなものです。


横並びにできつつ、縦横の
サイズが指定できるというものです。


使いどころでいうと、
こいつインライン要素やけどborderつけて
もっと縦幅伸ばしたいなってときとか


p要素を横並びさせたいなあ
ってときとかに僕は使っています。


使いどころがあってるかは
わからないです。笑


だから上の例でいくと、
p要素にdisplay:inline-block;を
書いてあげると、

Image from Gyazo

横並びのまま縦横のサイズを
指定してあげることができます。

使いどころを知ってからは
へービーユーザーですね。笑


便利なんでみなさん使ってみてください。
最後まで読んでいただきありがとうございました。

【CSS】リストのスタイル変更と位置変更、そして余白

$
0
0

list-style: none;

:sunny:リストの先頭のマークを消す

例.html
<ul><li>←ここに黒い点が表示されている</li><li>←ここに黒い点が表示されている</li><li>←ここに黒い点が表示されている</li></ul>

Web

スクリーンショット 2019-12-25 15.34.12.png

この黒い点を消すために・・・

例.css
li{list-style:none;}

このCSSを適用させると・・・

スクリーンショット 2019-12-25 15.51.10.png

なくなりました!:laughing:

float

:sunny:指定した要素を横並びにする
:sunny:値を left にした場合は左寄せ、 right にしたら右寄せ

例.html
<ul><li>りんご</li><li>みかん</li><li>メロン</li></ul>

Web

スクリーンショット 2019-12-25 15.59.50.png

通常であれば、このように縦に並んでしまいます。
これを横並びにしたい!・・・というときに float プロパティを使うと・・・

例.css
li{float:left;}

Web

スクリーンショット 2019-12-25 16.05.32.png

横並びにはなったけど黒い点が邪魔・・・:sweat:
さきほどの list-style: none; を付け加えると・・・

例.css
li{float:left;list-style:none;}

Web

スクリーンショット 2019-12-25 16.08.10.png

消えました!:laughing:
でも りんごみかんメロン って文字がぎゅうぎゅうで見にくいな・・・:thinking:
余白を取るにはどうしたらいいのだろう。

余白(paddingとmargin)

:sunny: padding はブロック内側に余白をとる
:sunny: margin はブロック外側に余白をとる

どういうことかというと・・・

スクリーンショット 2019-12-25 17.10.03.png

まだなにも余白をとっていないときはこのようになります。
この赤と青のあいだに余白を入れたいときには margin プロパティを使用します。

margin-bottom: 100px;

スクリーンショット 2019-12-25 17.18.48.png

余白がとれました!:smile:
そして padding はどうなるのかというと・・・

スクリーンショット 2019-12-25 17.23.00.png

こうなります。
書き方がいろいろあるのでまとめます。

書き方 説明
margin-top: 10px;ブロック上に外側10pxの余白をとる
margin-bottom: 10px;ブロック下に外側10pxの余白をとる
margin-left: 10px;ブロック左に外側10pxの余白をとる
margin-right: 10px;ブロック右に外側10pxの余白をとる
書き方 説明
padding-top: 10px;ブロック上に内側10pxの余白をとる
padding-bottom: 10px;ブロック下に内側10pxの余白をとる
padding-left: 10px;ブロック左に内側10pxの余白をとる
padding-right: 10px;ブロック右に内側10pxの余白をとる

他にも書き方があって、複数の余白をとりたいときは下記のほうが便利です!

書き方 説明
margin: 10px;ブロックの外側、上下左右に10pxの余白をとる
margin: 10px 20px;ブロックの外側、上下に10px,左右に20pxの余白をとる
margin: 10px 20px 30px;ブロックの外側、上に10px,左右に20px,下に30pxの余白をとる
margin: 10px 20px 30px 40px;ブロックの外側、上に10px,右に20px,下に30px,左に40pxの余白をとる
書き方 説明
padding: 10px;ブロックの内側、上下左右に10pxの余白をとる
padding: 10px 20px;ブロックの内側、上下に10px,左右に20pxの余白をとる
padding: 10px 20px 30px;ブロックの内側、上に10px,左右に20px,下に30pxの余白をとる
padding: 10px 20px 30px 40px;ブロックの内側、上に10px,右に20px,下に30px,左に40pxの余白をとる

これを利用してさきほど見づらかった りんごみかんメロン を変更してみます

例.css
li{float:left;list-style:none;margin-right:20px;}

4行目に margin-right: 20px; を追加してみました。

Web

スクリーンショット 2019-12-25 18.20.38.png

りんご みかん メロン となり見やすくなりました:raised_hands:

10時間で、Webサイトをどこまで作れるかやってみた

$
0
0

ご挨拶

こんにちは。
私は、バカンのセールスメンバーのひとりです。

バカン Advent Calendar 2019の23日目の投稿としてこの記事を書いているのですが、
今回、私が書く記事は、「10時間で、Webサイトをどこまで作れるかやってみた」です。

世の中には、「10,000時間の法則」なるものがあるらしいのですが、ご存知でしょうか。
ある分野を極めた複数の「達人」を分析したところ、「達人」たちがその分野に投下した時間は、10,000時間だったとのこと。つまり。ある物事を極めるには、10,000時間をそれに費やす必要があるのだ、ということです。とインターネットが言ってました。
そこで私は、「10時間では、どこまで行けるだろうか?」というチャレンジをすることにしました。チャレンジ内容は、Webサイトの作成です。
なぜ、ド素人がWebサイト作成に挑戦しようと思ったのか?

現在、バカンのセールスは各々の案件を持っており、課題解決のためにお客様と対話しながら、サービス導入までのマネジメントまで行います。
サービスの導入にあたって、デザイナーやエンジニアに仕事をお願いするのですが、技術やデザインのことを知っておいた方が、やはりマネジメントのためになります。そういうわけで、Webサイト作成にチャレンジしてみようと思ったのです。
それでは、私の挑戦をご覧ください。

ワイヤー作成&全体の実行スケジュール作成

まずはワイヤー作成。どんなWebサイトを作成するのかを決めました。
時間がないので、構成だけ(ワイヤーとは呼べないシロモノ…)仕上げました。

スクリーンショット 2019-12-25 19.30.36.png

できた。
ちなみにサイトのテーマは、チュニジアの紹介です。これをチョイスしたのは、今冬、チュニジア出身のエンジニアがバカンにジョインしてくれたからです。メンバーの出身地、紹介したい!!
ちなみにこちら、HTMLとCSSだけで構成されています。「10時間でド素人が」なので、JavaScriptまで書くような余地はなさそうです。

ここまでで30分使ったので、実行スケジュールはこんな感じ。
⓪ワイヤーの作成:0.5時間
①HTMLとCSSの書き方を勉強:1.5時間
②HTMLの作成:2時間
③CSSの作成(HTMLを手直ししながら):6時間

それではやっていきます。

HTMLとCSSの書き方を勉強

まずは、HTMLの書き方を勉強です。適当に文字や画像を入れてみる。
なるほど、ふむふむ、文字を入れたり画像を載せたりできるのか。HTML上での文字の入れ方、画像の載せ方にも色々あるらしい。(すでにこの時点で、画像は正しく表示されていませんが…)

スクリーンショット 2019-12-21 14.57.12.png

Webサイトが形作られていくのは、なかなか面白い!
(このとき、コーディングは時間のかかる作業だということも痛感しました)

CSSの書き方も勉強。
文字の色、大きさ、位置など、見た目を自由に設定できるのですね。とても面白いです!

ここまでで2.5時間経過。30分オーバーしてますね。
しかし、焦ることなく、一方で自分のボルテージは上がっていく。

ワイヤー修正

ここで、欲が出ました。まだ何も成していないのに。
「このワイヤー、作り込もう」と。

スクリーンショット 2019-12-25 19.40.54.png

色々なWebサイトを参考に、最終的にこんなワイヤーにすることにしました。サイトの内容まで考えきれていないですが、それでも成果物イメージが洗練されてくると、やる気が上がりますね。
ここで30分使ったので、3時間経過しています。

HTML作成

HTML作成に入る。まずは簡単に作ってみる。

スクリーンショット 2019-12-21 15.15.17.png
スクリーンショット 2019-12-21 15.24.17.png

できた。ここまで4時間。
書けるものを書いた(しかもテキストはまだ適当)
という感じではあるものの、スケジュールの遅れを取り戻しました。
ここからHTMLを手直ししつつ、CSSを書いていきます。(適当だったテキストも当然書き直す)

CSS作成

CSSは、ページの色を変えたり、変更したりできるので、作業が楽しいです。背景や文字色を変えると、こんな感じに。

スクリーンショット 2019-12-21 17.44.10.png

ここで、画像が正しく表示されなかったので、HTMLに戻って修正。無事表示されるようになりました!ついでに画像の配置も整えようと頑張る。

スクリーンショット 2019-12-22 19.56.05.png

ワイヤーのように画像の中に白い枠を乗せることはできました。
次は、画像の右下に白い枠を移動させる作業です。
うーん…?難しい。
これはどうすればいいんだろう…?
とりあえず、こうかな!?

スクリーンショット 2019-12-25 19.55.45.png

爆死。
アイキャッチの画像もドアップになるし、今まで作っていた画像の配置も消え失せた…

実はここで10時間経過。タイムアップです。やはり、時間が全然足りませんでしたね…
Webサイトの制作は今後も少しずつ進めるとして、今回のチャレンジの振り返り。

結果&振り返り

結果、10時間ではWebサイトを完成させることができませんでした!無念!!
やはり10時間でゼロからWebサイトを作ってみる、というのは難しかったみたいです…

ただ、学んだこともたくさんあります。
コーディングの反省点はたくさんありますが、
そのひとつは、HTMLの書き方を工夫しなくてはいけなかった点だと思います。
HTMLでリストを作れば、もしくはDivの括り方を変えれば、爆死せずに済んだのでは?望み通りのものができたのでは?と思います。

普段の仕事に活かせる学びもたくさんあります。
そのひとつは、エンジニアの無駄な修正作業を予防するマインドが強まったことです。
エンジニアの修正作業は、本来すごく時間と手間のかかることなのだと痛感しました。
(バカンのエンジニアは超速でプロダクトを作り上げていきますが…)
何を、いつ、どう頼むべきか、今まで以上に気にかけていこうと思います。

最後に

バカンでは、「世の中の混雑をなくし、優しい世界を作り上げたい」というメンバーが働いています。
一緒に働くメンバーを募集していますので、ご興味ある方は、ぜひ下記HPをご覧ください!
株式会社バカン:https://www.vacancorp.com/

年賀状の宛名の作成と印刷をブラウザでやってみる

$
0
0

ゴール

↓これをHTMLとCSSで作ってブラウザから印刷するかPDFで保存。
img01.png

動機

  • 年賀状の季節
  • 住所データが特定のツール(例えばエクセル)でしか開けないのが嫌になってきた
  • Macで宛名印刷するツールが少ない
  • CSSの縦書きがW3Cの勧告になったとのこと(CSS Writing ModesがW3C勧告に

初めての縦書き

がんばりました。
自分用なのでChromeだけで動けばいいです。

sampel.html
<!DOCTYPE html><htmllang="ja"><head><title>宛名印刷</title><style>@page{size:100mm558px;/* 148mmだと若干ずれたのでpxで指定 */margin:0;padding:0;}@mediascreen{.page{background-image:url(nenga.png);}}body{width:100mm;margin:0;padding:0;font-family:serif;}.page{width:100mm;height:558px;/* 148mmだと若干ずれたのでpxで指定 */margin:0;padding:0;position:relative;page-break-after:always;}#to-name{position:absolute;top:28mm;right:35mm;/* ずれたら適宜変更 */height:93mm;font-size:24pt;line-height:1.2em;writing-mode:vertical-rl;text-orientation:upright;display:flex;margin:0;padding:0;}#to-name>div{position:relative;}#to-postcode3{position:absolute;top:12.8mm;left:45.5mm;/* ずれたら適宜変更 */margin:0;padding:0;font-size:14pt;letter-spacing:4.2mm;font-family:serif;}#to-postcode4{position:absolute;top:12.8mm;left:67.0mm;/* ずれたら適宜変更 */margin:0;padding:0;font-size:14pt;letter-spacing:4.1mm;font-family:serif;}#to-address{top:30mm;right:8mm;/* ずれたら適宜変更 */height:95mm;font-size:14pt;letter-spacing:0.2mm;text-indent:-1em;writing-mode:vertical-rl;text-orientation:upright;position:absolute;margin:0;padding:0;}#to-family-name{min-height:30mm;letter-spacing:0.2em;padding-bottom:0.2em;}#to-first-name{min-height:30mm;letter-spacing:0.2em;padding-bottom:0.2em;}#to-name-suffix{min-height:24mm;}</style></head><body><sectionclass="page"><spanid="to-postcode3">150</span><spanid="to-postcode4">0002</span><divid="to-address">東京都渋谷区渋谷百ー二百ー三百<br>ビルビルビルビル4F<br></div><divid="to-name"><divid="to-family-name">四駆<br></div><divid="to-first-name">太郎<br>はなこ</div><divid="to-name-suffix"><br></div></div></section>

縦書き記述はwriting-mode:vertical-rl;text-orientation:upright;あたりです。
<section class="page">...</section>が、はがき1枚分になり印刷でも1ページになるようにしてます。
なので、ここを印刷したい住所の数だけページを増やしていく感じになります。

あと、height:148mmの指定だと1pxぐらい大きくなって改ページが入ってしまったので、pxの指定に変えました。

住所データ

JSONで管理することにします。
あんまり深いことは考えず実装が楽な感じにしてみました。

address.json
[{"postcode":"1500002","address-line1":"東京都渋谷区渋谷百ー二百ー三百","address-line2":"ビルビルビルビル4F","address-line3":"","name":[{"family-name":"四駆","first-name":"太郎","suffix":"様"},{"first-name":"はなこ","suffix":"様"}]},{"postcode":"1234567","address-line1":"東京都渋谷区渋谷四百ー五百ー六百","address-line2":"マンションマンション4F","address-line3":"","name":[{"family-name":"姓","first-name":"名前","suffix":"様"},{"first-name":"名","suffix":"様"},{"first-name":"めい","suffix":"ちゃん"},{"first-name":"メイ","suffix":"くん"}]},・・・]

もちろん、みんな大好きな jq使います。

例えば、select(.name[]."family-name" == "四駆")とか書けばそれだけ抽出できたりします。

$ jq -r '.[] | select(.name[]."family-name" == "四駆")' address.json
{
  "postcode": "1500002",
  "address-line1": "東京都渋谷区渋谷百ー二百ー三百",
  "address-line2": "ビルビルビルビル4F",
  "address-line3": "",
  "name": [
    {
      "family-name": "四駆",
      "first-name": "太郎",
      "suffix": "様"
    },
    {
      "first-name": "はなこ",
      "suffix": "様"
    }
  ]
}

印刷用データ作成の流れ

まず、先程のsample.htmlから<section class="page">...</section>までを切り出して、print_template.htmlpage_template.htmlに分割して変換用のパラメータを埋め込んでおきます。

page_template.html
<sectionclass="page"><spanid="to-postcode3">{{postcode3}}</span><spanid="to-postcode4">{{postcode4}}</span><divid="to-address">{{address}}</div><divid="to-name"><divid="to-family-name">{{family-name}}</div><divid="to-first-name">{{first-name}}</div><divid="to-name-suffix">{{suffix}}</div></div></section>

これを住所の数だけ置換しながら増やしていきます。

実行

Macを想定。
以下のコマンドを実行。

$ (cat print_template.html; jq -r' .[] | "-e \"s/{{postcode3}}/"+ .postcode[:3] +"/g\" -e \"s/{{postcode4}}/"+ .postcode[3:7] +"/g\" -e \"s/{{address}}/"+ ."address-line1" +"<br>"+ ."address-line2" +"<br>"+ ."address-line3" +"/g\" -e \"s/{{family-name}}/"+ ([ .name[]."family-name" ] | join("<br>")) +"/g\" -e \"s/{{first-name}}/"+ ([ .name[]."first-name" ] | join("<br>")) +"/g\" -e \"s/{{suffix}}/"+ ([ .name[]."suffix" ] | join("<br>")) +"/g\" page_template.html" ' address.json | xargs -n 13 sed;)>print.html; /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --headless--print-to-pdf="print.pdf" file:///path/to/print.html

必要なものは以下。

  • Google Chrome
  • jq

これを実行すると、print.htmlprint.pdfが同一ディレクトリにできるので、好きな方で印刷するだけです。

最後に

最後になりますが、記事を書いてくれたみなさま、読んでくれたみなさま、ありがとうございます。来年もみなさまにとってよい年でありますよう心よりお祈り申し上げます。


:christmas_tree: FORK Advent Calendar 2019
:arrow_left: 24日目 Nuxt.jsとmysqlを連携してデータを表示してみた@ktn

CSSを利用して、好きなアニメに出てくるデジタル時計のデスクトップアプリを作ってみた

$
0
0

この記事はたまたま集まった技術&もの作りが好きな人たち Advent Calendar 2019 25日目の記事です。

はじめに

初めまして!25日目を担当させていただきます@a2ureと言います
クリスマスですね!あと30分切ってますがw
(ギリギリの投稿です)

今回はテレビアニメ「蒼穹のファフナーEXODUS」に登場するデジタル時計のデスクトップアプリを作ってみました!

作成にHTML,CSSやEletron等を利用しているのですが、私はHTML,CSSといったフロント周りの経験がない、ほぼ初心者なので至らない点が沢山あると思います。
完全にノリと勢いで作ったものなので、「こんなのを作りたかったのね」というゆるい感覚で見ていただければと思っております…!

注意

この作品が好きな人間が「個人の範囲内で楽しむため」に作成したものになります。
公式とは一切関係ございません。

作成するデジタル時計について

そもそも「蒼穹のファフナー」という作品を知らない方もいると思うので、軽く説明を。
蒼穹のファフナー」は2004年から放送されているロボットアニメシリーズです。
「ファフナー」というロボットに乗り、宇宙からきた生命体「フェストゥム」と戦い・対話し平和を掴もうと生きる人々の物語です。

今回作るのはこの作品のTVシリーズ第2弾にあたる「蒼穹のファフナーEXODUS」に登場するデジタル時計です。
ファフナーのコックピット内で登場し、日時等を教えてくれます。

image.png
画像: 蒼穹のファフナーEXODUS第16話より

デザインが好きだったので「こんなデスクトップアプリとかあったらなー」と思ったのがきっかけ。
ないなら作ればいい」精神でCSS,electronを利用してこれのデスクトップアプリを作っていきます。

完成品

先に、(GIFになりますが)完成品はこちらになります。
ちなみに今年の6月に作成開始して7月に完成。
約1か月ほどかかりました。
fd5559534d2053363a1d8e4de96ade24.gif

作成の流れ

今回は下記3つの工程で作成しました。
- HTML,CSSで再現する
- 時計用のフォントを作成する
- Electronでデスクトップアプリ化

HTML,CSSで再現する

本編の画像を見ながら、HTML,CSSで模写していきます。
日時を表示する部分はjavascriptを利用しました。

ブラウザ向けにgithubにあげたものがこちらになります。
- 完成品
- ソースコードはこちら
※ chromeでは表示が少し崩れてしまっているようで、今後修正予定です。(safariでは崩れず表示ができることを確認できました)

再現のために主利用したのは下記になります。
- clip-path
- z-index
- flexbox
- Grid Layout

基本的には
1. clip-pathでパーツを作る
2. z-indexでパーツを重ねる
3. 2で作ったものをflexboxで並べる
4. flexでの配置が難しそうな部分はGrid Layoutを利用
といった事を繰り返しました。

なんと、画像は一切使っておりません!
なんでCSSだけで頑張ろうと思ったのか私にもわかりません!!

本当は色々コードについて解説したいのですが、完全にノリと勢いで作っていたので記憶がないです。。

フォントを作成する

日付を表示しているデジタル文字のフォントを作成していきます。

作成にはCalligraphrを利用しました。
- Calligraphr

本編からデジタル時計の登場するシーンを「0~9」の数字分さがして、ペイントツールで描きました。
作業の様子↓
Image from iOS.jpg

Electronでデスクトップアプリ化

最後にElectronを利用してデスクトップアプリ化していきます。
- Electron
いつもはmacでプログラミングや作業をしていますが、今回はWindowsで動かしてみたかったのでWindowsにElectronの環境を構築してみました。
- 2019 年版:Electron の環境構築(Windows 向け)

これで完成です。

まとめ

完全に勢いで始めたのですが、CSSを触たり、フォントを1から作ってみたり、とても楽しかったです!
でも全部CSSは少し疲れました…🤤

また機会があった際はなにか作ってみようかなと思います!

【HTML/CSS】クリスマスなのでペンギンをHTML/CSSで作ってみた

$
0
0

ペンギンをHTML/CSSで作る

クリスマスなので、シンプルなペンギンを作ってみました。
HTMLとCSS以外は使っていません。

完成形

スクリーンショット 2019-12-25 23.43.32.png

ソース

ソースは下記の通りです。
jsfiddleで作成しました。
別の環境でテストしていないため、別の環境で絵が崩れた場合については
ご了承ください。

目(class="eyes")の部分はflexボックスを使用しています。
もしよかったら参考にしてみてください。

HTML

<divclass="penguin"><divclass="eyes"><divclass="eye"><divclass="pupil"></div></div><divclass="eye"><divclass="pupil"></div></div></div><divclass="mouth"><hrclass="mouth_border"></div><divclass="stomach"></div></div>

CSS

.penguin{display:block;background-color:#5BA9FF;width:370px;height:400px;border-radius:35%35%00;margin-top:20px;margin-left:20px;}.eyes{display:flex;position:absolute;margin-top:52px;}.eye{background:white;width:50px;height:50px;border-radius:50%;margin-left:86px;}.pupil{background:black;position:relative;margin-top:5px;margin-left:5px;width:40px;height:40px;border-radius:50%;}.mouth{background-color:#FFC039;position:absolute;width:120px;height:20px;margin-top:110px;margin-left:120px;border-radius:50%;}.mouth_border{position:relative;margin-top:8px;}.stomach{background:white;position:relative;width:300px;height:180px;margin-left:6%;border-radius:35%35%00;position:absolute;bottom:0;}

HTML/CSSで大石泉すきを「描」いてみる

$
0
0

まえがき

若干遅刻してしまい誠に申し訳ありませんでした。皆さんもインフルエンザには気をつけましょう……。

HTML/CSSで大石泉すきをいてみる

まずは基本。

<!DOCTYPE html><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0">大石泉すき

(いや CSS 使ってないやんというのは置いておいて、)HTML ではこれだけで「大石泉すき」とけてしまいます。なんなら viewport項を抜いても構いません。

でも、なんの捻りもなく面白みに欠けますよね……?

HTML/CSSで大石泉すきをいてみる

じゃあいてみよう。

まず下準備をしましょう。

<!DOCTYPE html><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><style>:root{--size:14vw}body{align-items:center;display:flex;justify-content:space-evenly;margin:0}body,html{height:100%}body>div{display:grid;height:var(--size);width:var(--size)}body>div>div{background:#000;transform-origin:righttop}</style><div></div><div></div><div></div><div></div><div></div>

この CSS では body配下に CSS Flexible Box Layoutを用い(display:flex)、上下(align-items:center)左右(justify-content:space-evenly)共に中央で、子を余白付きで横並びに等分する配置(justify-content:space-evenly)を指定しています。
そして、body配下には子となる div要素を 5 つ配置しています。察しの良い方はこの時点で完成像が予想できるのではないでしょうか。なんなら既に不穏なスタイルが定義されていますね。

image.png

では「大」からいていきましょう。

まず最初に HTML 末尾にある div要素群の一番上に divを 4 つ入れます。こんな感じです。

<div><div></div><div></div><div></div><div></div></div><div></div><div></div><div></div><div></div>

また次の CSS を styleの中に追加で投入します。

body>div:nth-child(1){grid:2fr1fr6fr/4fr1fr4fr}body>div:nth-child(1)>div{grid-column:2;grid-row:3}body>div:nth-child(1)>div:nth-child(1){grid-column:2;grid-row:1}body>div:nth-child(1)>div:nth-child(2){grid-column:1/4;grid-row:2}

先ほど下ごしらえした CSS の効果で、body直下の divCSS Grid Layoutを用いて配置(display:grid)されることが指定されており、追加で投入した CSS のうち一番最初の行で、内部を行列それぞれ 2:1:6 4:1:4 の割合で分割(grid:2fr 1fr 6fr/4fr 1fr 4fr)するように指定しています。

後の 3 行で先ほど追加した div 4 つをうまいこと配置します。要は grid-columngrid-rowプロパティで列番号と行番号を指定しているだけです。スラッシュ(/)区切りで番号が 2 つ指定されている場合、それぞれ始端と終端を表します。

image.png

おっと、下を斜め向きにするのを忘れていましたね。

body>div:nth-child(1)>div:nth-child(3){transform:skewX(-.5rad)}body>div:nth-child(1)>div:nth-child(4){transform:skewX(.5rad)}

これで「大」の完成です。

image.png

先ほどの手順と要領はあまり変わりません。

divを 6 つ入れて……

<div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div><div></div></div><div></div><div></div><div></div>

次の CSS を投入します。

body>div:nth-child(2){grid:1fr3fr1fr1fr2fr1fr/repeat(4,1fr)4fr1fr}body>div:nth-child(2)>div{grid-column:4/6}body>div:nth-child(2)>div:nth-child(3n){grid-row:3/7}body>div:nth-child(2)>div:nth-child(1){grid-column:1/7;grid-row:1}body>div:nth-child(2)>div:nth-child(2){grid-column:4;grid-row:2/5;transform:skewX(-.5rad)}body>div:nth-child(2)>div:nth-child(3){grid-column:3}body>div:nth-child(2)>div:nth-child(4){grid-row:3}body>div:nth-child(2)>div:nth-child(5){grid-row:6}body>div:nth-child(2)>div:nth-child(6){grid-column:6}

おっと、ここで repeatなるものが現れましたね。これは repeat([繰り返す回数],[繰り返す内容])を表しており、repeat(4,1fr)1fr 1fr 1fr 1frほぼ同義です。
あとさらっと :nth-child(3n)なるセレクタも使っていますが、これは見た目通り $3n$ 番目にあたる要素にマッチするので、すなわちここでは 3 番目と 6 番目が対象となります。

さて、こんな感じの「石」が生まれたら成功です。

image.png

うーん、最大の関門……。
先ほどまでと同じ要領で divを 12 個入れます。

<div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><div></div><div></div>

追加するスタイルはこんな感じです。

body>div:nth-child(3){grid:repeat(4,1fr2fr)4fr2fr/repeat(9,1fr)}body>div:nth-child(3)>div{grid-row:8}body>div:nth-child(3)>div:nth-child(-n+6){grid-row:2/7}body>div:nth-child(3)>div:nth-child(-n+4){grid-column:2/9}body>div:nth-child(3)>div:nth-child(6n+1){grid-column:5}body>div:nth-child(3)>div:nth-child(1){grid-row:1}body>div:nth-child(3)>div:nth-child(2){grid-row:2}body>div:nth-child(3)>div:nth-child(3){grid-row:4}body>div:nth-child(3)>div:nth-child(4){grid-row:6}body>div:nth-child(3)>div:nth-child(6){grid-column:9}body>div:nth-child(3)>div:nth-child(7){grid-row:7/11}body>div:nth-child(3)>div:nth-child(8){grid-column:4;grid-row:10}body>div:nth-child(3)>div:nth-child(9){grid-column:3;grid-row:9/11;transform:skewX(-.5rad)}body>div:nth-child(3)>div:nth-child(10){grid-column:7;grid-row:8/11;transform:skewX(.5rad)}body>div:nth-child(3)>div:nth-child(11){grid-column:1/4}body>div:nth-child(3)>div:nth-child(12){grid-column:8/10;transform:skewY(-.25rad)}

まず最初の repeat部分ですが、このように複数の数値を入れても動いてくれます。すなわち repeat(4,1fr 2fr)1fr 2fr 1fr 2fr 1fr 2fr 1fr 2frのように展開されます。

あと :nth-child(-n+6)のような記法は「最初の 6 要素」が対象になります。初見だとややこしいですね。

さて、「泉」はこんな感じになりました。

image.png

ひらがなになると若干ごちゃごちゃ感は解消するんですが、バランスよく配置するのが結構難しいです。divを 5 つ生やして……

<div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div></div>

CSS をドン!

body>div:nth-child(4){grid:2frrepeat(5,1fr)2fr/3frrepeat(3,1fr)3fr}body>div:nth-child(4)>div{grid-column:3}body>div:nth-child(4)>div:nth-child(1){grid-column:1/6;grid-row:2}body>div:nth-child(4)>div:nth-child(2){grid-column:4;grid-row:1/8}body>div:nth-child(4)>div:nth-child(3){grid-column:2;grid-row:4/7}body>div:nth-child(4)>div:nth-child(4){grid-row:4}body>div:nth-child(4)>div:nth-child(5){grid-row:6}

もはや重点的に解説することはありませんね。「す」完成です。

image.png

先ほどと同じく divを 5 つぶち込んで……

<div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div></div>

CSS もこんな感じに。

body>div:nth-child(5){grid:repeat(3,4fr3fr)3fr3fr/1fr1fr3fr1fr2fr1fr}body>div:nth-child(5)>div{grid-column:1/8}body>div:nth-child(5)>div:nth-child(1){grid-row:2}body>div:nth-child(5)>div:nth-child(2){grid-row:4}body>div:nth-child(5)>div:nth-child(3){grid-column:4;grid-row:1/7}body>div:nth-child(5)>div:nth-child(4){grid-column:2;grid-row:6/8}body>div:nth-child(5)>div:nth-child(5){grid-column:2/6;grid-row:8}

「き」は若干なんとも言えない感じがありますが、まあよしとしましょう。

image.png

大石泉すき

最終的にこんな感じになります。

<!DOCTYPE html><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><style>:root{--size:14vw}body{align-items:center;display:flex;justify-content:space-evenly;margin:0}body,html{height:100%}body>div{display:grid;height:var(--size);width:var(--size)}body>div>div{background:#000;transform-origin:righttop}body>div:nth-child(1){grid:2fr1fr6fr/4fr1fr4fr}body>div:nth-child(1)>div{grid-column:2;grid-row:3}body>div:nth-child(1)>div:nth-child(1){grid-column:2;grid-row:1}body>div:nth-child(1)>div:nth-child(2){grid-column:1/4;grid-row:2}body>div:nth-child(1)>div:nth-child(3){transform:skewX(-.5rad)}body>div:nth-child(1)>div:nth-child(4){transform:skewX(.5rad)}body>div:nth-child(2){grid:1fr3fr1fr1fr2fr1fr/repeat(4,1fr)4fr1fr}body>div:nth-child(2)>div{grid-column:4/6}body>div:nth-child(2)>div:nth-child(3n){grid-row:3/7}body>div:nth-child(2)>div:nth-child(1){grid-column:1/7;grid-row:1}body>div:nth-child(2)>div:nth-child(2){grid-column:4;grid-row:2/5;transform:skewX(-.5rad)}body>div:nth-child(2)>div:nth-child(3){grid-column:3}body>div:nth-child(2)>div:nth-child(4){grid-row:3}body>div:nth-child(2)>div:nth-child(5){grid-row:6}body>div:nth-child(2)>div:nth-child(6){grid-column:6}body>div:nth-child(3){grid:repeat(4,1fr2fr)4fr2fr/repeat(9,1fr)}body>div:nth-child(3)>div{grid-row:8}body>div:nth-child(3)>div:nth-child(-n+6){grid-row:2/7}body>div:nth-child(3)>div:nth-child(-n+4){grid-column:2/9}body>div:nth-child(3)>div:nth-child(6n+1){grid-column:5}body>div:nth-child(3)>div:nth-child(1){grid-row:1}body>div:nth-child(3)>div:nth-child(2){grid-row:2}body>div:nth-child(3)>div:nth-child(3){grid-row:4}body>div:nth-child(3)>div:nth-child(4){grid-row:6}body>div:nth-child(3)>div:nth-child(6){grid-column:9}body>div:nth-child(3)>div:nth-child(7){grid-row:7/11}body>div:nth-child(3)>div:nth-child(8){grid-column:4;grid-row:10}body>div:nth-child(3)>div:nth-child(9){grid-column:3;grid-row:9/11;transform:skewX(-.5rad)}body>div:nth-child(3)>div:nth-child(10){grid-column:7;grid-row:8/11;transform:skewX(.375rad)}body>div:nth-child(3)>div:nth-child(11){grid-column:1/4}body>div:nth-child(3)>div:nth-child(12){grid-column:8/10;transform:skewY(-.25rad)}body>div:nth-child(4){grid:2frrepeat(5,1fr)2fr/3frrepeat(3,1fr)3fr}body>div:nth-child(4)>div{grid-column:3}body>div:nth-child(4)>div:nth-child(1){grid-column:1/6;grid-row:2}body>div:nth-child(4)>div:nth-child(2){grid-column:4;grid-row:1/8}body>div:nth-child(4)>div:nth-child(3){grid-column:2;grid-row:4/7}body>div:nth-child(4)>div:nth-child(4){grid-row:4}body>div:nth-child(4)>div:nth-child(5){grid-row:6}body>div:nth-child(5){grid:repeat(3,4fr3fr)3fr3fr/1fr1fr3fr1fr2fr1fr}body>div:nth-child(5)>div{grid-column:1/8}body>div:nth-child(5)>div:nth-child(1){grid-row:2}body>div:nth-child(5)>div:nth-child(2){grid-row:4}body>div:nth-child(5)>div:nth-child(3){grid-column:4;grid-row:1/7}body>div:nth-child(5)>div:nth-child(4){grid-column:2;grid-row:6/8}body>div:nth-child(5)>div:nth-child(5){grid-column:2/6;grid-row:8}</style><div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div></div><div><div></div><div></div><div></div><div></div><div></div></div>

大石泉すきとかずに大石泉すきとくことに成功しました。

image.png

See the Pen 大石泉すき on HTML/CSS by Acid Chicken (硫酸鶏) (@acid-chicken) on CodePen.

あとがき

想定された使い方とは明らかに異なったスタイルで大石泉すきを描いてみました。やはり CSS で一次元配置をするなら Flexible Box、二次元配置をするなら Grid に限りますね。

ボタンコンポーネントからはじめるCSS設計

$
0
0

はじめに

Webサイトの構築においては、ページ上に繰り返し現れる各種UIをメンテナンス性・再利用性の観点からコンポーネント化し、共通のソースコード(HTML/CSS/JavaScript)で管理することが一般的です。

数あるUIコンポーネントの中で、サイト規模の大小を問わずほとんどすべてのWebサイト(ページ)に存在すると言えるのがボタンコンポーネントです。

ボタン自体はシンプルな見た目であることが多く、一見すると実装は簡単そうに思えますが、さまざまな場面に登場することから機能やデザイン(見た目)のバリエーションが意外と多くなり、サイト制作を進めるうちにいつの間にか複雑な実装になってしまった、ということも少なくありません。

私自身、1ページ完結のLPから数1000ページに及ぶ大規模サイトまでさまざまなタイプのWebサイト制作に携わる中で、「ボタン」を設計する難しさと奥深さを日々感じています。

本記事では、ボタンコンポーネントのCSS設計において私が意識している8つのポイントをご紹介します。

ボタンコンポーネントのCSS設計で意識する8つのポイント

1. 特定のclassのみでボタンコンポーネントを表現する

<aclass="button"href="#">ボタン(a要素)</a><buttonclass="button"type="button">ボタン(button要素)</button>
/* OK */.button{/* ボタンコンポーネントのスタイル指定 */}/* NG */a.button,button,p.buttona{/* ボタンコンポーネントのスタイル指定 */}

ボタンコンポーネントは特定のclassのみで表現できるようにし、HTML要素に依存したスタイル指定は避けるようにします。

上記のOK例では、ボタンコンポーネントを表現するためのclassとして .button1を用意し、対象となるHTML要素が何であれ(a要素、button要素、input要素、div要素、span要素など 2)classの付与のみでボタンコンポーネントのスタイルを適用できるようにしています。

2. a要素やbutton要素のデフォルトCSSを意識して、ボタンコンポーネントの初期スタイルを調整する

ボタンコンポーネントとして利用されることが多いa要素やbutton要素にはユーザーエージェントごとのデフォルトCSSが指定されているため、それらを踏まえて .buttonに対してスタイルの調整をおこないます。

.button{-webkit-appearance:none;box-sizing:border-box;margin:0;border:0;background-color:transparent;color:inherit;font-size:inherit;text-align:left;text-decoration:none;cursor:pointer;}

button要素のデフォルトスタイルをリセットするための -webkit-appearance: none;や、a要素のデフォルトスタイルをリセットするための color: inherit;, text-decoration: none;などを記述しています。

3. displayの値はinline-flexにする

一般的にボタンコンポーネントのdisplay値は inline-blockとされる場合が多いように思いますが、自分の経験上では inline-flexがもっともスタイリングの融通が効く指定だと感じています。

ボタンの内容となるテキストやアイコンは上下左右中央寄せに配置されることが多く、そのようなレイアウトを justify-contentalign-itemsの指定によって簡単に実現することができます。

.button{-webkit-appearance:none;box-sizing:border-box;margin:0;border:0;background-color:transparent;color:inherit;font-size:inherit;text-align:left;text-decoration:none;cursor:pointer;/* 追記 */display:inline-flex;justify-content:center;align-items:center;}

inline-blockとの比較

display値が inline-blockの場合、例えば「ボタンが特定の高さを保ちつつ、ボタン内のテキストやアイコンは上下中央寄せにしたい」といったデザイン的な要求があった場合に paddingfont-size, line-heightなど複数の数値を絡めた調整が必要になり、扱いづらいコードになりがちです。

その点、display値が inline-flexであれば、min-heightalign-itemsを指定することで同様のデザインも簡単に実現可能です。
また、「font-sizeを少し変えたらボタンの高さが微妙に変わってしまった」といったことも起こりにくくなります。

.button-inline-block{display:inline-block;/* 省略 */font-size:20px;line-height:1;padding-top:12px;padding-bottom:12px;/* 20 + 12 + 12 = 44pxの高さを確保する */}.button-inline-flex{display:inline-flex;/* 省略 */min-height:44px;/* 最低限の高さ44pxを保ちつつ */align-items:center;/* ボタンの中身は上下中央寄せ */}

4. widthやheight、paddingなど、ボタンの大きさに影響する「固定値」の指定は慎重におこなう

1つ前のセクションで「高さ指定」の話をしたばかりですが、ボタンコンポーネントに対して width, height, padding, font-sizeなどサイズに関する固定値を指定する際には、本当にそれがボタンのデザインルールとして妥当な実装であるかを十分に検討すべきです。

デザインの意図を考える

例えば、とあるWebサイトを制作する際、デザインカンプ内に次のようなボタンコンポーネントがあったとします。
調べてみるとボタンの横幅はだいたい200pxになっていました。
このボタンコンポーネントをCSSで実装する際、どのようなコードが妥当と言えるでしょうか?

qiita_01.png

結論から言うと、この時点ではまだボタンコンポーネントのもつデザインルールや特性が判断できないため、ボタンコンポーネントとして妥当なCSSを書くことはできません。

このデザインカンプから読み取れる範囲内でも、少なくとも下記3つのようにまったく異なるパターンのデザインルールが考えられます。

  1. ボタンの横幅は必ず200pxである
  2. ボタンの横幅はテキスト量によって伸縮し、ボタン内側に必ず左右45pxの余白(padding)が確保される
  3. ボタンの横幅はテキスト量によって伸縮するが、どんなにテキスト量が少ない場合でも最低200pxの横幅が確保される

個人的には、2か3のどちらかかな? と考えると思います。

CSS設計時に大切なことは、このようなデザインルールについてデザイナーの意図を確認し、それらを言語化し、実装まで落とし込むことです。

そのような検討プロセスを省略して、デザインカンプの見た目から安易に width: 200px;といった固定値を指定してしまうと、本来のデザインルールと相反するコンポーネントとなって後々の制作や運用に支障をきたす場合が多いです。

5. ボタンの種類が明確にある場合のみ、Modifierを利用して派生パターンを作成する

「コンテンツ幅100%に広がるボタン」「サイト内で重要度の高いボタン」など、ボタンの種類や意味合いが明らかに他のものと区別できる場合は、Modifierを利用して新たなclassを作成し、差分となるスタイルを指定します。

<aclass="button button-full"href="#">コンテンツ幅100%に広がるボタン</a><buttonclass="button button-primary"type="button">サイト内で重要度の高いボタン</button>
.button{/* 省略 */}.button-full{width:100%;}.button-primary{background-color:red;color:white;}

このようなclassを作る際も、「どこまでが標準的なボタンコンポーネントが持っている特性(スタイル)で、どこからが例外的な特性(スタイル)なのか」についてデザイナーと議論をし、可能な限りそれらを言語化した上で実装を進めていくことが大切です。

逆に、きちんと言語化できないことを「何となく」で実装してしまうと、それが後になって矛盾を引き起こす場合が多いと感じます。

6. marginなど、レイアウトに影響するスタイル指定はおこなわない

あらゆる場所で利用される可能性のあるコンポーネントは「それ自身がどのようにレイアウトされるかは知らない」という状態にしておくべきであり、marginfloatなどレイアウトに関するスタイルをコンポーネント自身に持たせることは避けます。

/* NG */.button{margin:30px00;}

レイアウトに関するスタイルは祖先要素にもたせるか、コンポーネント要素に固有のclassを新たに付与して、そのclassに対してスタイル指定します。

<divclass="centerButton"><buttonclass="button"type="button">ボタン</button></div>
/* 祖先(親)要素にレイアウトスタイルをもたせる */.centerButton{margin-top:30px;text-align:center;}

7. target="_blank" やPDFリンクの場合に自動的にアイコンが表示されるようにする

Webサイトのデザインルールにもよるところですが、ページ内の「別ウィンドウ(タブ)で遷移するリンク」や「PDFダウンロードリンク」に対して、それとわかるよう特定のアイコンを表示することが一般的です。

ボタンコンポーネントにもそのようなデザインルールが適用されるのであれば、属性セレクタと疑似要素を利用してアイコン表示を自動化しておきます。

これにより、個々のボタンにアイコンを追加していく作業負荷が軽減し、長期的なサイト運用におけるデザインルールのバラつきを抑える効果も期待できます。

See the Pen qiita_c382cf78f8ffe6fbe65b_01 by Sho Uchida (@shouchida) on CodePen.

.button[target="_blank"]::after{font-family:"Font Awesome 5 Free";content:"\f24d";margin-left:0.4em;}.button[href*=".pdf"]::after{font-family:"Font Awesome 5 Free";content:"\f1c1";margin-left:0.4em;}

上記の例では、Font Awesomeによるアイコンフォントを利用して、「target属性が "_blank"である場合」と、「href属性に .pdfが含まれる場合」にそれぞれアイコンを表示させています。
プロジェクト独自のアイコン画像を使用する場合は、backgroundとして画像を指定し、サイズの調整をおこないます。

.button[href*=".pdf"]::after{content:"";background:url(icon_pdf.svg)no-repeatcenter/contain;width:0.8em;height:0.8em;margin-left:0.4em;}

8. disabled など非活性状態のスタイルも忘れずに実装する

フォームに含まれるボタンなど、「操作ができない(disabled)状態」のボタンもWebページには頻繁に登場するため、ボタンコンポーネントを作成する際はそれらのスタイルも忘れずに用意しておきます。

See the Pen qiita_c382cf78f8ffe6fbe65b_02 by Sho Uchida (@shouchida) on CodePen.

<buttonclass="button"type="button"disabled>非活性状態のボタン</button>
.button[disabled]{pointer-events:none;background-color:gray;}

ここでも属性セレクタを利用し、「disabled属性がある場合」という条件でスタイルを記述します。

おわりに

ボタンコンポーネントはひとつのWebサイト内で数多く使用されるという特徴からも、設計段階における少しの差が後々のサイト運用負荷に大きく影響する可能性があります。

「たかがボタン」ですが、本記事内で繰り返し述べたように、最適なボタンコンポーネントを作るためにはデザインの意図やルールについてデザイナーと実装者との間でしっかりと認識を合わせ、言語化していくことが非常に大切です。

そして、そのようなコミュニケーションの積み重ねがWebサイト全体の品質向上に繋がっていくと考えています。


  1. CSSの命名規則については本記事では取り扱いません。 

  2. div要素やspan要素はtabキー操作時にフォーカスが当たらないため、「ボタン」として振る舞わせる場合にはtabindex属性の追加など工夫が必要です。 

【CSS】floatで並び方をかえる

$
0
0

リストを横並びと縦並びとでわける

スクリーンショット 2019-12-26 3.55.39.png

:thinking:フルーツは横並びで野菜(赤文字)は縦並びにしたい。

例.html
<divclass="fruits"><ul><li>りんご</li><li>みかん</li><li>メロン</li></ul></div><divclass="vegetable"><ul><li>トマト</li><li>かぼちゃ</li><li>キャベツ</li></ul></div>
例.css
.fruits{float:left;}.vegetable{float:left;color:red;}li{float:left;list-style:none;margin-right:20px;}

コードを確認すると・・・

CSSファイルの fruits クラスと vegetable クラスの float: left; はHTMLファイルで div を使っているのでブロック化されている。
それを横並びにしただけ。
これはとくに関係なさそう。

CSSファイルの li の float: left; はブロック関係なく全ての li に対して横並びになっている。
原因はこれだな。

これを野菜ブロックだけ縦並びにしたい。
野菜ブロックだけに適応させたいということは、CSSを・・・

例.css
li{list-style:none;margin-right:20px;}.fruitsli{float:left;}

まずは li の部分の float: left; を消す。
それからフルーツブロックの文字を横並びにしたいので
.fruits クラスの li に float: left; を適用するようコーディングすれば・・・

Web

スクリーンショット 2019-12-26 4.20.07.png

できました!:laughing:

まとめ

:sunny: CSSでクラス名のあとに要素名を記入すると、そのクラスの要素にのみcssを適用することができる。

.クラス名 要素名 {
  プロパティ: 値;
}

左右に配置する

スクリーンショット 2019-12-26 4.20.07.png

:thinking:さきほどの野菜ブロックを右端に配置してみる

例.css
.vegetable{float:right;color:red;}

float: left; を float: right; に変更

Web

スクリーンショット 2019-12-26 4.49.42.png

かんたん:laughing:

edgeにGoogleフォントがきかなくて悲しいときの対処法

$
0
0

読み込んでたGoogleフォントがきいてない

<head>~</head>内にURLを記述して読み込んでたGoogleフォント、Lato( https://fonts.google.com/specimen/Lato )がedgeできいてなかった。

なんでかなと思って調べたら、edgeはGoogleフォントのURLを読み込むだけじゃきかないことがあるらしい。
なんでかは知らない。なんでやねん。

解決法は.woffの拡張子のフォントファイルをぶち込んで、そいつを@font-faceで読み込ませる。
これでちゃんときいたのでやり方を簡単に書いておく。

拡張子.ttfファイルを手に入れる

GoogleFontsのサイトで手に入れられるファイルは拡張子.woffじゃなくて.ttfなので、先にこいつを手に入れるぞ。

OTFとTTFとWOFFの違い【フォントタイプ】 | SEO白書

①Googleにアクセス

私の場合はLatoフォント。「SELECT THIS FONT」をクリック
Lato - Google Fonts

②ダウンロードボタンを押してローカルにzipファイルを落とそう

STANDARDのURLじゃなくて、右上のダウンロードボタンをクリック

.ttf爆誕

ダウンロードしたzipファイル展開で拡張子.ttfが爆誕。

.ttf.woffにしちゃう

WOFFコンバータ
こいつをインストールしてくれ。

インストールするとアプリケーションに追加されるので、こいつを立ち上げるぞ。

立ち上げるとこんな感じ。
「参照」ボタンをクリックして、.woffにしたい.ttfファイルを一つ選択。


「変換開始」ボタンを押すと、.woffに変換されたファイルが誕生。

できた。

.woffはフォルダに入れて、@font-faceで読ませる

変換してできた.woffは、fontフォルダとかにぶちこもう。
で、ぶちこんだそいつはfont-face.scss(名前はこれじゃなきゃいけないってわけじゃないけど)を作成して、以下のような記述で読み込ませよう。

@font-face{font-family:'Lato';font-style:normal;font-weight:normal;src:url('../font/Lato-Regular.woff')format('woff'),}

ちなみにこれ、Lato-Regularだけを.woff変換して読ませてるから、もし太字も使いたい場合はLato-Boldも変換してフォルダに入れてから読ませなきゃだめですぜ。

RegularとBoldの場合はこんな感じ。

@font-face{font-family:'Lato';font-style:normal;font-weight:normal;src:url('../font/Lato-Regular.woff')format('woff'),}@font-face{font-family:'Lato';font-style:normal;font-weight:bold;src:url('../font/Lato-bold.woff')format('woff'),}

そしたら最後にfont-family指定

最後にfont-familyで読ませたら完成。

body{font-family:'Lato';}

これでうまくいく・・・・はず。
たぶん。

CSSで文字などをクルッと回転させる方法

$
0
0

CSSで文字などをクルッと回転させるやり方

ポートフォリオサイトを作成中、ホバー時に文字をクルッと回転させる動作を実装したので、備忘的に投稿させて頂きます。
※javascriptは使用しておらずcssのみで実装しています。

実際方法

実装方法といっても、とてもシンプルです。
例として、回転させたい方向で3通り記載しております。
X軸起点 = 鉄棒で前回りするイメージ
Y軸起点 = フィギュアスケートでのスピンのイメージ
Z軸起点 = 側転するイメージ

example.html
<ul><ahref="#"class="example-X">X軸起点</a><ahref="#"class="example-Y">Y軸起点</a><ahref="#"class="example-Z">Z軸起点</a></ul>
example.css
ula{text-decoration:none;display:inline-block;color:black;font-size:30px;}.example-X{transition:1s;transform:rotateX(0deg);}.example-X:hover{transform:rotateX(360deg);}.example-Y{transition:1s;transform:rotateY(0deg);}.example-Y:hover{transform:rotateY(360deg);}.example-Z{transition:1s;transform:rotateZ(0deg);}.example-Z:hover{transform:rotateZ(360deg);}

大事なのは、transform: rotateX( 360deg ) この記述です。
このように記述する事で、ホバー時に、360度=1回転します。

また、transition: 1s の値を大きくすればゆっくり回転し、小さくすれば速く回転しますので、
お好みで調整してください。

少しでも、皆様の参考になれば幸いです。
閲覧頂きありがとうございました!

Viewing all 8496 articles
Browse latest View live