20201016のCSSに関する記事は5件です。

【HTML】buttonタグでリンクを貼る方法

プログラミング勉強日記

2020年10月16日
HTMLでコードを書いてるときにbuttonタグでリンクを埋め込みたいと思ったのでその方法を備忘録としてまとめる。

方法

 buttonタグはクリックできるボタンを作るもので、基本的な書き方は以下のようになる。

基本的な書き方
<button>表示させる内容</button>

 buttonタグを使ってリンクを貼る場合はonclick属性を以下のように追加する。

buttonタグでリンクを貼る方法
<button onclick="loction.href='リンク先のURL'">表示させる内容</button>
具体例
<button onclick="location.href='https://qiita.com/mzmz__02'">Qiita マイページ(buttonタグで)</button>

image.png

他の方法でリンク先をbutton風にする

HTMLファイル
<a href="https://qiita.com/mzmz__02">Qiita マイページ(aタグで)</a>
<br><br>
<a class="button" href="https://qiita.com/mzmz__02">Qiita マイページ(aタグでスタイルを使って)</a>
<br><br>
<input type="button" onclick="location.href='https://qiita.com/mzmz__02'" value="Qiita マイページ(input buttonで)">
<br><br>
<button onclick="location.href='https://qiita.com/mzmz__02'">Qiita マイページ(buttonタグで)</button>
CSSファイル
.button {
  display: inline-block;
  border-style: solid;
  color: black;
  background-color: rgb(225, 224, 224);
  border-width:1px;
  border-color: darkgray;
  text-decoration: none;
}

image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

高校生がAIでWebサイトの改善点を提案するサービスを作った話

まえがき

アクセシビリティーの観点からWebサイトを診断し、AIプラットフォームを利用して得た情報をもとにベストプラクティスを提案してくれるオープンソースのWebサービス「Visible」を開発しました。

Visible ─ アクセシビリティー診断&修正提案

GoogleのLighthouseなど、Webサイトの診断を行ってくれるサービスは以前からありましたが、診断だけではなく改善点の提案も行う新しいサービスになっています。また、アクセシビリティーに関する理解を深めてもらえるように工夫をした設計にしていたり、コマンドライン版ではスタンドアロンで実行可能なようになっています。

2020年度の「独創的アイデアと卓越した技術を持つ小中高生クリエータ支援プログラム」未踏ジュニアに採択されていて、技術・資金面で援助を頂いており、11月1日にYouTube Liveで最終成果報告会が行われる予定です!

機能の紹介

WebサイトのURLを入力することでページを診断し、改善点を自動で提案してくれます。

診断結果のスクリーンショット

以下に提案する修正の一例を紹介します。

alt属性

<img>要素はスクリーンリーダーやSEOのクローラーに画像の内容を説明するためにalt属性が提供されることが推奨されており、Google Cloud PlatformのVision APIを利用してキャプションを生成することで改善のヒントを提案します。

image.png

lang属性

Webページの言語が明示的に指定されていないと、言語情報を必要とするユーザーエージェントで問題があるためページの内容からTranslate APIから言語情報を検出し提案します。

image.png

色コントラスト比

もちろん機械学習を使わない改善提案も可能です。色コントラスト比が低いと色覚特性を持ったユーザーが使いづらいため、コントラストを上げる修正を提案します。

コントラスト

アクセシビリティーに関するベストプラクティスはW3CによってWCAGという名前で標準化されており、他にも標準に基づいたルールがいくつかあります。

提案の仕組み

診断プログラムの実行にはChromeをヘッドレスで実行できるPuppeteerを使っていて、チェックポイント(Rule)のインターフェイスを実装したプログラムを実行し、各ruleから返された値をもとにファイルの情報と紐付けて最終的に差分として表示できるようになっています。

ワークフロー。下で詳解します

全体はコア、プラグイン、アプリケーションの3つのコンポーネントから構成されていて、コアで公開されている最低限の実装とインターフェイスを実装する形でプラグインで実際の処理を書いています。プラグインの形式はESLintを参考にしています。

動作フローを図で示しています。下で詳しく説明します。

