動くコード図鑑技術記事現場の渡り方キャリア論すべての記事About
技術記事

ASP.NETでCSSが効かない時に試したこと

バイブス父さん
現役の業務SE
2020年2月12日8 min read
ASP.NETでCSSが効かない時に試したこと

みなさんこんにちは!

ひろぽんです!

今回Asp.Netで開発をしていて、LayoutPageが読み込まれていない!?!?ん?

っとはまってしまいました。

今回はそんな大ハマりした事象から、何を確認して、どのような仮説を立てて、どのように解決したのかについて書いていこうと思います

今回はまった際の環境

まず初めにどのような環境でLauoutが読み込めない。Cssが反映されないという事象が起こったのかについて書いていきたいと思います。

Viewsフォルダに関係するフォルダ群の環境

Asp.Netでプロジェクトを作ると、ModelsやContorollersなど様々なフォルダが作成されます。

ですが今回はLayoutとCssが問題と仮説を立てていたので、Views部分に関係する構成を解説します。

□ルートフォルダ
□□Views
□□□Layout.cshtml
□□□Cars
□□□□Create.cshtml
□□□□Details.cshtml
□□□□Delete.cshtml
□□□□Index.cshtml
□□□□Edit.cshtml
□□Content
□□□Bootstrapのファイル群がある
□□Style
□□□Reset.css

割と単純なフォルダ構造で、ルートフォルダに配下にViews、Content、Styleがあるといった形です。

またViewsの配下にCarModelからスキャフォールドしたViewがあります。

レイアウトの解説

では続いて、レイアウトでどのようなコードを書いていたのかを解説します。

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link rel="stylesheet" href="~/Css/Reset.css" runat="server"/>
    <link rel="stylesheet" href="~/Content/bootstrap.min.css" runat="server"/>
</head>
<body>
<header>
    <nav class="navbar navbar-expand-sm navbar-dark bg-dark mt-3 mb-3">
        <a class="navbar-brand" href="#">車検メール送信システム</a>
        <div class="collapse navbar-collapse">
            <ul class="navbar-nav">
                @if (Request.IsAuthenticated)
                {
                    <li class="nav-item">
                        <a class="nav-link" href="@Url.Action("SignOut", "Login")">ログアウト</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="@Url.Action("Index", "Cars")">車両管理</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="@Url.Action("Index", "Emails")">アドレス管理</a>
                    </li>
                }
                else
                {
                    <li class="nav-item">
                        <a class="nav-link" href="@Url.Action("Index","Login")">ログイン</a>
                    </li>
                }
            </ul>
        </div>
    </nav>
</header>
<div>
    @RenderBody()
</div>
</body>
</html>

すごくシンプルにレイアウトでCSSの読み込みをしているだけです。

CarのViewのIndexはこんな感じ!

@using System.ComponentModel.DataAnnotations
@model IEnumerable<CarInspection.Models.Car>

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/_LayoutPage.cshtml";
}

<h2>車輌一覧</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>

<div class="container">
    <div class="row">
        @foreach (var car in Model)
        {
            <div class="card col-md-4">
                <div class="card-body">

                    <h3 class="card-title">
                        <a href="@Url.Action("Details", "Cars", new {id = car.Id})">
                            @Html.DisplayNameFor(mo => mo.Name)
                            <span>
                                @Html.DisplayFor(modelItem => car.Name)
                            </span>
                        </a>
                    </h3>
                    <p class="card-body">
                        @Html.DisplayNameFor(mo => mo.Memo)
                        <br />
                        @Html.DisplayFor(modelItem => car.Memo)
                    </p>
                    <p class="card-footer">

                        @Html.DisplayNameFor(mo => mo.Created)
                        <span>@Html.DisplayFor(modelItem => car.Created)</span>
                        @Html.DisplayNameFor(mo => mo.Updated)
                        <span>@Html.DisplayFor(modelItem => car.Updated)</span>

                    </p>
                </div>
            </div>
        }
    </div>
</div>

多少のカスタマイズは加えているものの、やっていることはスキャフォールドされたViewsと変わりありません。

今回起こった事象

では続いて今回発生した事象について。

  • レイアウトで設定したCSSが効かない?

まず今回の流れを確認すると以下のような感じ。

CarのIndexではうまくレイアウトが読み込まれていて、Header部も表示されている。

車両名というのはリンクになっていて、CarのDetailsに飛ぶようになっている。

実際にクリックして飛んでみると。

スタイルが崩れている!!!

でもレイアウトのHeader部はちゃんと表示されている。

ってことは、CSSが読み込まれてない??

一体何故?

やったこと

検証でCSSが読み込まれているかの確認

なにやら、ガチでCSSが読み込めていないらしい。

CSSは相対パスにしているので、実際はどのようなパスで読み込まれているのか確認。

何故かローカルホスト部のCars/Cssを見に行っている。

でもそんなところにはCSSはない。

CSSがあるのは、ルートディレクトリ直下にあるCSSの配下である。

ということは、このレイアウトのこの箇所がおかしいということになる。

レイアウトページの再確認

もう一度レイアウトページを見てみる。

レイアウトページの再確認 (csharp)#1def26a674dd
<!DOCTYPE html>
 
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link rel="stylesheet" href="../Css/Reset.css" runat="server"/>
    <link rel="stylesheet" href="../Content/bootstrap.min.css" runat="server"/>
</head>
<body>
<header>
    <nav class="navbar navbar-expand-sm navbar-dark bg-dark mt-3 mb-3">
        <a class="navbar-brand" href="#">車検メール送信システム</a>
        <div class="collapse navbar-collapse">
            <ul class="navbar-nav">
                @if (Request.IsAuthenticated)
                {
                    <li class="nav-item">
                        <a class="nav-link" href="@Url.Action("SignOut", "Login")">ログアウト</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="@Url.Action("Index", "Cars")">車両管理</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="@Url.Action("Index", "Emails")">アドレス管理</a>
                    </li>
                }
                else
                {
                    <li class="nav-item">
                        <a class="nav-link" href="@Url.Action("Index","Login")">ログイン</a>
                    </li>
                }
            </ul>
        </div>
    </nav>
</header>
<div>
    @RenderBody()
</div>
</body>
</html>
▸ この snippet は実行結果未収録
▸ 実行結果は未収録です

おかしいのはこの箇所。

ここで一つの仮説。

  • レイアウトページを使用して、ページを表示したら使用元のページディレクトリにレイアウトページも引っ張られる?

という仮説があったとすれば、レイアウトページでのCSSパスは自身からの参照パスになっている。

それすなわちCar/Detailsがレイアウトを使用した場合、Detailsからの参照パス。

Cars/配下のCssを探しているということになる。

でもそこにはない。

CSSはそんな場所に保管していないのである。

ということは今回参照パスは使えない。

どうする?

絶対パス?を使う?

サーバーが変わったら??

結論

すごくシンプルに下記のようにかけば解決できました。


<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link rel="stylesheet" href="~/Css/Reset.css" runat="server"/>
    <link rel="stylesheet" href="~/Content/bootstrap.min.css" runat="server"/>
</head>

参照パスでは「../」のように書くが、「~/」とすることで、ルートディレクトリからのパスを指定するとのこと。

このようにすれば以下のように正常に動くようになる。

ここからリンク先をたたくと

こんな感じでうまく動く。。。

以上

この記事のコードと手順は ぜんぶ動作検証済み。 安心して現場で試してくれ。
バイブス父さん

現役の業務SE。C# / SQL Server 保守の現場から、コードも人もキャリアも全部書く。 実体験ベース。

運営者について