webサイト制作の勉強|2020年4月クラス用ブログ

ファリカテクニカルアカデミーのwebサイト制作科の授業解説ブログです。フェリカテクニカルアカデミーは池袋にある求職者支援訓練の学校です。

.matchMedia()でjsをメディアクエリを使って条件分岐する

window.matchMedia

window.matchMediaというメソッド使用することでCSS側に記述するブレイクポイントの記述と同じような形でJS側の判定条件を記述する事ができます。


例 1000pxまではjsを有効にさせる

$(window).on('load resize', function(){
if(window.matchMedia('(min-width:1000px)').matches) {

1000pxまで有効にさせたいjavascript

}
});

ナビゲーションの場合

Toggleを使う場合、「:not(:animated)」を設定しないとボタンをクリックした回数分スライドしてしまうので、「:not(:animated)」の設定をしましょう。

$(window).on('load resize', function(){
if(window.matchMedia('(max-width:767px)').matches){
  //スマホの時の状態
    $('#g-nav').hide();//SPの時はnavを非表示にしておく
  }else{
  //タブレット・PCの時の状態
    $('#g-nav').show();//SP以外の時はnavを表示しておく
}
});

$('#btn').on('click',function(){
$('#g-nav:not(:animated)').slideToggle();
});

ユーザーエージェントでスマホかPCか判別してやる方法もあります

ユーザーエージェント

ユーザーエージェント(UserAgent)とはウェブサイトに訪問する際「Google Chromeからアクセスしています」「iPhoneからアクセスしています」などのどんな環境でアクセスしているのかの利用者の情報のことを言います。
ウェブサイトにアクセスする際にはこのユーザーエージェントを必ず送ることになっています。


今回のパターンはPC・タブレットであればjQueryを有効に。スマホiPhoneAndroid)であればjQueryを無効にします。
「!」エクスクラメーションマーク (exclamation mark)とは、Javascriptでは否定の意味で使われます。

if(!navigator.userAgent.match(/(iPhone|Android)/)){
$(function(){
//ここにjQueryの記述
});
}


逆にPC・タブレットであればjQueryを無効に。スマホiPhoneAndroid)であればjQueryを有効の場合

if(navigator.userAgent.match(/(iPhone|Android)/)){
$(function(){
//ここにjQueryの記述
});
}

また、PCであればjQueryを無効に。スマホiPhoneAndroid)とタブレットiPad)であればjQueryを有効の場合

if(navigator.userAgent.match(/(iPhone|iPad|Android)/)){
$(function(){
//ここにjQueryの記述
});
}


このように「|」で区切って自身でユーザーエージェントを追加する事も出来ます。

$.ajax(jQuery)とfetch APIを使ってsvgを外部ファイルとして読み込む

svgをcss3のアニメーションで動かす場合、下記のようにsvgファイルのコードをインラインでbody内に入れる必要があります。

<body>
<svg class="likeButton" width="500px" height="500px" viewBox="0 0 500 500">
  <circle class="explosion" r="150" cx="250" cy="250"></circle>
  <g class="particleLayer">
    <circle fill="#8CE8C3" cx="130" cy="126.5" r="12.5"/>
    <circle fill="#8CE8C3" cx="411" cy="313.5" r="12.5"/>
    <circle fill="#91D2FA" cx="279" cy="86.5" r="12.5"/>
    <circle fill="#91D2FA" cx="155" cy="390.5" r="12.5"/>

ただこのやり方だとbody内のソースの可読性が著しく下がってしまうので、svgタグ部分を外部ファイル化しajaxを使って非同期通信で読み込む方式に変更します。
ajaxで読み込めばbody内のソースも整理され、なおかつインラインの時と同じようにcsssvgをコントロールする事が出来ます。

<body>
<div id="box">
<!--ここ外部svgデータが挿入-->
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$.ajax({
url: 'logo.svg',//ここにsvgファイルのパスを入れる
})
.then(
// 1つめは通信成功時の処理
function(data){
	var svg = $(data).find('svg');
  $('#box').append(svg);
},
// 2つめは通信失敗時の処理
function(){
	alert('読み込み失敗');
});
</script>
</body>

Fetch APIを使ってsvgを呼び出す

JavaScriptの次世代の非同期通信の規格であるFetch APIを使用する事で、jqueryを使わずに非同期通信が行えるようになります。


フェッチ 【 fetch 】とは

