2019/06/14 2019/07/07
ポートフォリオまとめサイト作成
まだ作った作品はとても少ないのですが
ひとところにまとめて置いておけた方がいいよね!ということで
ポートフォリオのまとめサイトを作成しました。
やっと置き場が出来てスッキリしました(*´ω`*)
これで毎回「あの作品どこに置いたっけ?あれお気に入りどこに入れた・・?」と
まるで片付けできない人間のような様相を繰り返さなくてすみますw
今回の目的
ポートフォリオって何なん?
プログラミング学習を始めてから、Twitterのタイムラインに飛び交う
「ポートフォリオ」なる言葉。
portfolio = 薄手の書類放り込んでおけるケース、だよな・・
自作?作って転職?何を言ってるんだこの人達は状態でしたマジで(;´Д`)
どうやらエンジニア界隈で言われているポートフォリオというのは
プログラミング技術を駆使して作った作品、もしくは
その作品をまとめて置いておく場所を指すようです。
これも人によって定義が違うのね・・専門用語は難しいのう(´・ω・`)
便宜的に、この記事では
ポートフォリオ: 作品そのもの
ポートフォリオまとめサイト: その作品をまとめて展示するサイト
と表記してあります。
ポートフォリオまとめサイト制作の目的
まずぶち当たる問題。
もう最初から就職!転職!フリーランス!!となってる人は
気にする必要もないんでしょうが
私、なにせ
- これまでの人生で就職活動すらしたことがない
(卒後研修義務化前の医師の場合、入りたい医局に見学に行って
秘書さんに履歴書渡して「国試受かったらお世話になります」と
挨拶したら行き先は決まってましたので・・) - そもそも就職する気は無い、むしろ体調的にまだ無理
(プログラミング学習を始めた当初はほぼベッド上安静生活
PC使えるのは1日2時間が限度でした) - そんなことより今は診断アプリを作りたくてだな(略
とまぁ、こんな状況でプログラミング学習を始めちゃったわけで
となるとポートフォリオまとめサイト制作の目的以前に
プログラミングを学んだ後、どうするのか?
を真面目に考えなきゃ何一つ前に動かないんですよねぇ・・(;´Д`)
で、年明けくらいから「今後の身の振り方」について考えた結果
- 体調が回復したらクラウドソーシングの案件を受ける
- 同時に自分でサービスを作って起業
- 今年1年は体調面含めて準備期間、更に言うなら後5年ぐらい
(息子が家を出るまで)は育児最優先
という結論に至りました。
全ては体調次第ってやつです。
育児最優先なのは、まぁ思想信条上の理由とでもしておきましょうか。
大分調子が良くなった、とはいえこれを書いている段階では
ひとつ作品を作るごとに数日ベッドに逆戻りする生活なので
フルリモートであったとしても継続的に作業が必要になる
就職やバイトというのは(現時点では)視野に入れていません。
出来なくは無いんだろうけどね
ひよっこだろうが駆け出しだろうが仕事する以上はプロですから
責任の取れない、言い訳のある状態で仕事を受けることはしたくないだけです。
ほら、救急外来に運び込まれて出てきたドクターが
「僕研修医だから上手く出来ないかもだけどごめんね」とか
言い出したら、「ごめんねちゃうわ!」ってなるっしょ?w
以上の前提を元に、今回のポートフォリオまとめサイトの制作目的は
- 将来案件に申し込む際必要であろう技術と情報を分かりやすく提示する
- これからビジネス用の作品と実験用の作品両方が出来てくるので
仕事や表に出すことを意識した作品と、実験作を分けて片付けておく
また技術面の目的として
- これまでjQueryで作っていたサイトの各機能を
Vue.jsで制作してテンプレ化、どっちでも使える様にする - 文章も自分の作品だよなぁ→外部ブログから記事一覧を引っ張ってきて載せる
- ちゃんと稼働するお問い合わせフォームの制作、テンプレ化
- 前回までの反省から、PC画面〜スマホ画面までの画面幅における
レイアウトの処理を考慮した設計を行う
こんな感じで目的を設定しました。
開発環境
- MacBook Pro (Retina, 15-inch, Mid 2015)
- MacOS Mojave (10.14)
- MAMP
- VSCode
- Sass(SCSS)
- Gulp とかWebpackとかbabelとか色々
- Vue.js (2.6.10)
- anime.js
- lodash
- vue-scrollto
- Adobe XD (カンプ作成用)
- CLIP STUDIO iPad版とApple Pencil (画像加工用)
- Gravit Designer(svg画像作成用)
制作過程
ワイヤーフレーム制作
はい、いつものやつです。
実際クライアントに提案するときはもうちょっと
きれいに書きますよ・・アナログだけど・・
相手に必要な情報を過不足無く、かつなるべくクリックやスクロールという
手間を少なくして届けることを考えた結果がこれ。
もうちょっとやりようはある気がするけど、今の私の解答ですな。
正直エンジニア目線で見たら
物足りないというかつまらないサイトじゃないかなぁ、とは思います。
ただ恐らくこれを見せる相手は
「ウェブカツに入る前の私レベルの知識を持ってる人すら少ない
ホームページが作れるの凄いね!ブログも作れるの!?な一般的感覚の皆様が大半」
と踏んでまして。
であれば
地味でも実用的な機能をサイトで見せて、こんなの作れるよ?と提示した方が
自分のサイトにもこういうのを付けたい・・と具体的に思い描けるし
かえって技術アピールになるんじゃないかな・・
という結論に至ったのです。
・・とは言いつつも一部目的外の趣味が入ってます。
別に見せたいわけでも無く、単に自分が満足するための機能ですw
機能洗い出し
いつも通り、この段階ではざっくり。
モック画面が出来上がる頃までに、具体的に何を使って機能を付けるかを決めていきます。
今回のサイトで付けようとしている機能は以下の通り。
- スクロールすると背景色が付くヘッダー
- スクロール量に応じてコンテンツをふわっと表示
- TOPへ戻るボタン実装
- 作品展示エリアでの切り替えタブ実装
- ブログ記事を何とかして持って来て表示
- アコーディオンメニュー
- お問い合わせフォーム
- SVGモーフィング
・・いっぱいあるなぁ・・(;´Д`)
基本的には「訪問者の利便性と自分のスキル提示を兼ね備えた機能」ですが
一番下のモーフィングは「一目惚れしたので趣味で付けたい」ってやつです。
まぁできるんじゃね?位のかるーい気持ちで書き出しております。
(この段階の作業時間: 30分+スキマ時間でちまちま調べ物)
デザインカンプ制作
XDで制作。
いつもながらイラストはCLIP STUDIOと
今回はベクター画像をsvg形式で保存したかったので
Gravit Designerを使用しています。
今回もカラーは「配色パターン集」からチョイス。
基本色3色に白黒グレーを組み合わせたシンプルなものです。
割と個人用のコンテンツはピンクを多用した
ぽえ〜んとしたイメージの物が多かったのですが(性格がそのまま出ているw)
今回は少し雰囲気を変えたい、ということで
主人と息子に相談した結果こうなりました。
しかしXDで制作したカンプをそのままコーディングしていくと
大抵
何でそんなに文字デカいの!!?
レイアウト微妙におかしくね?(;´Д`)
と叫ぶ羽目になりますので、大抵カンプ通りにはならず
コーディング段階で適宜修正するんですけどね・・
(この段階の作業時間: お絵描き含めて10時間)
画面モック制作
今回は
- トップページ
- プロフィール
- プライバシーポリシー
の3画面を作成します。
と言っても、プロフィールとプライバシーポリシーは
トップページの一部のデザインを流用。
更にHTML、CSS共にこれまで作ってきたサイトから抜き出した
スニペットがありますので、そこまで時間はかかるまい・・
と思っていたのに
そう言えばアコーディオンメニュー作るの初めてでしたね・・(;´Д`)
調べたらJSにしなくてもCSSで実装できるやーん!ここで付けたれ!
とか
ちょいまちSVG画像を背景で指定したらモーフィング出来なくね?
つまりレイヤーで重ねるような置き方するの?ってまたz-index効かねえぇぇぇ!!orz
(z-index効かせる要素にはpositionの指定が必要だったのを思い出した・・)
とか、まぁちょこちょこ引っかかったお陰で
結局いつもくらいの作業時間になってしまったのでした・・
グラデーション作成はこれを利用。便利すぎる。
(画面モック制作時間、PC版のみ: HTML3時間、CSS8.5時間)
機能実装(JS編)
anime.jsでSVGモーフィング実装
一番最初に、趣味で付けたかったSVGモーフィングを実装。
ヒーローバナーとフッター部分でもにょんもにょん波みたいに動いてるあれです。
色々調べた結果、anime.jsが一番使いやすそうという結論に至りました。
日本語の説明はこちら。
https://tr.you84815.space/animejs/
npm使ってanime.jsをインストール。
それをjsファイルで読み込んでおきます。
import anime from 'animejs'
で、動かしたいSVG画像を用意。
今回のアニメーションは2枚の画像をアニメーションで繋ぎますので
2種類の画像を用意しました。
で、ここを参考に付けようとしたら
https://tr.you84815.space/animejs/svg.html
おかしい・・うちのSVG画像にはpointsなんて要素が無いぞ・・
それ以前に<polygon>タグがねぇ・・(;´Д`)
調べてみたら、描画方法によってこのタグ違うんですね。
うちの画像の場合は<path>タグがこれにあたるようで、要素は’d’で表されてました。
なのでsvgタグにidを、pathタグにクラス名をつけて以下のように書きました。
anime({
targets: '#hero-bg .wave-below',
d: [
{
// 最初の位置と2枚目の位置データを配列で並べる
value: [
' M -23 -554.908 L -23 732.264 Q 157.628 590.187 421.987 656.849 C 550.032 689.137 831.927 783.43 983.976 745.484 C 1126.73 709.858 1241.692 614.846 1551.718 688.908 Q 1723.266 729.89 1943 717.196 L 1933.41 -554.908 Q 2.514 -564.145 -23 -554.908 Z ',
' M -23 -554.908 L -16 656.849 Q 142.366 738.945 294 757 C 594.101 792.733 595.031 657.801 827 630 C 1016.897 607.241 1090.265 712.414 1408 741 Q 1611.216 759.283 1934 662 L 1933.41 -554.908 Q 2.514 -564.145 -23 -554.908 Z '
]
},
{
// 最後の位置(今回は最初の位置と同じ)のデータを入れる
value:
' M -23 -554.908 L -23 732.264 Q 157.628 590.187 421.987 656.849 C 550.032 689.137 831.927 783.43 983.976 745.484 C 1126.73 709.858 1241.692 614.846 1551.718 688.908 Q 1723.266 729.89 1943 717.196 L 1933.41 -554.908 Q 2.514 -564.145 -23 -554.908 Z '
}
],
easing: 'easeInOutSine', // イージング
duration: 20000, // アニメーション間隔
loop: true // 無限ループ
})
ちなみに上の波画像だと、レイヤーが二つ(ピンクの波と青い波)なので
それぞれのレイヤー毎にこの記述をする必要があります。
これだけですんなり完成。アニメーション間隔やイージング選びに
こだわって時間かかったけど、やってみると案外簡単でした。
(SVGモーフィング実装: 2時間)
ページ内リンクでスクロール移動&TOPに戻るボタン
これは「vue-scrollto」を使いました。
https://www.npmjs.com/package/vue-scrollto
import Vue from 'vue'
import VueScrollTo from 'vue-scrollto'
// リンクのスクロール
Vue.use(VueScrollTo, {
duration: 600,
easing: 'ease-out'
})
これだけで、リンクを押すとスクロールして移動するようになります。
めっちゃ簡単(*´ω`*)
(この部分の制作時間: 30分)
Vue.jsでスクロールに応じて要素をふわっと表示する
jQueryではすでに付けたことのある機能をVue.jsで付けよう計画第一弾。
まずはスクロールしたらイベントが発火するように・・と思ったら
スクロールというイベント要素をまず作らねばならんのですね。
てわけでまずは公式見ながらグローバルにカスタムディレクティブを作成。
// カスタムディレクティブ(v-scrollを作る)
Vue.directive('scroll', {
inserted: function (el, binding) {
let f = function (evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f)
}
}
window.addEventListener('scroll', f)
}
})
ブラウザウインドウの高さも必要になるので、親のmethodに書きます。
こちらは負荷軽減のため、lodashをインポートして200ms毎に高さを取得することに。
ここでうんともすんとも言わなくて原因究明に30分。
methodsと書くところをmethodと書いてました・・orz
どうやらVue.jsあるあるらしいです。気をつけねば。
let app = new Vue({
data: {
// 高さのデータを規定
height: window.innerHeight
},
methods: {
// リサイズ時に高さを再取得
handleResize: _.debounce(function () {
this.height = window.innerHeight
}, 200)
},
mounted: function () {
window.addEventListener('resize', this.handleResize)
},
beforeDestroy: function () {
window.removeEventListener('resize', this.handleResize)
}
})
このheightはpropsを使って子コンポーネントへ渡します。
親のhtml側でv-bind:を使って渡して
<works v-bind:height="height"></works>
子コンポーネント側で受け取る。(propsな!propじゃないよ!!)
let works = {
data: function () {
return {
//省略
}
},
props: {
height: Number // 数値なので型をNumber縛りに
}
}
セクションタブにv-scroll:を書いて発火するようにして
子コンポーネントのmethodに要素表示のメソッドを書きます。
// 一定量スクロールしたら要素が出てくる
handleScroll: function (evt, el) {
// 基準となるセクション定義
let elementSection = document.getElementById('works')
let rectSection = elementSection.getBoundingClientRect()
// 上端からセクションまでの高さ
let distanceSection = window.pageYOffset + rectSection.top
// セクション上部が表示画面の下3分の1に
// 達したら要素を表示する
if (window.scrollY > distanceSection - (this.height * 2) / 3) {
el.setAttribute('style', 'opacity: 1; transform: translateY(0)')
}
return window.scrollY > distanceSection
},
これを全てのセクションに対して作って出来上がり。
この部分、保守性を考えると一つの関数にまとめた方が良いのですが
どうやらmixinを使うらしい、と言うところで詰まってしまったので
追々修正していく予定です。
(ヘッダーとセクションのスクロールイベント実装: 1時間半)
その他Vue.jsで実装したもの
最初は作品紹介の部分でスライダーを入れようとしたのですが
実際に入れてみたらどうも使い勝手が悪い・・ということで
機能を見直し、サムネイルをクリックすると概要が表示されるように。
今後作品が増えたら、サムネイル部分にスライダーを入れる予定です。
制作実績と試作品のタブ切り替え、サムネイルクリックで概要表示の部分は
前回作った診断アプリで実装した「v-forで実装してるリストをフィルタリングして表示」
機能をそのまま流用しています。
画面キャプチャ動画をアニメーションgifに変換するのは
これを使いました。
アニメーションPNGなんて形式があるのを初めて知りまして
そっちの方が品質良さげかな?と思って調べてたのですが
残念ながらIEとEdgeに対応してないようなので諦めてgifにしました・・
(この部分の制作時間: 2時間)
機能実装(PHP編)
Vue.jsで付けられる物は全て付けたので、続いてPHP機能を実装します。
まだフレームワークなるものは使えないので、生PHPです。
生って言うんですかね、この辺の言葉選びがとても素人ですな・・(;´Д`)
PHPで実装するのは
- お問い合わせフォーム
- head, header, footerを分割して見やすくする
- ブログ記事一覧表示
です。
てことでまずお問い合わせから・・と思ってPHPを書いてチェックしたら
動かないBrowser-sync
・・そう、これまでは「HTMLやCSSをいじって保存すると
自動的に作ってるサイトがブラウザで更新されて表示される」という
機能を使ってやってたんですね。
それが、ファイルを.phpにして書き始めた途端に動かない。
正確には、getできねぇ!と一言書かれただけのしろーいページが出てくる。
原因は未だ持って不明です。こういうものなんかもしれん。
てことで、ちゃんとアドレスを入れて表示しF5で更新することにしました。
解決法ご存じの方がいたら教えて欲しいですホント。
お問い合わせフォーム
P H P す っ げ ぇ 忘 れ て る ( ゚д゚)
いやー凄いわー
確かに最後にPHP書いたのは2月だから4ヶ月近く経ってるんですけど
こんなにきれいさっぱり忘れるのかよ・・と
画面を前に、いっそ清々しさすら感じつつ固まってましたw
お問い合わせフォームなんて何回も書いてるのに、覚えてたことと言えば
$_POSTが空じゃなかったら、変数に$_POSTの中身つっこんで
バリデーション・・必須入力してないとか
メール形式がおかしいとかどうやってたか忘れたけど調べて
それが大丈夫だったらまた変数にメールで送りたい物つっこんで
なんだっけ?メールなんちゃら?とかっての使って送って
ほんでThank youページへ遷移・・遷移あれどうやって書いてた・・?
・・これだけ!ww
いや、これだけでも残ってただけマシなのかもしれない、と思う事にしましたw
実際にはこの後、以前自分が書いたコードを見直して
「そうそうこうやるんだった、えらいなぁ2月の私」と自画自賛しつつ
実装していったんですけどねー。
一度自力で頑張ってれば、忘れてても意外とすんなりいくもんです。
で、今回の引っかかりポイント。
Vue.jsでセクション毎にコンポーネント化したのは良いのですが
いざエラー表示のためにtemplateの中にPHPタグを紛れ込ませると
タグがそのまんま出てきちゃう。
・・おぅ勝手にサニタイズされちゃうのね(;´Д`)
これ、結局解決法は分からず
PHPを利用するセクションはコンポーネント化せずに書くことで対処しました。
コンポーネントに入れてた「スクロールするとふわっと要素が出てくる」メソッドは
親の方へ移動させればうまいこと動きました(*´ω`*)
ちなみに今回の問い合わせフォームは
HTMLとPHP両方でバリデーションをかけてあります。
その方が良いとどこかで聞きかじったので・・
(お問い合わせフォーム制作、head,header,footer切り出し: 3時間半)
ブログ一覧をカードで表示
今回最大の難関、と思っていたところ。
このブログはサブドメインに置いてあって、ドメイントップに
今回作ったまとめサイトが入ります。
つまり同じドメイン上にあるサイトへ、ワードプレスのブログ一覧を表示する形です。
この場合は割と簡単だと言うことが発覚。
https://www.goodcircle.jp/blog834/
まぁ簡単とか言いながら、「あれPHPのforeach文書き方忘れてる・・」なんて
初歩的な部分をググりながらやる羽目になったんですけどね!orz
で、記事一覧は上手く出るようになったのですが
サムネイルが表示されない・・
正確には「アイキャッチを設定しているときのサムネイルだけ出ない」
謎の文字列が並ぶんですよ・・
何でだろ、と思って調べてみたら
違うっ・・!違うんだ・・!!
私が欲しいのはこんなコードじゃなくて
ただの「サムネイルの画像URL」だけなんだああぁぁぁ(´;ω;`)
てことで探した結果
https://web-diy.jp/2018/04/180416_01/
get_the_post_thumbnail_url こ れ だ !!
これで無事にサムネイル画像が表示されました。
imgタグでは無く背景で指定してあるのは
レスポンシブ対応でアスペクト比を保ったまま拡大縮小できるように
してあるためです。
<div class="p-panel--blog">
<?php if (has_post_thumbnail()) {
//サムネイルがあるときはそれを背景に指定
echo '<div class="c-panel__head--blog" style="background-image:url(' . get_the_post_thumbnail_url($post->ID, 'full') . ')">';
} else {
//サムネイルが無いときは用意した画像を背景に指定
echo '<div class="c-panel__head--blog" style="background-image:url(dist/img/noimage-eyecatch.jpg)">';
} ?>
</div>
(この部分の制作時間: 2時間半)
レスポンシブ対応
今回は768pxでスマホ用画面に。
worksの部分が案の定768pxまで縮小する間にレイアウト崩れを起こし
カンプのレイアウトから少しいじることになりました。
スマホ版は最初概要自体にスライダーを入れる予定だったのを
サムネイルを上に表示してそこで切り替える形に変更。
いずれこのサムネイル部分にスライダーを導入する予定です。
ハンバーガーメニューは外観とアニメーションについては
これまでに作った物を流用。
機能に関しては、Vue.jsでクリックする度にあらかじめCSSで指定した
クラスの付け外しをするmethodを書いてあります。
(レスポンシブ対応: 4時間)
デプロイ
いつも通り、必要なファイルをレンタルサーバーにアップしただけ。
相変わらずのSFTP接続です。
お問い合わせフォームは特にサーバー側で設定することも無く終了。
その他いくつか表示がおかしい部分を調整し
ファビコンとOGPを設定して完成です(*´ω`*)
OGPは毎回ここを参考にしています。
いい加減テンプレ化しよう・・
(この段階の制作時間: 1時間)
まとめと反省点と次回への展望
作業時間
- ワイヤーフレーム、機能洗い出し: 30分
- デザインカンプ作成: 10時間
- 画面モック(PC)とアニメーションを付ける: 11.5時間
- Vue.jsの機能を付ける: 6時間
- PHPの機能を付ける: 6時間
- レスポンシブ対応: 4時間
- デプロイ、実機確認: 1時間
合計: 39時間(約2週間)
結構時間かかってるなー
ただ思ったほどJSやPHPでは詰まらないなぁという印象。
逆にCSS・・お前めっちゃ時間かかるんじゃ・・(;´Д`)
こればかりは経験を積む(スニペットも増やす)しかないですかねぇ。
後ここには入っていませんが
コンテンツの中身を作るのに、というより
中身の構想にかなりの時間をかけています。
目的の達成度
技術面に於いてはほぼ達成。
このサイト制作の目的自体は・・まぁ今後見て下さる方の反応次第ですね。
今後も少しずつ修正していく予定です。
反省点
- やはりPC画面からスマホ画面までの移行部分でレイアウト崩れが起きやすいので、カンプ段階での設計が大事(特にボタンレイアウト)
- カンプを作る前にコンテンツの中身は書いておこう(今回カンプ作成とコンテンツの文章作成を同時に行ったため、途中でカンプの修正が必要に・・)
- CSSに時間かけすぎ。またクラス設計が途中から曖昧になる傾向があるので、カンプ終了後にクラス設計をしっかり行おう
- クラス設計に関して、utilityに配置した方が良い物を考慮する
- Vue.jsで書かれた部分、もっと保守性の高いコードに出来そう
今後の展望
- この制作ブログのテーマを、まとめサイトのデザインに合わせて作ります。
- 忘れかけているPHPをテーマ作りながら思い出して定着させたい
- その後Laravel学習へ
ソースコード
いつも通りGithubへ。
https://github.com/azumaya00/yuruknowledgelabo
次はワードプレスのテーマ作成。
あらかたデザインは決まっているようなものだし
多分そこまで時間かからないはず、多分な!!