こんにちは、フロントエンドエンジニアの権守です。
既にお気づきの方も多いと思われますが、こちらのテックブログは今月から装いを新たにしています。これは先日行った弊社コーポレートサイトのリニューアルに合わせたものです。
この記事では、今回行ったコーポレートサイトリニューアルについて実装面から紹介します。
特徴
今回のリニューアルの特徴は以下の3つです。
- Vue.jsによるSPA (Single Page Application)としての実装
- レスポンシブ対応
- アニメーションによるリッチな表現
それぞれについて詳しく紹介していきます。
Vue.js
Vue.jsはユーザーインタフェースを構築するためのJSフレームワークの1つです。Reactなどのフレームワークと同様にSPAの実装に使えますが、段階的に導入していくことも可能な点が特徴です。 その段階的に導入可能という点が、既存のサービスへの導入を容易にしていることもあり、弊社ではVue.jsを一部導入しています。現状、段階的に使っている上ではVue.jsは非常に便利という印象でしたが、今後、本格的に導入していく上でSPAフレームワークとしても満足のいくものであるかはわかりませんでした。 そこで、今回はVue.jsのSPAフレームワークとしての使い勝手を検証する意味も込めてコーポレートサイトの構築に全面的に導入しました。
Vue.jsの優れた点
結論から言うと、Vue.jsはSPAフレームワークとしても非常に便利であり、今後SPAを開発する際に弊社で採用する可能性は非常に高いと思います。 その判断に至った大きな要因は単一ファイルコンポーネントによる関心の分離のスマートさです。Vue.jsの単一ファイルコンポーネントでは、こちらで述べられている「関心の分離はファイルタイプの分離と等しくない」という理論の元、作られています。具体的には1つのファイルにテンプレート(HTML)・ロジック(JavaScript)・スタイル(CSS)の記述を可能としており、一貫性と保守性を高めています。 以下にコーポレートサイト内で用いている単一ファイルコンポーネントの例を示します。
<template lang="pug"> h1 {{title}} </template> <script> export default { name: 'heading', props: ['title'], } </script> <style lang="sass" scoped> @media (max-width: 1039px) h1 display: none @media (min-width: 1040px) h1 color: #333 text-align: center font-family: 'DIN' font-weight: bold font-size: 30px letter-spacing: 0.75px line-height: 200px </style>
上の例からテンプレート・ロジック・スタイルが1つのファイルに書かれていることがよくわかると思います。また、style部分にscopedと書かれていますが、これは単一ファイルコンポーネントが有するScoped CSSという機能を利用することを示しています。この機能を利用することで、そのコンポーネント内に記述されたスタイルが他のコンポーネントを汚染することを心配する必要がありません。それによってネームスペースを確保するためだけの余計なクラスを付与する必要もなくなります。これらの徹底した関心の分離はアプリケーションが大規模になるほど、より効果的になると考えています。
レスポンシブ対応
PC、タブレット、スマホといった具合にサイトを訪れる方のデバイスは様々です。それらのどれでアクセスしたとしても、弊社の魅力を最大限伝えられるように、レスポンシブ対応を全面的に行いました。
CSSのメディアクエリを用い、画面サイズによってPC用とモバイル用でスタイルを切り替えています。また、一部コンポーネントではモバイル版の中でもサイズによってレイアウトを2カラムから3カラムに切り替えるといったことも行っています。
CSSだけでなく、以前書いた記事で紹介した画像のレスポンシブ対応ももちろん取り入れています。
実際にどのようにCSSによるレスポンシブ対応をしているかの雰囲気がわかるように2カラムから3カラムに切り替わるコンポーネントのスタイル部分を示します。
<style lang="sass" scoped> article display: block overflow: hidden text-align: left .container position: relative width: 100% overflow: hidden img position: absolute top: 50% left: 50% -webkit-transform: translate(-50%, -50%) transform: translate(-50%, -50%) height: 100% margin: auto .blog display: inline-block color: #333 font-family: 'DIN' font-weight: bold &:hover text-decoration: underline time display: inline-block float: right color: #999 font-size: 10px .title display: block display: -webkit-box -webkit-box-orient: vertical -webkit-line-clamp: 3 overflow: hidden color: #333 text-align: left @media (max-width: 330px) article .title font-size: 10px line-height: 15px @media (min-width: 331px) and (max-width: 1039px) .title font-size: 11px line-height: 17px @media (max-width: 557px) article &:before padding-top: 153.62% width: calc(50% - 5px) @media (min-width: 558px) and (max-width: 1039px) article &:before padding-top: calc(100% + 90px) width: calc(33.3% - 6.66px) @media (max-width: 1039px) .meta padding: 0 3px 0 5px .blog font-size: 12px margin-top: 13px .title margin-top: 7px time margin: 14px 2px 0 0 article >a width: 100% height: 100% display: block position: absolute top: 0 left: 0 &:before display: block content: '' .container &:before display: block content: '' padding-top: 100% @media (min-width: 1040px) article width: 260px height: 310px transition: margin-top 0.25s ease-out &:hover margin-top: -20px .container height: 200px .blog font-size: 13px margin-top: 15px time margin-top: 15px .title font-size: 13px line-height: 20px margin-top: 9px </style>
また、このレイアウトが切り替わった際の要素の再配置部分はMasonryを用いて実装しました。CSSだけで実装しなかったのは、高さの異なる要素を縦方向に詰めて配置することができなかったからです。
アニメーションによるリッチな表現
今回のサイトデザインは、読みやすさを重視したシンプルなデザインな一方で、冷たい印象になりすぎないようにリッチなアニメーションを散りばめています。アニメーションの実装にはCSS3のアニメーションを中心に使いつつ、より複雑なアニメーションが求められる箇所ではD3.jsを用いました。 2つピックアップして実装について紹介します。
lazy-box
スクロールに応じて、コンテンツが出現するアニメーションをlazy-boxというコンポーネントとして実装しました。
<template lang="pug"> .lazy-box(ref="lazyBox" :class="{active: active}") slot(:active="active") </template> <script> export default { mounted() { window.addEventListener('scroll', this.handleScroll); this.handleScroll(); }, destroyed() { window.removeEventListener('scroll', this.handleScroll); }, data() { return { active: false, handleScroll: (e) => { if (window.innerHeight - this.$refs.lazyBox.getBoundingClientRect().top > 0) { this.active = true; } } } } } </script> <style lang="sass" scoped> .lazy-box opacity: 0 transition: opacity 2s, transform 0.5s @media (max-width: 1039px) transform: translateY(100px) @media (min-width: 1040px) transform: translateY(200px) &.active opacity: 1 transform: translateY(0) </style>
lazy-boxはVue.jsのコンポーネントのslot機能を用いることで任意のコンテンツに対してアニメーションを付与することが可能です。
D3.jsを用いたグラフ
RecruitページのグラフはD3.jsを使って実装しています。D3.jsはデータに基づいてドキュメントを操作するライブラリで、データ可視化によく用いられます。今回は、棒グラフとその数値のアニメーションの実装に用いました。 具体的には次に示すようなメソッドをVueコンポーネントのmethodsに設定し、コンポーネントがactiveになったタイミングで各メソッドを呼ぶようにしています。
methods: { barTransition() { var selection = d3.select(this.$refs.bar); selection .transition() .ease(d3[this.ease]) .duration(this.duration) .styleTween("width", () => { var i = d3.interpolate(0, '100%'); return function(t) { return i(t); }; }); }, valueTransition() { var selection = d3.select(this.$refs.value); var value = this.value; selection .transition() .ease(d3[this.ease]) .duration(this.duration) .tween("span", function(d) { var i = d3.interpolate(0, value); var self = this; return function(t) { d3.select(self).text(parseInt(i(t))); }; }); } }
まとめ
今回は、先日行った弊社のコーポレートサイトリニューアルについてその特徴と実装について紹介しました。 レスポンシブ対応をしっかり行ったので、画面サイズの変更やランドスケープモードへの切り替えなど、ぜひ色々試しながらVASILYのことを今一度知っていただけると幸いです。
最後に
VASILYでは、積極的に挑戦していけるエンジニアを募集しています。興味のある方は以下のリンクからぜひご応募ください。 https://www.wantedly.com/projects/61389www.wantedly.com