改善点の生成アルゴリズムやヘッドレスブラウザーもruleと同様にプラグインとして拡張可能なため、Google Cloud Platformに限らず別の方法を使うことも可能です。

使った技術

プロジェクトはTypeScriptで開発されています。Tech stacksは以下のとおりです。

コア部分

  • Puppeteer - Chromeを使ったヘッドレスブラウザーです。診断プログラムの実行に使っています
  • domhandler - HTMLのASTです
  • PostCSS - プリプロセッサーとして知られていますが、stylelintを参考にASTとして使っています

Webバックエンド

  • Clean Architecture - 4層にレイヤー分けした有名なバックエンドの設計方法です。
  • TypeORM - TypeScript向けのORMです。
  • Bull - Redisを使ったジョブキューのフレームワークです
  • Apollo - Node.jsのGraphQL実装です

Webフロントエンド

  • Next.js - SSR/SSG/LambdaをやってくれるReact向けのBFFです
  • Apollo - Node.jsのGraphQL実装です
  • Tailwind CSS - Utility-firstのCSSフレームワークです
  • i18next - JS向けの国際化ライブラリです。

その他

  • GitHub Actions - CI/CDに使っています
  • Docker - Web版のデプロイに使っています
  • Yargs - CLI版に使っているフレームワークです
  • Lerna - JSのモノリポジトリのためのツールです

開発時のエピソード

Webアクセシビリティーという技術には前から興味があった一方で、僕自身は支援技術の利用を迫られたことがなく、正しいマークアップを心がけるモチベーションは専ら検索エンジンへの最適化くらいだったため、知識はあってもアクセシビリティーを欠いたWebサイトを作ってしまうことが多くあり、ESLintみたいに修正の方法も教えてくれるソフトウェアがあればいいと考えていました。

同時に、未踏ジュニアに応募できる年齢制限が17歳までで、当時僕はすでに17歳だったため最後にチャレンジしてみたいと考えていて、丁度いい機会にそれを作って応募してみようとプロトタイプを制作し始めました。

プロトタイプ

僕自身は中学生のときからプログラムを書いていてアルバイトだったりもしてるのでコードはかなり書いていましたが、それでも応募まで数ヶ月しかない状態でプロトタイプを仕上げるのは結構厳しく(正直採択後よりも応募段階のほうが忙しかったかもしれない)明確にゴールを設定する必要がありました。

応募自体にはプロトタイプは必須ではなくプロダクトの概要を書いた書類を送れば良かったものの、採択されるには僕自身が持っている技術を示して最後まで作り上げることができることを証明する必要がありました。逆に、それを示せればどこが面白いのかは伝わると判断し診断できる項目は最低限に絞り、「修正の提案」はバッサリ捨てて、「URLを入力したら診断結果が出てくる」ところまでをやることにしました。あとは脳内のふわふわした概念をノートに書いてドメインモデルに落とし込み、一番慣れている技術スタックでコードを書き始めました。

応募時のプロトタイプのスクリーンショット
応募時のプロトタイプのスクリーンショット

大体2ヶ月くらいで動くプロトタイプが出来上がり、無事書類選考も通過しました。その後は面接を受けることになっていて、オンラインでメンター陣にプロダクトに関する質問を受けました。正直何を言ったかよく覚えていませんが、確かプロダクト自体が将来的にどういう目標があるかみたいなことを訊かれて、漠然とした回答しかできなかったのは覚えています...。

採択後

採択後は、既にプロトタイプがあったためアジャイルで開発しました。未踏ジュニアでは定期的にメンタリングを受けられることになっていて、僕のプロジェクトでは週に一度メンターに進捗を報告しフィードバックを頂いていたので、だいたい各週でマイルストーンを設けてそれまでに小分けにした機能の開発を進めました。

ユーザーに使ってもらうまでのタスクの優先順位は完全に僕の勘で「これができるようになったぞ」って言ったときのインパクトが強い順でやっていましたが、今考えるとあんまりいい方法ではなかったかなと思います。ただ、それがあったおかげでビジネスロジックには拘ってもフレームワークに関する細かいところを弄りすぎることはなくてスピードは上がっていた気がします。

