.NET MAUI WebView(Windows/WebView2)で縦スクロールバーを非表示にする方法|CSS/JavaScript注入の実装例

Windows 上の .NET MAUI WebView でページを表示すると、右端に縦スクロールバーが出てUIが崩れることがあります。本記事では WebView2 の仕組みを踏まえ、MAUI 側ではなく HTML/CSS を JavaScript で注入してスクロールバーだけを非表示にする実装例と注意点をまとめます。

目次

.NET MAUI の WebView(Windows)で縦スクロールバーが消えない理由

.NET MAUI の WebView は、Windows では内部的に WebView2(Microsoft Edge / Chromium ベース) を使って Web コンテンツを描画します。ここで見えている縦スクロールバーは、MAUI のコントロールが「外側に付けているUI部品」ではなく、多くのケースで 表示している Web ページ(HTML/CSS)が描画しているスクロールバー です。

つまり、「MAUI のプロパティを1つ設定したらスクロールバーだけ消える」といった単純な制御が用意されていないことが多く、実務的には Web 側(CSS)を変更する のが近道になります。

スクロールバーの“表示”と“スクロール可否”は別物

まず押さえておきたいのが、スクロールバーを消したい目的が次のどちらかで実装が変わる点です。

目的やりたいこと代表的なCSS注意点
スクロールはできるがバーは見せたくないマウスホイール/タッチパッドでスクロールできる状態を維持しつつ、縦スクロールバーを非表示::-webkit-scrollbar を隠す/幅を0にするページ内のスクロール要素が body 以外の場合、追加の指定が必要
スクロール自体を無効にしたい固定表示にしたい(スクロール操作を受け付けない)overflow: hiddenコンテンツがはみ出すと読めなくなる。UI設計の見直しが必要

「縦スクロールバーだけ隠す」が目的なら、基本は前者です。overflow: hidden は強力ですが、スクロールそのものが止まるため、意図しない表示欠けが起きやすい点に注意してください。

解決方針:JavaScript 注入で CSS を追加し、縦スクロールバーを非表示にする

Windows の MAUI WebView では、ページ読み込み後に WebView2 に対して ExecuteScriptAsync() を呼び出し、<style> タグを動的に追加する のが現実的な落としどころです。Webページを自分で管理しているなら HTML/CSS 側に直接書くのが最もシンプルですが、外部ページ・共通コンポーネント・同一HTMLを複数のアプリで流用している場合は、アプリ側で注入できると運用が楽になります。

まずは“スクロールは残してバーだけ隠す”CSSを用意する

WebView2 は Chromium 系なので、基本は ::-webkit-scrollbar が効きます。縦スクロールバーだけを消したい場合は、縦方向の幅(width)を 0 に寄せるのが安定です。

/* スクロールは可能なまま、スクロールバーだけを隠す(WebView2/Chromium向け) */
html, body {
  /* ここで overflow を hidden にしないのがポイント(スクロール自体は残す) */
  -ms-overflow-style: none; /* 古いEdge/IE系の名残(保険) */
  scrollbar-width: none;    /* Firefox向け(保険) */
}

html::-webkit-scrollbar,
body::-webkit-scrollbar {
  width: 0 !important;      /* 縦スクロールバーを潰す */
  height: 0 !important;     /* 横も消したい場合。横を残すなら height は外す */
  display: none;            /* 実装依存だが併記しておくと効く環境がある */
}

「縦だけ消して横は残したい」なら、height: 0 を削除し、縦方向のみ 0 にする構成にします。逆に、スクロール自体も止めたいなら次のようにします。

/* スクロール自体を止めたい場合(バーも消えるが、操作もできなくなる) */
html, body {
  overflow: hidden;
}

実装例:Windows の WebView2 に対して CSS 注入を行う(.NET MAUI)

ここからは「Windows のときだけ」WebView2 に CSS を注入する流れを、.NET MAUI のコードとして具体化します。ポイントは次の3つです。

  • Windows では WebView の実体が Microsoft.UI.Xaml.Controls.WebView2 になる
  • CoreWebView2 が初期化される前に触ると落ちる/Null になるので、初期化完了を待つ
  • ページ遷移のたびに反映させたいなら、AddScriptToExecuteOnDocumentCreatedAsync(もしくは DOMContentLoaded など)で再注入する

Behavior を使って「特定の WebView だけ」スクロールバー非表示を適用する

