CSSでグリッチっぽい表現をやる

![jdIOWpguRq.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/11e29c66-970a-a64f-0a29-563e8dcdff26.gif)

[PIXIV TECH FES.](https://conference.pixiv.co.jp/2020/tech-fes) ← このサイトかなりカッコいいですよね（私は行けませんが…）（担当したのは@yui540です[^1]）

[^1]: https://twitter.com/yui540/status/1217733679021117440

CSSで文字を分割します、面倒くさいので構成は[Parcel](https://parceljs.org/)で行きます、JavaScriptは使いませんが現実的なところを考えると要ります（アニメーションの発火を制御するのにとか…）

```shell
yarn add parcel-bundler -D
npx parcel src/index.html
```

この記事は自分でも空でかける自信が無いので備忘録として書き残しておきます（アニメーションまでは面倒くさくなって書かないことになりました、書くのは文字分割までです）

# HTML

まずHTMLから

## 1
```html
<body>
  <div class="wrapper">
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
  </div>
</body>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/f2625104-13ee-5df8-3fef-d2a0e5cce140.png)[^2]

[^2]: https://twitter.com/_rotaren_/status/1126783024870244352

まずグリッチしたい要素（今回は`p`）を`.text-wrapper`で囲む
`.text-wrapper`を更に大きな`.wrapper`で囲む

## 2

```html
<body>
  <div class="wrapper">
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper"><p>そのツイート、切らせてもらう</p></div>
    <div class="text-wrapper placeholder"><p>そのツイート、切らせてもらう</p></div>
  </div>
</body>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/2bf519d0-2dad-3bd4-290d-7b86d47b2578.png)

`.text-wrapper`を`n + 1`個に増やす（`n`は分割する数です）、今回は10分割するので11個に増やします

最後の要素に`.placeholder`クラスを付与しておく（次からのCSSでの見通しが良くなるからです（使わない場合は`:nth-of-last-type`などでどうにか気合でやる））

# SCSS
forループとかを使うと一般化ができるのでかなり嬉しいのでSCSSで書く、リセットCSSなどでmargin等が消えている前提でCSSを書いていきます

## 1

```scss
.wrapper {
  position: absolute;
  top: 25px;
  left: 25px;
}
```

概略図
![mspaint_mK3RjqrKDt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/431adf21-afc9-aeab-56f4-c13e43d38919.png)

## 2

```scss
.wrapper {
  position: absolute;
  top: 25px;
  left: 25px;
}

.text-wrapper {
  font-size: 3rem;
}

.text-wrapper.placeholder {
  visibility: hidden;
}

.text-wrapper:not(.placeholder) {
  position: absolute;
  top: 0;
  left: 0;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/0a0afa64-3581-1f87-8a96-7afc4aa2ce12.png)

すべての`.text-wrapper`要素に必要なスタイルを当てる（文字をデカくする）

`.placeholder`要素は場所を取るだけの要素なので見えないようにしておきます

`.placeholder`以外の要素はすべて重ね合わせてある状態になっています

概略図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/0c57dd01-a33e-3beb-c569-760bc0a9403d.png)

## 3

```scss
.wrapper {
  position: absolute;
}

.text-wrapper {
  font-size: 3rem;
}

.text-wrapper.placeholder {
  visibility: hidden;
}

.text-wrapper:not(.placeholder) {
  position: absolute;
  top: 0;
  left: 0;
  width: 10%;
  height: 100%;
  overflow: hidden;
  & > p {
    position: absolute;
    top: 0;
    white-space: nowrap;
  }
  @for $i from 1 through 10 {
    &:nth-of-type(#{$i}) {
      left: ($i - 1) * 10%;
      & > p {
        left: -(($i - 1) * 100%);
      }
    }
  }
}
```

![A4imFr318C.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/dfb8405c-462d-eaa0-5053-4741b4a0cfda.gif)

気合で理解してほしいです

文字のような要素では`white-space: nowrap`を指定しないと改行されて壊れます

概略図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/bf6090ef-1c88-f7b0-e2de-c46658be3296.png)

## 4
```scss
.text-wrapper:not(.placeholder) {
  position: absolute;
  top: 0;
  left: 0;
  width: 10%;
  height: 100%;
  overflow: hidden;
  & > p {
    position: absolute;
    top: 0;
    white-space: nowrap;
  }
  @for $i from 1 through 10 {
    &:nth-of-type(#{$i}) {
      top: ($i * 25%); // ← ここで文字を斬る
      left: ($i - 1) * 10%;
      & > p {
        left: -(($i - 1) * 100%);
      }
    }
  }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/e09a89ed-5a3b-0b96-56a9-0fd4eded10c4.png)
 
おー斬れました　よかったですね

後は[mathsass](https://github.com/terkel/mathsass)などを使って乱数っぽく座標をずらしたりすると良いと思います（`29% * sin(1.7922rad * cos(1.9877777777deg * $i) + $i * .7rad)`など）、transform, translateなどを駆使して頑張って下さい

## 一般化
```scss
.text-wrapper:not(.placeholder) {
  $n: 30;

  position: absolute;
  top: 0;
  left: 0;
  width: (100% / $n);
  height: 100%;
  overflow: hidden;
  & > p {
    position: absolute;
    top: 0;
    white-space: nowrap;
  }
  @for $i from 1 through $n {
    &:nth-of-type(#{$i}) {
      left: ($i - 1) * (100% / $n);
      & > p {
        left: -(($i - 1) * 100%);
      }
    }
  }
}
```

# 作例

画像でも応用できる
![odFwwtFj7J.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/7e6ed222-82c7-2231-dda1-1e0dfedd0579.gif)

`transform: skew()`などをやるとかなり意味がわからない動きになってメチャクチャ面白い
![iM40d4seu6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107334/3e10b3b4-5bcf-b6fb-999e-9e78a4ac3564.gif)


以上です