インパクト重視な機能の例
インパクト重視な機能の例

初ユーザーテスト

未踏ジュニアでは期間中、採択直後と中間時点と最後の3回登壇する機会があり(今年はオンラインでしたが)、一回目のプレゼンの機会がやってきたので既にあるプロトタイプ+αの段階のものを発表しました。

その際に、その時点のものをデプロイしたURLを共有し聴いていた方たちに実際に使っていただいたのですが、dockerの共有メモリの設定をミスっていたり非同期にするべきところを同期でレスポンスしたいたりして発表直後にサーバーがダウンしてしまい、期待していたほどのフィードバックは得られませんでした (トホホ〜)

A11yが専門の方々へのインタビュー

期間の四分の一を過ぎたあたりでメンター陣のご協力もあり某社のアクセシビリティーチームの方にフィードバックしていただく機会を頂けました。

アクセシビリティーの現場でどんなプロセスが行われているのかや、どんなツールを使っているか、チーム開発特有の問題を伺うことができ、このインタビューでストーリーラインを具体化してユーザー層を絞ることができました。タスク優先度もここらへんから明確になってきたと思います。

その後の改善

未踏ジュニアでの2回目の発表(もちろん負荷対策はしました...)やTwitterのフォロワーなどを活用して、実際に使ってもらいアンケートに答えてもらうというフィードバックループを小分けに回しました。

フィードバックは「How to create a good survey」と検索して上に出てきた良いとされる質問をパクってフィードバック用のフォームをGoogle Formsで作成したものと、Google Analyticsのタグを埋め込んだもので多面的に得られるようにしています。

特にユーザーがどの情報を欲しがっているかは重視していて、例えば未実装の機能にもURLを割り振ってそのURLにどれくらいトラフィックが発生したかで機能の優先度を付けることで開発に反映しました。

Google formのスクリーンショット

詰まったところ

すげーニッチな内容かもしれませんが、開発にあたって詰まったところのメモを書いておきます。

CSSのDOMから取れる情報とASTのマッピングができない

HTMLやCSSなどのソースコードはブラウザでパースされたあとにDOMに変換されてJavaScriptから利用可能になりますが、getComputedStlyeなどのメソッドから取得できるCSSの情報からは、どのファイルや宣言が適用されているのかわかりません。

そこで、Google Chromeの開発者ツールのAPIである Chrome Devtools Protocol を使うことにしました。CDPはCSS.styleSheetAdded というイベントから読み込まれたスタイルシートの情報を取得できるため、問題検出時にNodeのIDと該当のCSSプロパティから対応するCSSファイルを探し出し、PostCSSのASTに変換して扱うことができました。

Clean ArchitectureでORMをどこに置くか問題

書籍では「Interface adapter層はframework層が必要としているデータ形式に変換するレイヤー」と説明されており、そのためSQLクエリを発行する部分は interface adapter層、それを具体的なRDBMSで実行するのはframework層という扱いになっているのですが、ORMではこの2つのプロセスの境界が曖昧で、ググっても色んな人が全然違うことを言ってるっぽかったです。

TypeORMは(もちろん限度はありますが)どのRDBMSを使うかが抽象化されていて、最終的にormconfigで決定するようになっているので、詳細について言及していないと割り切ってinterface adapter層でDALを実装することにしました。

余談ですが、ドメインモデルをAPIの形に変換するpresenterもGraphQLの定義を直接扱うのではなくpresenter側で定義した型を使うことで依存の方向を守っています。

モノレポ(Yarn Workspace)でDockerをやるのが辛すぎる

マイクロサービスとかだとモジュール同士が依存することはあんまり無いのかと思いますが、フロントエンドとバックエンドで共有するパッケージがあるみたいなケースでYarn workspaceとDockerを使いたくなってしまうと、パッケージごとにlockfileを作れなかったりnode_modules以下がシンボリックリンクになっているから単純にコピーしても動かなかったりして詰みます。