ソフトウェアやネットワーク通信の分野では、データなどの受信側・需要側が(送信側・供給側から送られてくるのを待つのではなく)能動的に読み出しに行く、相手に送信するよう要求する、といった意味合いでフェッチという用語が用いられる。特に、送信側が能動的に送り出す「プッシュ」(push)方式と対比して、一定時間ごとに受信すべきデータの有無を繰り返し確認する受信側の動作を指す場合があり、「ポーリング」(polling)とも呼ばれる。

マイクロプロセッサ(CPU/MPU)では、命令を実行する最初の段階で、命令コード(インストラクション)をメインメモリ(またはキャッシュメモリ)から読み出し、プロセッサ内部のレジスタに転送する動作のことをフェッチという。フェッチされた命令デコード(解析)されて実行に移される。フェッチにかかる時間を「フェッチサイクル」(fetch cycle)あるいは「命令サイクル」(instruction cycle)という。

また、CPUやソフトウェアが将来必要になる(かもしれない)データなどを先取りして読み出しておくことで読み込み動作にかかる待ち時間を削減する手法が様々な分野で幅広く利用されており、そのような「先読み」方式のことを「プリフェッチ」(prefetch)という。

var box = document.getElementById("box")
fetch("logo.svg")
.then(function(response) {
    return response.text();
}).then(function(svg) {
    box.innerHTML = svg
})

jQueryでのcookieの指定

Cookie(クッキー)とは?

Cookie(クッキー)とは、ホームページを訪問した ユーザーの情報を一時的の保存する仕組み、またはそのデータです。ID、パスワード、メールアドレス、訪問回数などが ユーザー情報として保存されます。これによって再訪問したときに ユーザーを特定し、情報を入力する手間が省けます。ショッピングサイトに訪問したとき、すでにログイン状態になっている、以前カートに入れた商品がそのまま残っているのは、Cookie機能がはたらいているからです。


似たような機能でSessionという機能がありますが、Cookieはクライアント側にデータを保存するのに対して、Sessionはサーバー側に保存されてるため機密性の高いデータを扱う場合はSessionを使った方が良いでしょう。



github.com
※jquery2.2.4で動作確認済み



$(function(){
//jquery.cookie.jsの設定
if($.cookie('access')){
//既にアクセス済みの場合はカーテンを非表示
$('.svg-wrapper').css({'display':'none'});
}else{
//初アクセスの場合はカーテンをfadeOutさせる
$('.svg-wrapper').delay(5000).fadeOut(400);
}
//ファイルがロードされたら
$(window).load(function(){
$.cookie('access',$('body').addClass('access'));
});
});

sassを使ったシングルページ

1.sassを使ったページ作成
2.jqueryでカレント表示
3.srcsetを使って画像を差し替える
4.clip-pathを使った表現
5.AOSを使ったスクロールアニメーション
6.ajaxを使ってSVGアニメーションを外部ファイル化&クッキーを使って1回のみ表示
7.resizeイベントを使用したナビゲーション

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>sassを使ったシングルページ</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>
<div class="header_inner">
<h1>サイトタイトル</h1>
<p>タグライン</p>
</div>
<nav id="g-nav">
<ul>
<li id="list01" class="current"><a href="#content01">コンテンツ1</a></li>
<li id="list02"><a href="#content02">コンテンツ2</a></li>
<li id="list03"><a href="#content03">コンテンツ3</a></li>
<li id="list04"><a href="#content04">コンテンツ4</a></li>
<li id="list05"><a href="https://www.yahoo.co.jp/">外部サイトへ</a></li>
</ul>
</nav>
</header>

<div class="main">
<div class="key-visual">
<picture>
<source media="(min-width:1200px)" srcset="img/pc.jpg 1200w" sizes="1200px">
<source media="(min-width:960px)" srcset="img/pc.jpg 1200w" sizes="100vw">
<source media="(min-width:641px)" srcset="img/tab.jpg 960w" sizes="100vw">
<img media="(max-width:640px)" srcset="img/sp.jpg 640w" sizes="100vw">
</picture>
</div><!-- /.key-visual -->


<div class="box" id="content01">

<div class="box-inner">
<p class="photo" data-aos="fade-left"><img src="https://placehold.jp/3d4070/ffffff/600x400.jpg" alt=""></p>
<p class="txt" data-aos="fade-left" data-aos-delay="200">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr</p>
</div><!-- /.box-inner -->
</div><!-- /.box -->