プロジェクト全体の WebView に影響を出したくない場合は、Behavior にまとめるのが扱いやすいです。XAML で対象だけ付け替えられ、デバッグもしやすくなります。

Behavior(Windowsのみ実装)

using Microsoft.Maui.Controls;

#if WINDOWS
using Microsoft.UI.Xaml.Controls;
using Microsoft.Web.WebView2.Core;
#endif

namespace YourApp.Behaviors;

public class HideVerticalScrollBarBehavior : Behavior
{
#if WINDOWS
private WebView2? _webView2;
private bool _hooked;
#endif


protected override void OnAttachedTo(WebView bindable)
{
    base.OnAttachedTo(bindable);
    bindable.HandlerChanged += OnHandlerChanged;
}

protected override void OnDetachingFrom(WebView bindable)
{
    bindable.HandlerChanged -= OnHandlerChanged;


#if WINDOWS
if (_webView2?.CoreWebView2 != null && _hooked)
{
_webView2.CoreWebView2.DOMContentLoaded -= CoreWebView2OnDOMContentLoaded;
_hooked = false;
}
_webView2 = null;
#endif
base.OnDetachingFrom(bindable);
}


private async void OnHandlerChanged(object? sender, EventArgs e)
{


#if WINDOWS
if (sender is not WebView mauiWebView)
return;


    // MAUI WebView の PlatformView を WebView2 として取得
    if (mauiWebView.Handler?.PlatformView is not WebView2 platformWebView2)
        return;

    _webView2 = platformWebView2;

    // CoreWebView2 を確実に初期化
    await _webView2.EnsureCoreWebView2Async();

    // 1回のナビゲーションだけでなく「毎回」適用したいなら、DocumentCreated に登録しておくのが堅牢
    await _webView2.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(BuildInjectionScript());

    // DOMContentLoaded でも念押し(ページによっては head が遅延生成される対策)
    if (!_hooked)
    {
        _webView2.CoreWebView2.DOMContentLoaded += CoreWebView2OnDOMContentLoaded;
        _hooked = true;
    }


#endif
}

#if WINDOWS
private void CoreWebView2OnDOMContentLoaded(object? sender, CoreWebView2DOMContentLoadedEventArgs e)
{
// 既に DocumentCreated で実行されるが、念のため再実行(重複注入はスクリプト側で防止)
_ = _webView2?.CoreWebView2.ExecuteScriptAsync(BuildInjectionScript());
}


private static string BuildInjectionScript()
{
    // style タグを一度だけ追加する(重複防止用に id を固定)
    return @"


(function () {
const STYLE_ID = '**maui_hide_vscrollbar**';
if (document.getElementById(STYLE_ID)) return;

const style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = `     html, body {
      -ms-overflow-style: none;
      scrollbar-width: none;
    }
    html::-webkit-scrollbar,
    body::-webkit-scrollbar {
      width: 0 !important;
      display: none !important;
    }
  `;
document.head && document.head.appendChild(style);
})();";
}
#endif
}

XAML 側で適用

<ContentPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:behaviors="clr-namespace:YourApp.Behaviors">


<WebView Source="https://example.com">
    <WebView.Behaviors>
        <behaviors:HideVerticalScrollBarBehavior />
    </WebView.Behaviors>
</WebView>


この形なら、スクロールバーを消したい画面だけに Behavior を付けられます。アプリ全体の WebView に強制適用しないので、画面ごとの要件差(スクロールバーが必要な管理画面など)にも対応できます。

DOM のタイミング問題:どこで注入するのが一番安全か

「注入したのに効いたり効かなかったりする」場合、ほとんどが 実行タイミング の問題です。WebView2 では “CoreWebView2 がまだ無い” “head がまだ無い” “SPA で画面だけ書き換わった” といったケースが起きやすいので、複数のタイミングを組み合わせると安定します。

タイミング狙いメリット注意点
EnsureCoreWebView2Async 後CoreWebView2 を確実に触れるようにするNull 例外を避けられるここではまだ DOM が無い場合がある
AddScriptToExecuteOnDocumentCreatedAsync各ナビゲーションで自動実行「遷移すると元に戻る」を防ぎやすいページ側の CSP やフレーム構成に影響されることがある
DOMContentLoadedDOM が組み上がった後に確実に追加head への追加が通りやすいSPA の内部遷移では発火しないことがある
NavigationCompleted描画完了後の最後の一押し見た目の揺れを確認しやすい遅い実行になるので、一瞬バーが見える場合がある