今の所ごちゃごちゃなワークアラウンドを書いてなんとか動いています。Yarn v2 (berry) では yarn workspace focus という機能が提供されて、ほしいパッケージの依存だけをインストールして独立して動かせるようになっているっぽいので早く移行したいなと思っているのですが、Plug'n'Play周りが理解しきれていないためまだ手を付けられていません。

styled-componentsが辛い

初めてちゃんとデザインシステム的なUIコンポーネントを作ったんですが、一つのコンポーネントが複数のバリアントを持ってるみたいなとき(下記)にstyled-componentsでやると可読性が最悪で最終的にTailwindに逃げました。

const Button = styled.button`
  font-size: 12px;

  ${
    (props) => props.variant === 'primary'
      ? css`
        color: ${props.theme.primaryFgColor};
        background-color: ${props.theme.primaryBgColor};
      `
      : css`
        color: ${props.theme.secondaryFgColor};
        background-color: ${props.theme.secondaryBgColor}
      `;
  }
`;

詳細: https://qiita.com/rigarashi/private/5c97be5ed8fb15ea2d96

Utilify-firstをCSS-in-JSに輸入したstyled-systemとかxstyledというやつもあるっぽいんですが、テーマの型が静的に付かなかったので見送りました。

Puppeteerで並列処理

puppeteer-clusterというライブラリがいい感じっぽかったのですが、unmaintained気味なのと、pageのインスタンスをコールバックで受け取って簡単な処理をすることしかできず、例えばObservableに変換するみたいな今回のユースケースだと厳しかったのでやめました。

代わりに、いわゆるObject Poolingでbusyなインスタンスとそうでないインスタンスを管理して、暇そうなインスタンスに処理を投げるようにしました。こういうのは多分ワーカープロセスをforkしていくのがいいのかと思いますが、Puppeteerを起動した時点ですでにChromiumのプロセスと分かれるのであんまり意味がなかったのと、GraphQLのsubscriptionのソースになっているのがただのシングルトンで、redisとかを挟んでなくて同じプロセスで呼ばないとブラウザに伝えられないためです。

あとがき

蔑ろにされがちなアクセシビリティーで人々の気を引くにはどうすればいいか考えた結果、若干地雷っぽいタイトルになってしまったことをお赦しください。

また、web版等公開していますのでぜひお試しいただきフィードバックをお訊かせいただけると嬉しいです。

関連リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

機械学習APIでWebサイトの改善点を提案するサービスを作った話

まえがき

アクセシビリティーの観点からWebサイトを診断し、AIプラットフォームを利用して得た情報をもとにベストプラクティスを提案してくれるオープンソースのWebサービス「Visible」を開発しました。

Visible ─ アクセシビリティー診断&修正提案

GoogleのLighthouseなど、Webサイトの診断を行ってくれるサービスは以前からありましたが、診断だけではなく改善点の提案も行う新しいサービスになっています。また、アクセシビリティーに関する理解を深めてもらえるように工夫をした設計にしていたり、コマンドライン版ではスタンドアロンで実行可能なようになっています。

2020年度の「独創的アイデアと卓越した技術を持つ小中高生クリエータ支援プログラム」未踏ジュニアに採択されていて、技術・資金面で援助を頂いており、11月1日にYouTube Liveで最終成果報告会が行われる予定です!

機能の紹介

WebサイトのURLを入力することでページを診断し、改善点を自動で提案してくれます。

診断結果のスクリーンショット

以下に提案する修正の一例を紹介します。

alt属性

<img>要素はスクリーンリーダーやSEOのクローラーに画像の内容を説明するためにalt属性が提供されることが推奨されており、Google Cloud PlatformのVision APIを利用してキャプションを生成することで改善のヒントを提案します。

image.png

lang属性

Webページの言語が明示的に指定されていないと、言語情報を必要とするユーザーエージェントで問題があるためページの内容からTranslate APIから言語情報を検出し提案します。

image.png

色コントラスト比

もちろん機械学習を使わない改善提案も可能です。色コントラスト比が低いと色覚特性を持ったユーザーが使いづらいため、コントラストを上げる修正を提案します。

