ChatGPTでホームページのコーディングができるか試した


今(2022年12月時点)、超絶話題になっているChatGPTで遊んでいる。

Webデザイナーの知人と、AIの話をしていると
「Webページのコーディングくらいならできるのかな？」 
という話題になり、実際に少しやってみたという内容です。

## 検証したこと

- 基本的にコードの内容はChatGPTにすべて書かせる
- 動かすために最低限必要なサポートは人間（自分）がやってよい
- 対話だけで適当なWebサイトのTOPページを作る

## 実際のやりとり

最初に以下のような大枠を作る指示をしてみる。何が出てくるか。

```text
企業の公式WebサイトのTOPページのためのindex.htmlを用意します。

- サイト名は株式会社hoge
- ヘッダー部分はサイト名とグローバルナビゲーション
- グローバルナビゲーションはAbout, Service, Contactへのリンク
- フッター部分はコピーライト表記
```

以下は実際に出力された結果のスクリーンショット

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/fca35d86-acac-8d34-f096-b87424c522e7.png)


怖いです。
最初の最初で100点満点のコードが出てきました。

ChatGPTの恐ろしいところは、このセッションが終わるまではコンテキストを保持するので、このコードに対して追加の要望をしていくことでどんどん仕上げていくことができます。

試しにfooterに公式twitterとfacebookへのリンクを入れてみましょう

```
footerに企業公式TwitterとFacebookへのリンクを追加。
```

以下のような差分を得られました。
ほぼ意図通りのコードです。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/3722d7b0-c97d-96db-f0cb-ff76db44bc5c.png)


ではこれにstyleを当てます。次のように指示をしてみました。

```
このhtmlにstyleを当てます。
headerは左にロゴ、右にグローバルナビゲーションを配置し、ブルーの背景と白いテキストで。
footerは中央にコピーライト、右に公式snsのリンクを配置します。
グレーの背景と濃いグレーのテキスト色。
```

得られたコードのcss部分が以下

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/43694301-2cd8-4dca-455f-ca935868fefd.png)

![web00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/6c443837-c39c-b1c1-dd1d-aac19abd0324.png)



styleが追加されました。これだけで驚きではあるのですが、ちょっと物足りない見た目ではあります。
対話を通じて、可能な限り修正を試みます。

```html
headerを修正します

- タイトルはh1 > a の形でリンクを追加。
- グローバルナビゲーションは横並び。テキストの色は白
- header内のaのカラーを白字にする
```

最終的にこのようになりました。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/88974cc7-c675-231a-dc38-4e7f104b1ce7.png)

この時点での見た目はこちら

![web0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/d73f6399-53d2-9c7c-ae76-46380a5075c1.png)


そういえばreset.cssを当てていないので隙間ができています。

以下のようにオススメのreset.cssを聴いてみました。

```html
このhtmlにreset.cssを当てたいです。オススメのreset.cssを教えて下さい。
```

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/48ee4171-4b02-b3a3-0be7-8caf0ff509ce.png)


予想よりいろいろと教えてくれました。

現状のベストプラクティスなのか？はさておき、ものすごくそれっぽい内容ですね。
注意点として、結構平気で大嘘を混ぜてついてくる事があるので、内容はかなりちゃんと検証する必要があります。
（ちなみに1番下はリンク切れ（そもそも存在していない？）でした。）

せっかくなのでオススメしてくれたものを適用してみます。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/69fc50f7-17fe-2b9c-7030-d45a5d6b40ee.png)

linkでロードしてくれました。resetが適用されてキュッとしまりました。
見た目は以下。

![web1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/2a40c032-3555-3cb4-4cb1-41ad98acc0df.png)


読みづらいので適当なpaddingを入れたいです。

```html
headerとfooterが読みづらいので適当なpaddingをつけてください。
```

`「読みづらい」` や `「適当な」` のような抽象的で不明瞭な言葉を使って指示してみました。
が、これも難なく対応してくれました。

![web2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/12bd448a-d909-9a79-fbae-a5782fca7525.png)


ではちょっと実装難易度の高いパーツを追加してみましょう。

メインヴィジュアルによくあるスライドショーのパターンを試してみます。

これをどう言語化すればよいのか難しいですが、ひとまず以下のように指示を出してみます。

```html
headerの次にキービジュアルのコンポーネントを配置します。
キービジュアルはカルーセルスライダーになっていて、3枚の画像を配置します。
next, prev ボタンでスライダーを変える処理、画像上の中央下部の位置にページャーを配置し
現在アクティブなスライドが何枚目かが分かるように色で表現します。
```

すると初めて「ごめんなさい」が帰ってきました。


![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/d82ee3bf-3245-f9f2-61e8-59727f87d92a.png)



ただ恐らくこれは聴き方が悪いので以下の書き方に変えてみました。

```html
キービジュアル3枚を表示するスライダーコンポーネントをhtml/css/jsで作ります。
以下仕様を満たすコードだけを作成してください。

- 3枚の画像をスライダー表示
- next, prev ボタンがあり、これらをクリックで表示する画像を切替える
- 現在アクティブなスライドが何枚目かが分かるページャー

```

得られた最終的なコードが以下。
（実際には文字数制限があるらしく、何度か細切れに取得できたものをつなげた）