実務では、DocumentCreated に登録しつつ、DOMContentLoaded でも念押し が一番バランスが良いことが多いです(重複注入は style の id で防ぐ)。

「ページ内の特定要素がスクロールしている」ケースに注意

Web ページによっては、スクロール対象が body ではなく、次のような要素になっている場合があります。

  • モーダル内のスクロール領域(例:.modal-body)
  • 一覧コンポーネントのスクロール(例:.list)
  • CSS で height: 100vh を使い、内部の div に overflow: auto を当てている

この場合、body だけに CSS を当てても縦スクロールバーが残ります。自分が管理できるページなら、スクロール要素にクラスを付けて “そこだけ” を狙い撃ちするのが保守的です。

/* 例:スクロール領域が .scroll-container の場合 */
.scroll-container {
  -ms-overflow-style: none;
  scrollbar-width: none;
}
.scroll-container::-webkit-scrollbar {
  width: 0 !important;
  display: none !important;
}

外部ページで構造が読めない場合は *::-webkit-scrollbar のような全要素対象もできますが、意図しない副作用(エディタや地図など、スクロールバーが必要なUIまで消える)が出やすいので、最終手段にしてください。

よくあるつまずきと対処

症状原因になりやすいポイント対処の方向性
NullReferenceException が出るCoreWebView2 初期化前に触っているEnsureCoreWebView2Async() を await してからイベント登録・スクリプト実行する
最初は消えるが、別ページへ遷移すると戻る1回だけ ExecuteScriptAsync しているAddScriptToExecuteOnDocumentCreatedAsync で毎回注入する
たまに効かない/再現性が低いDOM のタイミング(head が無い、SPAの内部遷移)DocumentCreated + DOMContentLoaded の併用、必要なら NavigationCompleted でも再注入
縦は消えたが、スクロールできなくなったoverflow: hidden を入れてしまったバー非表示目的なら overflow は触らず、scrollbar の見た目だけ潰す
特定の部分だけバーが残るスクロール領域が body ではなく divスクロール要素にクラスを付けて CSS を追加する/構造に合わせてセレクタを調整
外部サイトだけ効かない厳しい CSP(Content-Security-Policy)やフレーム制御まずは対象サイトで動作確認。CSP が厳しい場合は「自前ページで包む」「表示方法を変える」など設計側の回避が必要

“スクロールバーを隠す”ことのUX・アクセシビリティ面の注意

縦スクロールバーは「今どれくらいスクロールできるか」「どこまで読んだか」を示す重要な手がかりです。完全に消すと、次のような影響が出ることがあります。

  • スクロール可能であることに気づけない(特にマウスホイールを使わないユーザー)
  • 長文ページで現在位置が分からなくなる
  • ドラッグでの高速スクロールができなくなる

そのため、見た目の都合でバーを消す場合でも、次のような “代替の手がかり” を用意すると運用トラブルが減ります。

  • ページ末尾に到達しやすいように「次へ」「トップへ」などのボタンを配置する
  • コンテンツが長い場合はページ内ナビ(固定ヘッダー、セクションジャンプ)を用意する
  • アプリ側の UI と被るなら、Web 側に余白(padding)を確保してバーを目立たなくするという折衷案も検討する

補足:iOS の InputTransparent と混同しない

iOS では「スクロールを無効化したい」目的で InputTransparent="True" のようなアプローチが語られることがありますが、これは タッチ入力を透過させることで操作を受け付けなくする 方向の手段です。Windows の WebView2 で “スクロールバーだけを消す” という話とは目的も副作用も異なります。

まとめ:Windows の .NET MAUI WebView は「CSS注入」が最短ルート

  • Windows の .NET MAUI WebView は WebView2 で描画され、スクロールバーは Web(HTML/CSS)側の要素として扱われることが多い
  • スクロールバーを消したいなら、JavaScript で <style> を注入して ::-webkit-scrollbar を制御する方法が現実的
  • 安定させるコツは、EnsureCoreWebView2Async で初期化を待ち、AddScriptToExecuteOnDocumentCreatedAsync と DOMContentLoaded で適用漏れを防ぐこと
  • ページ内のスクロール領域が body 以外のケースや、外部サイトの CSP には要注意

「縦スクロールバーだけ隠して、操作性は落としたくない」という要件はよくあります。まずは本記事の Behavior 例を最小構成で動かし、対象ページのスクロール構造に合わせて CSS セレクタを調整していくのが成功パターンです。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次