コントラスト

アクセシビリティーに関するベストプラクティスはW3CによってWCAGという名前で標準化されており、他にも標準に基づいたルールがいくつかあります。

提案の仕組み

診断プログラムの実行にはChromeをヘッドレスで実行できるPuppeteerを使っていて、チェックポイント(Rule)のインターフェイスを実装したプログラムを実行し、各ruleから返された値をもとにファイルの情報と紐付けて最終的に差分として表示できるようになっています。

ワークフロー。下で詳解します

全体はコア、プラグイン、アプリケーションの3つのコンポーネントから構成されていて、コアで公開されている最低限の実装とインターフェイスを実装する形でプラグインで実際の処理を書いています。プラグインの形式はESLintを参考にしています。

動作フローを図で示しています。下で詳しく説明します。

改善点の生成アルゴリズムやヘッドレスブラウザーもruleと同様にプラグインとして拡張可能なため、Google Cloud Platformに限らず別の方法を使うことも可能です。

使った技術

プロジェクトはTypeScriptで開発されています。Tech stacksは以下のとおりです。

コア部分

  • Puppeteer - Chromeを使ったヘッドレスブラウザーです。診断プログラムの実行に使っています
  • domhandler - HTMLのASTです
  • PostCSS - プリプロセッサーとして知られていますが、stylelintを参考にASTとして使っています

Webバックエンド

  • Clean Architecture - 4層にレイヤー分けした有名なバックエンドの設計方法です。
  • TypeORM - TypeScript向けのORMです。
  • Bull - Redisを使ったジョブキューのフレームワークです
  • Apollo - Node.jsのGraphQL実装です

Webフロントエンド

  • Next.js - SSR/SSG/LambdaをやってくれるReact向けのBFFです
  • Apollo - Node.jsのGraphQL実装です
  • Tailwind CSS - Utility-firstのCSSフレームワークです
  • i18next - JS向けの国際化ライブラリです。

その他

  • GitHub Actions - CI/CDに使っています
  • Docker - Web版のデプロイに使っています
  • Yargs - CLI版に使っているフレームワークです
  • Lerna - JSのモノリポジトリのためのツールです

開発時のエピソード

Webアクセシビリティーという技術には前から興味があった一方で、僕自身は支援技術の利用を迫られたことがなく、正しいマークアップを心がけるモチベーションは専ら検索エンジンへの最適化くらいだったため、知識はあってもアクセシビリティーを欠いたWebサイトを作ってしまうことが多くあり、ESLintみたいに修正の方法も教えてくれるソフトウェアがあればいいと考えていました。

同時に、未踏ジュニアに応募できる年齢制限が17歳までで、当時僕はすでに17歳だったため最後にチャレンジしてみたいと考えていて、丁度いい機会にそれを作って応募してみようとプロトタイプを制作し始めました。

プロトタイプ

僕自身は中学生のときからプログラムを書いていてアルバイトだったりもしてるのでコードはかなり書いていましたが、それでも応募まで数ヶ月しかない状態でプロトタイプを仕上げるのは結構厳しく(正直採択後よりも応募段階のほうが忙しかったかもしれない)明確にゴールを設定する必要がありました。

応募自体にはプロトタイプは必須ではなくプロダクトの概要を書いた書類を送れば良かったものの、採択されるには僕自身が持っている技術を示して最後まで作り上げることができることを証明する必要がありました。逆に、それを示せればどこが面白いのかは伝わると判断し診断できる項目は最低限に絞り、「修正の提案」はバッサリ捨てて、「URLを入力したら診断結果が出てくる」ところまでをやることにしました。あとは脳内のふわふわした概念をノートに書いてドメインモデルに落とし込み、一番慣れている技術スタックでコードを書き始めました。

応募時のプロトタイプのスクリーンショット
応募時のプロトタイプのスクリーンショット

大体2ヶ月くらいで動くプロトタイプが出来上がり、無事書類選考も通過しました。その後は面接を受けることになっていて、オンラインでメンター陣にプロダクトに関する質問を受けました。正直何を言ったかよく覚えていませんが、確かプロダクト自体が将来的にどういう目標があるかみたいなことを訊かれて、漠然とした回答しかできなかったのは覚えています...。

