Web作ってる（html,css,js,php）

## はじめに
初めまして、ひつじです。
初投稿がこんなのでいいのか不安ですが、最後までお付き合いいただけると幸いです。

さて、巷では○○jsが流行っていますが、そんなの使いません。php,html,css,jsでやります。
今回はこのサイトを作っていくうえで思ったこと、使ったことなどなどを、php,html/css,jsについて一つずつコメントします。

## 本編
### どんなサイトを作ってる?
ブルーアーカイブの二次創作ページを構築中です。（ファンページと言っていいのかは微妙。）
コンセプトはキヴォトス教育委員会。いろいろ言うより見た方が早いということで、現状のサイトが[こちら](http://kivotosboe.net)

作ってる途中なのでまだまだ未完成で不完全です。許してください。
### addEventLinsterで困った（js）
#### 困ったポイント１
jsで要素の幅を取得すると、その値がnullになっちゃうこと。
要素が読み込まれる前に要素幅を取得しようとするからnullになっちゃう。解決方法は簡単でした。'DOMContentLoaded'を使って読み込まれたときに発火するようにすればいいです。
```js
document.addEventListener('DOMContentLoaded', () =>  {
    // ここに処理を入れる
}
```
ってすればOKです。
#### 困ったポイント2
画面幅に応じて可変的に要素幅を変更したい...ので、こんな感じにしてみました。
```js
window.addEventListener('resize', () => {
    const dt = document.querySelectorAll('.news-child-img > a time');
    const du = document.querySelectorAll('.news-child-img > a h4');
    const dtH = dt[0].getBoundingClientRect().width;
    dt.forEach(elm => elm.style.fontSize = `${dtH*0.9}px`);
    du.forEach(elm => elm.style.fontSize = `${dtH*0.15}px`);
    // 続く
}
```
が、うまくいかないときがある。
基本的に要素のサイズを変えてくれましたが、ブラウザの最大化をすると発火していなそう...はて、どうしたものか...
解決法思いつかず...どなたかよい方法あれば教えてください...！
今現状はとりあえず何とかしてます()。

### 共通するものは流用しよう（php） 
タイトルの通り。react/○○jsでやるやつです。コンポーネント化しようのphp番的な感じ。~~(react/○○jsの方が...)~~ phpのfunctionで共通するやつをまとめて作っちゃって、functionを読ませることでコードを書かずに済む、と。
headerやfooterがいい例ですね。header.php/footer.phpをincludeやrequireして読み込ませること、多いと思います。あるいはWordPressみたく関数で定義して読み込んだり（今回はこちらでやりました。）

それを共通して使うところ全部でやる。

例えば画像を表示させる関数：
<details><summary>php</summary>

```php
function img($src,$alt,$addInfo=null){
    global $root;
    if(preg_match('/^https?:\/\//', $src) === 1){
        return'<img src="'.$src.'" alt="'.$alt.'"'.$addInfo.'>';
    }else{
        $extension = pathinfo($src)['extension'];
        $src = preg_replace('/\.([a-zA-Z0-9]+)$/', '', $src);
        $avif = (file_exists($root.$src.'.avif')) ? $src.'.avif': false;
        $webp = (file_exists($root.$src.'.webp')) ? $src.'.webp': false;
        $plane = (file_exists($root.$src.'.'.$extension)) ? $src.'.'.$extension: '/com/assets/img/noimg.png';
        $img = '<img src="'.htmlspecialchars($plane).'" alt="'.htmlspecialchars($alt).'"'.htmlspecialchars($addInfo).'>';
        if($webp !== false || $avif !== false){
            $add1 = ($avif !== false) ? '<source type="image/avif" srcset="'.htmlspecialchars($avif).'">': '';
            $add2 = ($webp !== false) ? '<source type="image/webp" srcset="'.htmlspecialchars($webp).'">': '';
            return '<picture>'.$add1.$add2.$img.'</picture>';
        }else{
            return $img;
        }
    }
}
```

</details>
これは画像のリンクとaltを渡したらいい感じにしてhtmlを返します。webp,avifがあるかないかでコードを変えなきゃいけないのは面倒なので、phpでファイルの存在確認をして、あるなら表示、ないなら非表示、何もないなら別画像を表示させるようにしただけです。
webp,avifなどがあればそちらを優先して、なければそのまま指定された画像を表示させます。もし、指定した画像すらなければnoimg.pngを表示させます。覚えるのも書くのも面倒なのが、関数にすればすごく楽に書けますね。

と、実はここで一つ悩んだことがあります。
それはコンテンツをreturnで返すかechoで表示させるか、です。
それぞれで関数を作って表示させるには次のようにします。
```php
function hoge(){
    return 'content1';
}
function nya(){
    echo 'content2';
}

echo hoge();
// content1
nya();
// content2
```
結論から言うと使い分けをすることにしました。
headerやfooterのように基本的にそれを表示させるだけ、の場合はechoで、そうでない場合はreturnで返すことにしました。returnで返せば関数の中に関数をぶち込めるので楽なんですよね。でもheaderみたいなのはいちいちechoって書くのが面倒で...
なのでその関数の機能によって使い分けしました。

**悩んだらreturnでいいと思います。**


[このサイト](http://kivotosboe.net/news/)では基本的にこの関数を使って画像を表示させています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957354/68ed0be1-2748-5b90-d0c2-6e100cbd9178.png)

### clip-path, ::before, ::after は神！だけど...（html,css）
cssを扱ったことがある人ならそう思いますよね（圧）

::before, ::afterは疑似要素です。文字通りそれがついた要素の前/後にコンテンツを追加します。
こいつらを使うときは必ず指定しなきゃいけないものがあります。
これです
```css
.hogehoge::before{
    content:''; /* これ必須 */
}
```
何も入れる必要がなくても、contentを指定しないと表示されません！（これ忘れてて何時間無駄にしたか...）
もちろん文字を入れたらその文字が入ります。
```css
.hoge::before{
    content: '〇+×△;
}
```
これで指定したのが下の画像の左上のところになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957354/603594a9-2ebb-16e0-6dae-cc6e0ccfe5a7.png)

before/afterのメリットとしてはhtmlがすごい深くならないこと、同じ要素に関連付けして配置できることがあるかな。デメリットはぱっと見で分かりづらいこと。
例えば上の画像の折り返しているように見えるところ（灰色の三角形）は::afterで配置しています。折り返すところまでセットで一つの要素ですよね。〇+×△も::beforeで配置しています。これも要素の一部になりますもんね。（要素を分けないときに使うといいかも）
逆に、要素を分けた方がいい時にbefore/afterは使わない方がいいです。そりゃそうだ。

clip-pathは要素を切り抜いてくれるやつです。
今回はクリップや折り返し、一番外枠の形作りをclip-pathで作りました。svgでもいいじゃん...その通り。だけど使ってみたかったんです。
あとこいつ癖がある。clip-pathで切り抜いた要素にbox-shadowがうまくつきません。borderもうまくつきません。そして書きにくい/読みにくい。 ~~使うメリットねぇじゃん！~~ 
こいつのうれしいところは要素から子要素がはみ出したとき、clip-pathで切り抜いたところで切れること。つまり、clip-pathの外側に子要素が出ないことですね。（overflow:hiddenしてね）
複雑な図形の中に文字を収めたいときとか、役に立つかもしれないです！

<details><summary>html</summary>

```html
<div class="section">
    <div class="section-in">
        <div class="section-cont-out">
            <h2><span>This is タイトル</span></h2>
            <div class="section-cont">コンテンツ</div>
        </div>
    </div>
</div>
```

</details>
<details><summary>css</summary>

```css
.section{
    position: relative;
    box-sizing: border-box;
    width: 100%;
    height:  auto;
    margin: 2rem 0;
    padding: calc(20px + 3rem) 20px 20px;
    border-right: 1px #888 solid;
    border-bottom: 1px #888 solid;
    background-color: #fff;

    clip-path: polygon(0 0, 0 100%, 100% 100%, 100% 2rem, 8rem 2rem, 7rem 0);
}
.section-in{
    position: relative;
    overflow: hidden;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    padding: calc(20px + 3rem) 20px 20px;
    border: 1px solid #000;
    background-color: #fff;

    clip-path: polygon(0 0, 0 100%, calc(100% - 3rem - 2px) 100% ,100% calc(100% - 3rem - 2px), 100% 0);
}
.section::before,.section::after,.section-in::before,.section-in::after{
    position: absolute;
    z-index: 0;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    content: '';
}
.section::before{
    padding: 0.5rem 1rem;
    content: "〇＋×△";
    color: #08f;
    background-image: linear-gradient(-50deg, #00000000 3rem, #0088ff33 3rem 8rem, #00000000 5rem, calc(100% - 8rem), #0088ff33 calc(100% - 8rem) calc(100% - 3rem), #00000000 calc(100% - 3rem));
    font-size: 1.2rem;
}
.section::after{
    z-index: 1;
    width: 3.5rem;
    height: 1rem;
    transform: translate(2rem,4rem) rotateZ(60deg);
    border: 0.3rem solid #08f;
    border-radius: 1rem;

    clip-path: polygon(0 0,0 100%,0.99rem 100%,1.16rem 80%,1.5rem 80%,1.5rem 100%,100% 100%,100% 0);
}
.section-in::before{
    box-sizing: border-box;
    padding: calc(30px + 3rem) 30px 30px;
    content: '';
}
.section-in::after{
    background-color: #888;

    clip-path: polygon(calc(100% - 3rem) 100%, 100% calc(100% - 3rem), calc(100% - 3rem) calc(100% - 3rem));
}
.section-cont-out > h2 {
    position: relative;
    width: fit-content;
    margin: 0 auto;
    transform: rotateZ(-5deg);
    white-space: nowrap;
    font-size: 3rem;
}
.section-cont-out > h2 span {
    position: relative;
    padding: 1rem;
    background-color: #ffe300;
}
.section-cont-out > h2 span::before{
    position: absolute;
    z-index: -1;
    right: 0.5rem;
    bottom: -0.2rem;
    width: 80%;
    height: 50%;
    content: "";
    transform: rotateZ(5deg);
    background-color: #888;

    filter: blur(4px);
}
.section-cont-out{
    position: relative;
    width: 100%;
    height: 100%;
    box-shadow: 0 0 5px #00000033;
}
.section-cont{
    box-sizing: border-box;
    height: calc(100% - 6rem);
    margin-top: 2rem;
    padding: 1rem;
}
```

</details>

## まとめ
最後まで見てくれてありがとうございます！
アドベントカレンダーに参加したくて書いたけど、結局gdgdになっちゃいました。ごめんなさい。
なんだかんだでreactとか楽やなぁ...って思いました。
何かあれば都度updateしていきます。

次はファイルサイズを小さくしよう！って記事を書きたいなって思いました。はい。