FlaskのWTFormsで作成したフォームにCSSを適用させたい！

# はじめに
FlaskのWTFormsでフォームを作成するとCSRF対策が簡単にできるため便利。
ただ、元のフォームは見栄えがシンプルすぎるのでCSSを適用させよう！という記事です。

# 初期段階
### 画面
![元のフォーム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653241/69d3534f-8788-e6bc-313c-cd9b090947db.png)

### ソースコード
``` forms.py
class CreateVoiceForm(FlaskForm):
    title = StringField('タイトル： ', validators=[DataRequired()])
    voice = TextAreaField('内容： ', validators=[DataRequired()])
    picture_path = FileField('ファイルアップロード', default='')
    submit = SubmitField('ボイス投稿')
```

``` index.html
<form method="POST" enctype="multipart/form-data">
    {{ form.csrf_token }}
    {{ render_field(form.title) }}
    {{ render_field(form.voice) }}
    {{ render_field(form.picture_path) }}
    {{ form.submit() }}
</form>
```

# 結論
- `{{ render_field(form.title) }}`は初期状態で`<input id="title" name="title" type="text" value="">`となっているため、idを指定してCSSを適用する
- placeholderなどは、フォームを定義している箇所で`render_kw=` を使用してレンダリングキーワードを設定する
    - 例）`title = StringField('', validators=[DataRequired()], render_kw={"placeholder": "タイトルを入力"})`

# 適用例
https://form.run/media/contents/form-creation-tools/contact-form_design/
こちらの記事を参考に、自分で少しいじってみました。

### 画面
![変更フォーム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2653241/3e04c597-437c-e469-6661-baf07080ba48.png)

### ソースコード
```forms.py
class CreateVoiceForm(FlaskForm):
    title = StringField('', validators=[DataRequired()], render_kw={"placeholder": "タイトルを入力"})
    voice = TextAreaField('', validators=[DataRequired()], render_kw={"placeholder": "本文を入力"})
    picture_path = FileField('', default='')
    submit = SubmitField('ボイス投稿')
```

```index.html
<form method="POST" enctype="multipart/form-data">
        {{ form.csrf_token }}
        <div class="form_item">
            <p class="form_item_label">
                <span class="form_item_label_required">必須</span>タイトル
            </p>
            {{ render_field(form.title) }}
        </div>
        <div class="form_item">
            <p class="form_item_label">
                <span class="form_item_label_required">必須</span>本文
            </p>
            {{ render_field(form.voice) }}
        </div>
        <div class="form_item">
            <p class="form_item_label">
                画像
            </p>
            {{ render_field(form.picture_path) }}
        </div>
        <div class="form_item_btn">
            {{ form.submit(class_="form_btn") }}
        </div>
    </form>
```

```style.css
.form_item {
    border-top: 1px solid #ddd;
    padding-top: 24px;
    padding-bottom: 24px;
    width: 100%;
    display: flex;
    flex-flow: column;
}

@media screen and (max-width: 480px) {
    .form_item {
        padding-left: 14px;
        padding-right: 14px;
        padding-top: 16px;
        padding-bottom: 16px;
        flex-flow: column;
        flex-wrap: wrap;
    }
}

.form_item:nth-child(5) {
    border-bottom: 1px solid #ddd;
}

.form_item_label {
    width: 100%;
    max-width: 248px;
    letter-spacing: 0.05em;
    font-weight: bold;
    font-size: 22px;
}

@media screen and (max-width: 480px) {
    .form_item_label {
        max-width: inherit;
        display: flex;
        margin-left: 2em;
        align-items: center;
        font-size: 15px;
    }
}

.form_item_label_required {
    border-radius: 6px;
    margin-right: 8px;
    margin-bottom: 8px;
    padding-top: 8px;
    padding-bottom: 6px;
    width: 48px;
    display: inline-block;
    text-align: center;
    background: #FFCC66;
    color: #fff;
    font-size: 14px;
}

@media screen and (max-width: 480px) {
    .form_item_label_required {
        border-radius: 4px;
        padding-top: 4px;
        padding-bottom: 4px;
        width: 32px;
        font-size: 10px;
    }
}

button, input, textarea {
    font-family: Meiryo;
    font-size: 100%;
}

#title {
    border: 1px solid #ddd;
    border-radius: 6px;
    padding-left: 1em;
    padding-right: 1em;
    height: 48px;
    flex: 1;
    width: 100%;
    max-width: 410px;
    background: #eaedf2;
    font-size: 18px;
}

@media screen and (max-width: 480px) {
    #title {
        margin-left: 0;
        margin-top: 18px;
        height: 40px;
        flex: inherit;
        font-size: 15px;
    }
}

#voice {
    border: 1px solid #ddd;
    border-radius: 6px;
    padding-left: 1em;
    padding-right: 1em;
    height: 216px;
    flex: 1;
    width: 100%;
    max-width: 410px;
    background: #eaedf2;
    font-size: 18px;
}

@media screen and (max-width: 480px) {
    #voice {
        margin-top: 18px;
        margin-left: 0;
        height: 200px;
        flex: inherit;
        font-size: 15px;
    }
}

.form_item_btn {
    border-top: 1px solid #ddd;
}

.form_btn {
    border-radius: 6px;
    margin-top: 32px;
    margin-left: 100px;
    padding-top: 20px;
    padding-bottom: 20px;
    width: 200px;
    display: block;
    letter-spacing: 0.05em;
    background: #FFCC66;
    color: #fff;
    font-weight: bold;
    font-size: 20px;
}
```

# 最後に
初心者ながらに、色々試行錯誤してみました。
テキスト入力フィールドは出来たのですが、`input type="file"`のフォームをいじるとかなりめんどくさそう？だったので、今回は何もしていません。
しかし、余力のある人であれば挑戦してみると良いかと思います。（出来れば教えて頂きたいです。）

最後までご覧いただき、ありがとうございました。