採択後

採択後は、既にプロトタイプがあったためアジャイルで開発しました。未踏ジュニアでは定期的にメンタリングを受けられることになっていて、僕のプロジェクトでは週に一度メンターに進捗を報告しフィードバックを頂いていたので、だいたい各週でマイルストーンを設けてそれまでに小分けにした機能の開発を進めました。

ユーザーに使ってもらうまでのタスクの優先順位は完全に僕の勘で「これができるようになったぞ」って言ったときのインパクトが強い順でやっていましたが、今考えるとあんまりいい方法ではなかったかなと思います。ただ、それがあったおかげでビジネスロジックには拘ってもフレームワークに関する細かいところを弄りすぎることはなくてスピードは上がっていた気がします。

インパクト重視な機能の例
インパクト重視な機能の例

初ユーザーテスト

未踏ジュニアでは期間中、採択直後と中間時点と最後の3回登壇する機会があり(今年はオンラインでしたが)、一回目のプレゼンの機会がやってきたので既にあるプロトタイプ+αの段階のものを発表しました。

その際に、その時点のものをデプロイしたURLを共有し聴いていた方たちに実際に使っていただいたのですが、dockerの共有メモリの設定をミスっていたり非同期にするべきところを同期でレスポンスしたいたりして発表直後にサーバーがダウンしてしまい、期待していたほどのフィードバックは得られませんでした (トホホ〜)

A11yが専門の方々へのインタビュー

期間の四分の一を過ぎたあたりでメンター陣のご協力もあり某社のアクセシビリティーチームの方にフィードバックしていただく機会を頂けました。

アクセシビリティーの現場でどんなプロセスが行われているのかや、どんなツールを使っているか、チーム開発特有の問題を伺うことができ、このインタビューでストーリーラインを具体化してユーザー層を絞ることができました。タスク優先度もここらへんから明確になってきたと思います。

その後の改善

未踏ジュニアでの2回目の発表(もちろん負荷対策はしました...)やTwitterのフォロワーなどを活用して、実際に使ってもらいアンケートに答えてもらうというフィードバックループを小分けに回しました。

フィードバックは「How to create a good survey」と検索して上に出てきた良いとされる質問をパクってフィードバック用のフォームをGoogle Formsで作成したものと、Google Analyticsのタグを埋め込んだもので多面的に得られるようにしています。

特にユーザーがどの情報を欲しがっているかは重視していて、例えば未実装の機能にもURLを割り振ってそのURLにどれくらいトラフィックが発生したかで機能の優先度を付けることで開発に反映しました。

Google formのスクリーンショット

詰まったところ

すげーニッチな内容かもしれませんが、開発にあたって詰まったところのメモを書いておきます。

CSSのDOMから取れる情報とASTのマッピングができない

HTMLやCSSなどのソースコードはブラウザでパースされたあとにDOMに変換されてJavaScriptから利用可能になりますが、getComputedStlyeなどのメソッドから取得できるCSSの情報からは、どのファイルや宣言が適用されているのかわかりません。

そこで、Google Chromeの開発者ツールのAPIである Chrome Devtools Protocol を使うことにしました。CDPはCSS.styleSheetAdded というイベントから読み込まれたスタイルシートの情報を取得できるため、問題検出時にNodeのIDと該当のCSSプロパティから対応するCSSファイルを探し出し、PostCSSのASTに変換して扱うことができました。

Clean ArchitectureでORMをどこに置くか問題

書籍では「Interface adapter層はframework層が必要としているデータ形式に変換するレイヤー」と説明されており、そのためSQLクエリを発行する部分は interface adapter層、それを具体的なRDBMSで実行するのはframework層という扱いになっているのですが、ORMではこの2つのプロセスの境界が曖昧で、ググっても色んな人が全然違うことを言ってるっぽかったです。

TypeORMは(もちろん限度はありますが)どのRDBMSを使うかが抽象化されていて、最終的にormconfigで決定するようになっているので、詳細について言及していないと割り切ってinterface adapter層でDALを実装することにしました。