<div class="box" id="content02">
<div class="box-inner">
<p class="photo" data-aos="fade-right"><img src="https://placehold.jp/3d4070/ffffff/600x400.jpg" alt=""></p>
<p class="txt" data-aos="fade-right" data-aos-delay="200">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr</p>
</div>
</div>


<div class="box" id="content03">
<div class="box-inner">
<p class="photo" data-aos="fade-left"><img src="https://placehold.jp/3d4070/ffffff/600x400.jpg" alt=""></p>
<p class="txt" data-aos="fade-left" data-aos-delay="200">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr</p>
</div><!-- /.box-inner -->
</div>
<div class="box" id="content04">
<div class="box-inner">
<p class="photo" data-aos="fade-right"><img src="https://placehold.jp/3d4070/ffffff/600x400.jpg" alt=""></p>
<p class="txt" data-aos="fade-right" data-aos-delay="200">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr</p>
</div>
</div><!-- /.box -->
</div><!-- /.main -->

<div class="curtain">
<p id="svg-logo-box">

</p>
</div>


<footer>
<a href="#" id="to-top">
<p class="to-top-btn">ページトップに戻る</p>
</a>
</footer>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="js/script.js"></script>
<script src="js/aos.js"></script>
<script src="js/jquery.cookie.js"></script>

<script>
$(window).on('load resize',function(){
if(window.matchMedia('(min-width:768px)').matches){
  AOS.init();
}
});
</script>
<script>
$.ajax({
url: 'img/logo2.svg',//ここにsvgファイルのパスを入れる
})
.then(
// 1つめは通信成功時の処理
function(data){
	var svg = $(data).find('svg');
  $('#svg-logo-box').append(svg);
},
// 2つめは通信失敗時の処理
function(){
	alert('読み込み失敗');
});

if($.cookie('access')){
$('.curtain').hide();
}else{
$('.curtain').delay(4000).fadeOut(400);
}

//ファイルがロードされたら
$(window).load(function(){
$.cookie('access',$('body').addClass('access'));
});
</script>

</body>
</html>
@import "_reset.scss";
@import "_aos.scss";


header{
width: 100%;
background:#FFF;
display: flex;
padding:0 20px;
position: fixed;
top: 0;
left: 0;
z-index: 100;
border-bottom: 4px solid  darkslategray;
.header_inner{
width: 40%;
>h1{
padding: 10px 0;
}
>p{
margin-bottom: 10px;
}
}
#g-nav{
width: 60%;
>ul{
display: flex;
justify-content: center;
>li{
height: 50px;
margin:0 10px;
>a{
display: block;
padding: 32px 0 18px;
text-align: center;
color: #006c6c;
font-weight: bold;
&::after{
display: block;
content: "";
width: 0;
height: 6px;
background-color: #006c6c;
transition:0.2;
}
}
&.current>a::after{
width: 100%;
}
}
}
}
}

.main{
padding-top:120px;
}

.key-visual{
max-width: 1200px;
margin: 100px auto;

img{
max-width: 100%;
}
}

.box{
height: 120vh;
clip-path: polygon(0 0,100% 0,100% 90%,0 100%);
&:nth-of-type(even){
background-color: darkslategray;
clip-path: polygon(0 10%,100% 0,100% 90%,0 100%);
}
.box-inner{
max-width: 600px;
margin: 0 auto;
padding-top: 160px;
position: relative;
>.txt{
width: 300px;
height: 200px;
padding: 20px;
background-color: darkslategray;
color: #FFF;
position:absolute;
right: -180px;
bottom: -50px;
}
}
&:nth-of-type(odd) .txt{
left: -180px;
background-color: #FFF;
color: #222;

}
}


.curtain{
width: 100%;
height: 100vh;
background-color: #FFF;
position: fixed;
top:0;
left: 0;
z-index: 1000;
}
#svg-logo-box{
width: 300px;
margin: 100px auto 0;
}
.svg-logo{
fill:#FFF;
stroke:#F90000;
stroke-width:2px;
stroke-dasharray: 640px;
stroke-dashoffset: 640px;
animation: logo-anime 1s 0.5s forwards linear;
}
@keyframes logo-anime{
0%{stroke-dashoffset: 640px;}
100%{stroke-dashoffset: 0;}
}




footer{
width: 100%;
height: 200px;
background:darkslategray;
}
.to-top-btn{
width: 50px;
height: 50px;
border-radius: 50%;
background:darkslategray;
border: 2px solid #FFF;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
position: fixed;
right: 60px;
bottom: 60px;
&::before{
display: block;
content: "";
width: 20px;
height: 20px;
border-top: 2px solid #FFF;
border-right: 2px solid #FFF;
transform: rotate(-45deg);
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}
}