```html
<!DOCTYPE html>
<html>
<head>
  <title>株式会社hoge</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
  <style>
    header {
      background-color: blue;
      color: white;
      display: flex;
      justify-content: space-between;
      padding: 10px;
    }

    header a {
      color: white;
    }

    footer {
      background-color: #cccccc;
      color: #444444;
      text-align: center;
      padding: 10px;
    }

    footer p:last-child {
      text-align: right;
    }

    nav ul {
      display: flex;
    }

    nav li {
      list-style: none;
    }

    .slider {
      position: relative;
      width: 100%;
      height: 400px;
      overflow: hidden;
    }

    .slider .slides {
      position: absolute;
      width: 100%;
      height: 400px;
      top: 0;
      left: 0;
    }

    .slider .slides img {
      width: 100%;
      height: 400px;
      object-fit: cover;
    }

    .slider .pager {
      position: absolute;
      bottom: 10px;
      left: 50%;
      transform: translateX(-50%);
      display: flex;
    }

    .slider .pager .page {
      width: 10px;
      height: 10px;
      margin: 0 5px;
      border-radius: 10px;
      background-color: #cccccc;
      cursor: pointer;
    }

    .slider .pager .page.active {
      background-color: blue;
    }

    .slider .controls {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      width: 100%;
      text-align: center;
    }

    .slider .controls button {
      background-color: transparent;
      border: none;
      color: white;
      font-size: 36px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <header>
    <h1><a href="index.html">株式会社hoge</a></h1>
    <nav>
      <ul>
        <li><a href="about.html">About</a></li>
        <li><a href="service.html">Service</a></li>
        <li><a href="contact.html">Contact</a></li>
      </ul>
    </nav>
  </header>

  <div class="slider">
    <div class="slides">
      <img src="image1.jpg" alt="image1">
      <img src="image2.jpg" alt="image2">
      <img src="image3.jpg" alt="image3">
    </div>
    <div class="pager">
      <div class="page active"></div>
      <div class="page"></div>
      <div class="page"></div>
    </div>
    <div class="controls">
      <button class="prev">&lt;</button>
      <button class="next">&gt;</button>
    </div>
  </div>

  <footer>
    <p>Copyright © 2022 株式会社hoge</p>
    <p>
      <a href="https://twitter.com/hoge">Twitter</a>
      <a href="https://facebook.com/hoge">Facebook</a>
    </p>
  </footer>

  <script>
    const slider = document.querySelector('.slider');
    const slides = document.querySelectorAll('.slides img');
    const pager = document.querySelector('.pager');
    const pages = document.querySelectorAll('.page');
    const prevBtn = document.querySelector('.prev');
    const nextBtn = document.querySelector('.next');

    let currentIndex = 0;
    let slidesLength = slides.length;

    const changeSlide = (index) => {
      currentIndex = index;
      slides.forEach((slide) => (slide.style.display = 'none'));
      slides[currentIndex].style.display = 'block';
      pages.forEach((page) => page.classList.remove('active'));
      pages[currentIndex].classList.add('active');
    };

    const prevSlide = () => {
      if (currentIndex === 0) {
        changeSlide(slidesLength - 1);
      } else {
        changeSlide(currentIndex - 1);
      }
    };

    const nextSlide = () => {
      if (currentIndex === slidesLength - 1) {
        changeSlide(0);
      } else {
        changeSlide(currentIndex + 1);
      }
    };

    // スライドの切り替え
    prevBtn.addEventListener('click', prevSlide);
    nextBtn.addEventListener('click', nextSlide);

    // ページャーをクリックしたときのスライド切り替え
    pager.addEventListener('click', (e) => {
      const pageIndex = Array.from(pages).indexOf(e.target);
      if (pageIndex >= 0) {
        changeSlide(pageIndex);
      }
    });

    // スライドの自動切り替え
    let interval;
    const autoSlide = () => {
      interval = setInterval(nextSlide, 3000);
    };
    autoSlide();

    // スライドがマウスオーバーされたときの自動切り替えの停止
    slider.addEventListener('mouseover', () => {
      clearInterval(interval);
    });

    // スライドがマウスアウトされたときの自動切り替えの再開
    slider.addEventListener('mouseout', autoSlide);

  </script>
</body>
</html>
```

（画像は [unsplash.com](http://unsplash.com/) でお借りしたものを🙏😺）

ちゃんと動くコードができてしまった。


![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274832/bcc8168e-0238-93e2-a6ca-03111a1092cc.png)

実際にはもっと感じを良くしないとダメだが、このあたりも言葉で伝えたり、具体的なライブラリ名を渡して組み込んでもらったりすることができる。
これをこのままプロダクションで使える品質とは言わないが、本当にほしい品質の要件さえ伝えられれば、もちろん本番使用に耐えうる品質に上げていくことも可能そうだ。


## まとめ

時々意図しない、良くないコードが出てくる場面はあるものの、こちらの目線で品質だけチェックしつつ、AIの解釈しやすい言葉を渡すことができれば、Webページのコーディングのアシスタントとして、ものすごい便利に使っていけそうだと感じる。

これは正直かなりの衝撃を受けた。

AIは、要件がはっきりしている定番の設計の時ほど、素早く正解をサジェストしてくれるので、（特殊でクリエイティブなコードそ除き）そういうコードはAIに書かせてしまって良いかもしれません。

## 今後の予想？

今回はかなり記事化するためにゆっくり進めたが、これは少し工夫すれば声で入力して、リアルタイムでコードに反映が可能なので、本当にAIに口頭指示をしながらあっという間にコーディングができるようになる日がすぐだと感じる。

AIの成長は指数関数的と言われているので、webのコーディングは人間が書かない日が結構近いかもしれません🧠