余談ですが、ドメインモデルをAPIの形に変換するpresenterもGraphQLの定義を直接扱うのではなくpresenter側で定義した型を使うことで依存の方向を守っています。

モノレポ(Yarn Workspace)でDockerをやるのが辛すぎる

マイクロサービスとかだとモジュール同士が依存することはあんまり無いのかと思いますが、フロントエンドとバックエンドで共有するパッケージがあるみたいなケースでYarn workspaceとDockerを使いたくなってしまうと、パッケージごとにlockfileを作れなかったりnode_modules以下がシンボリックリンクになっているから単純にコピーしても動かなかったりして詰みます。

今の所ごちゃごちゃなワークアラウンドを書いてなんとか動いています。Yarn v2 (berry) では yarn workspace focus という機能が提供されて、ほしいパッケージの依存だけをインストールして独立して動かせるようになっているっぽいので早く移行したいなと思っているのですが、Plug'n'Play周りが理解しきれていないためまだ手を付けられていません。

styled-componentsが辛い

初めてちゃんとデザインシステム的なUIコンポーネントを作ったんですが、一つのコンポーネントが複数のバリアントを持ってるみたいなとき(下記)にstyled-componentsでやると可読性が最悪で最終的にTailwindに逃げました。

const Button = styled.button`
  font-size: 12px;

  ${
    (props) => props.variant === 'primary'
      ? css`
        color: ${props.theme.primaryFgColor};
        background-color: ${props.theme.primaryBgColor};
      `
      : css`
        color: ${props.theme.secondaryFgColor};
        background-color: ${props.theme.secondaryBgColor}
      `;
  }
`;

詳細: https://qiita.com/rigarashi/private/5c97be5ed8fb15ea2d96

Utilify-firstをCSS-in-JSに輸入したstyled-systemとかxstyledというやつもあるっぽいんですが、テーマの型が静的に付かなかったので見送りました。

Puppeteerで並列処理

puppeteer-clusterというライブラリがいい感じっぽかったのですが、unmaintained気味なのと、pageのインスタンスをコールバックで受け取って簡単な処理をすることしかできず、例えばObservableに変換するみたいな今回のユースケースだと厳しかったのでやめました。

代わりに、いわゆるObject Poolingでbusyなインスタンスとそうでないインスタンスを管理して、暇そうなインスタンスに処理を投げるようにしました。こういうのは多分ワーカープロセスをforkしていくのがいいのかと思いますが、Puppeteerを起動した時点ですでにChromiumのプロセスと分かれるのであんまり意味がなかったのと、GraphQLのsubscriptionのソースになっているのがただのシングルトンで、redisとかを挟んでなくて同じプロセスで呼ばないとブラウザに伝えられないためです。

あとがき

蔑ろにされがちなアクセシビリティーで人々の気を引くにはどうすればいいか考えた結果、若干地雷っぽいタイトルになってしまったことをお赦しください。

また、web版等公開していますのでぜひお試しいただきフィードバックをお訊かせいただけると嬉しいです。

関連リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(自分用)スムーズにいかなかった点と解決方法②

グラデーション色について

CSS グラデーションは データ型で表現され、2つ以上の色の間の連続的な変>化から成る の特殊型です。グラデーションは3種類から選択することができます。線形linear (linear-gradient 関数によって生成)、放射radial (radial-gradient 関数によって生成)、扇形conic (conic-gradient 関数によって生成) の3種類です。 repeating-linear-gradient, repeating-radial-gradient, repeating-conic-gradient の各関数によって、反復グラデーションを生成することもできます。
まずグラデーションは3種類から選択することができます。

① 線形 ⇨ linear-gradient
② 放射 ⇨ radical-gradient
③ 扇形 ⇨ conic-gradient    の3種類から選択できます。

グラデーション色の使用方法

グラデーションの最も基本的な形を作成するために必要なことは、2つの色を指定することです。これらは色経由点color stopsと呼ばれています。少なくとも2つ必要ですが、必要なだけの数を設定することができます。