script.js

$(function(){

//カレント表示
var div01 = $('#content01').offset().top;
var div02 = $('#content02').offset().top - 50;
var div03 = $('#content03').offset().top - 50;
var div04 = $('#content04').offset().top - 50;
//console.log(div03);

$(window).scroll(function(){
var posScroll=($(this).scrollTop());
//console.log(posScroll);
//0以上かつdiv02未満までは#list01に.current
//div02以上かつdiv03未満までは#list02に.current
//div03以上かつ#list04未満までは#list03に.current
//div04以上は#list04に.current
if(0<=posScroll && posScroll<div02){
$('#list01').addClass('current').siblings('li').removeClass('current');
}else if(div02<=posScroll && posScroll<div03){
$('#list02').addClass('current').siblings('li').removeClass('current');
}else if(div03<=posScroll && posScroll<div04){
$('#list03').addClass('current').siblings('li').removeClass('current');
}else if(div04<=posScroll){
$('#list04').addClass('current').siblings('li').removeClass('current');
}
});

//スムーススクロール
$('#to-top').on('click', function () {
$('html,body').animate({ scrollTop: 0 },200);
});
});

srcsetを使って画像を切り替える

img要素を画面幅によって切り替えたい場合、以前はJavascript等でwindow幅によって画像のファイル名を変える、などの方法が取られていましたが、html5.1,で策定された「srcset」を使う事で手間のかかるCSSJavaScriptを必要とせず、htmlのみでデバイスによって適切なimgが表示させられます。

srcsetとは

  • srcsetはHTML5で策定された新属性
  • この要素はブラウザのスクリーン要件(幅、高さ、ピクセル密度)に応じて、異なる画像を読み込む事ができる
  • IEでは使うことが出来ない(http://caniuse.com/#search=srcset)

picture要素

picture要素を使うと、画面解像度や画面幅、画像形式等に基づいて、開発者が任意の画像を出し分けることが可能です。
pictureタグは複数のsourceタグと一つのimgタグで構成されます。sourceタグには3つの属性を指定します。

  • media属性(メディアクエリ)
  • srcset属性
  • sizes属性
srcset属性

画像ファイルのパスと横幅は、imgタグのsrcset属性に記述します。「画像ファイルの横幅」は、「画像をウェブページ上で表示する際の横幅」では無く画像自体の横幅です。


sizes属性

表示する画像の横幅はsizes属性に記述します。メディアクエリーと組み合わせて複数の横幅を指定可能です。
例:ディスプレイ1200px以下の時は画面幅、それ以外では1200pxで画像を表示したい場合は次のように記述します。

sizes="(max-width:1280px) 100vw, 1280px"
レスポンシブイメージのソース

今回の仕様は

  • バイスの横幅が1200px以上の場合は1200px幅のpc用画像を画面中央に表示
  • バイスの横幅が1200px~960pxの間は1200px幅のpc用画像を画面画面一杯にフルードで表示。
  • バイスの横幅が959px〜641pxの場合は960px幅のタブレット用画像を画面一杯にフルードで表示。
  • バイスの横幅が640px以下の場合は640px幅のsp用画像を画面一杯にフルードで表示。

※imgにフルードイメージの設定を必ず指定

<body>
<picture>
<!--1200px以上の時に表示したい画像の指定-->
<source media="(min-width:1200px)" srcset="https://placehold.jp/2f90a8/ffffff/1200x350.jpg?text=pc 1200w" sizes="1200px">
<!--1199~960pxの時に表示したい画像の指定-->
<source media="(min-width:960px)" srcset="https://placehold.jp/2f90a8/ffffff/1200x350.jpg?text=pc 1200w" sizes="100vw">
<!--959~641pxの時に表示したい画像の指定-->
<source media="(min-width:641px)" srcset="https://placehold.jp/db4ca2/ffffff/960x450.jpg?text=tablet 960w" sizes="100vw">
<!--640px以下の時に表示したい画像の指定-->
<img srcset="https://placehold.jp/6edb4c/ffffff/640x450.jpg?text=sp 640w" sizes="100vw" alt="">
</picture>
</body>

レスポンシブイメージは便利な機能ですがIE11では非対応なので、IE対応必須という要件ではポリフィルを用います。


ics.media