.simple-linear {
background: linear-gradient(blue, pink);
}

2種類以上の色を()内に入力することでグラデーションが適用されます。

グラデーション色の方向の設定方法

to right 左から右へ

.horizontal-gradient {
background: linear-gradient(to right, blue, pink);
}

to bottom right 左上から右下へ

.diagonal-gradient {
background: linear-gradient(to bottom right, blue, pink);
}

70deg 70度の位置へ

.angled-gradient {
background: linear-gradient(70deg, blue, pink);
}

MDN

余談

自分の勉強用として投稿していますが、同じ問題に悩んだときに参考になれば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】初回ログイン時・jQueryを使用した、画面を真っ二つに割る方法

目標

split.gif

開発環境

ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

前提

【Ruby on Rails】初回アクセス時に一度だけ表示(jquery.cookie.js使用)
こちらに少し手を加えた形となりますので、
コードをそのまま使うとcookieがなくなるまでは表示出来ません。

実際のコード

app/views/layouts/application.html.erb
<div class="indication-left"></div> # 追加
<div class="indication-right"></div> # 追加
<div class="box">
  <p>下記の表示終了ボタンを押すと、<br>更新しても見ることは出来ません。<br>
    新しいブラウザを立ち上げると表示されます。
  </p>
  <button>表示終了</button>
</div>
app/assets/stylesheets/application.css
/* 追加 */
/* ここから */
 .indication-left, .indication-right{
  position: fixed;
  top: 0;
  width: 100%;
  height: 100vh;
  background-image: url("image1.jpg");
  background-size: cover;
  background-position: center;
  z-index: 1040;
  transition: 3s;
}
.indication-left{
  left: 0;
  clip: rect(0px 50vw 100vh 0px);
}
.indication-right{
  right: 0;
  clip: rect(0px 100vw 100vh 50vw);
}
.leftslide{
  transform: translateX(-100%);
}
.rightslide{
  transform: translateX(100%);
}
/* ここまで */


.box{
  position: absolute;
  top: 40%;
  left: 35%;
  width: 400px;
  height: 200px; 
  background-color: #ffffff;
  z-index: 1050; /* 変更 */
}
.box p{
    padding: 15px;
}
.box button{
  display: block;
  margin: 0 auto;
}
app/assets/javascripts/application.js
$(function(){
  $(".indication").show();
  if($.cookie('Flg') == 'on'){
    $(".box").hide(); // indicationの子ではなくなったので追加
    $(".indication-right").hide(); // 追加
    $(".indication-left").hide(); // 追加
  }else{  
    $(".box").show(); // 追加
    $(".indication-right").show(); // 追加
    $(".indication-left").show(); // 追加
  }
  $(".box button").click(function(){
    $(".indication-right").addClass("rightslide"); // 追加
    $(".indication-left").addClass("leftslide"); // 追加
    $(".box").fadeOut(); // 追加
    $.cookie('Flg', 'on', { expires: 1, path: '/' });
  });
});

z-indexについて

bootstrapを使用する場合、今回のような機能の実装では
.fixed-topよりも高い位置に表示する必要があったため、
1030より高い数値を指定しております。

bootstrap.css
.fixed-top {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 1030;
}

clip: rect( ); について

clip要素とは画像などの要素について、切り抜き領域の外にある内容を表示せず、
切り抜き領域を指定するプロパティです。
指定方法はrectととなり、rectの長さには
rect(上端からの距離, 右端からの距離, 下端からの距離, 左端からの距離)のように、
上から時計回りの順でコンマで区切って4つの値を指定します。

右側の画像clip: rect(0px 50vw 100vh 0px);
左側の画像clip: rect(0px 100vw 100vh 50vw);

まとめ

jqueryを使用せず、cssのinputを使用した方法もあるため、
両方の知識を入れておくのは大事だと思います。
近々更新できればと思います。

またtwitterではQiitaにはアップしていない技術や考え方もアップしていますので、
よければフォローして頂けると嬉しいです。
詳しくはこちら https://twitter.com/japwork

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む