質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Microsoft Edge

Microsoft Edgeは、マイクロソフト社が開発する新しいWebブラウザです。Windows 10から標準搭載されており、Internet Explorerとは違うレンダリングエンジンが採用されています。

DOM

DOMは、Document Object Modelの略で、HTML文書やXML文書をアプリケーションから利用するためのAPIです。

Chrome

Google Chromeは携帯、テレビ、デスクトップなどの様々なプラットフォームで利用できるウェブブラウザです。Googleが開発したもので、Blink (レンダリングエンジン) とアプリケーションフレームワークを使用しています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

Q&A

1回答

1688閲覧

ChromeやEdgeで代替スタイルシートを切換可能にするには?

M.Y.

総合スコア29

Microsoft Edge

Microsoft Edgeは、マイクロソフト社が開発する新しいWebブラウザです。Windows 10から標準搭載されており、Internet Explorerとは違うレンダリングエンジンが採用されています。

DOM

DOMは、Document Object Modelの略で、HTML文書やXML文書をアプリケーションから利用するためのAPIです。

Chrome

Google Chromeは携帯、テレビ、デスクトップなどの様々なプラットフォームで利用できるウェブブラウザです。Googleが開発したもので、Blink (レンダリングエンジン) とアプリケーションフレームワークを使用しています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

0グッド

1クリップ

投稿2022/11/02 05:44

編集2022/12/13 10:05

前提

代替スタイルシートをJavaScriptで切換可能にしたい。

Firefoxではメニューバー→表示→スタイルシートで代替スタイルへの切換を選択できるが、これをJavaScriptによってページ上部のプルダウン・メニューからも選択可能にし、この機能を実装しないGoogle ChromeやMicrosoft Edge等のFirefox以外のブラウザーでも代替スタイルシートを利用可能にしたい。

ブラウザーの互換性の表によってはOperaも代替スタイルシート対応とするものがあるが、GoogleChrome48がこの機能を削除した2015年11月以降のバージョンでは同じBlink系レンダリング・エンジンであるOperaも非対応となってしまった。Chromeで代替スタイル切替ができる仕組みにすればOperaでも操作可能になるはず。ほかSafariについては、環境がWindowsなので実験できず。

実現したいこと

  • フォームのSelectメニューからスタイル名を選択し、submitボタンで切替実行。
  • 代替シート名以外に、初期設定(デフォルトの固定スタイルシート)とスタイル解除(プレーンHTMLのみ)も選択肢に出す。
  • htmlヘッダーにおけるlink要素で呼び出した外部スタイルシートをHTML仕様書通りに反映させ、指定スタイルの適用順序は、第一に固定スタイルシート(title属性無し。永続スタイルシート)があって、それにtitleありの優先スタイルシートか代替スタイルシートかが上書きされてゆく形にする。
  • できれば、Cookieは使用しない方向で。

発生している問題

Firefoxではうまくいったのだが、Google ChromeとMicrosoft EdgeやOperaでは不具合が生じます。

例)link要素に優先スタイルシートが無い場合、リロード直後のページで最初に「代替シート1」を選択→実行してもスタイル表示に変化なく、「スタイル解除」の実行しか有効でない。しかし、その「スタイル解除」の実行後、さらに「初期設定」を選択して実行した後では、「代替シート1」の選択・実行も可能になる。Firefoxならば最初からメニューにある「代替シート1」「スタイル解除」のどれも選択してスタイル変更できた。

ChromeやEdgeやOperaでもFirefox同様の動作をさせるには、プログラムをどう直したらよいのですか。

該当のソースコード

html

1<head> 2<link rel="stylesheet" type="text/css" href="../persistent.css"> 3<!-- <link rel="stylesheet" type="text/css" href="../preferred.css" title="優先シート"> --> 4<link rel="alternate stylesheet" type="text/css" href="../alternate.css" title="代替シート1"> 5<script TYPE="text/javascript" charset="Shift_JIS" src="../SwitchStyle.js"></script> 6</head>

JavaScript

1//** SwitchStyle.js **// 2if (document.styleSheets 3 && !(navigator.userAgent.indexOf("Mac_PowerPC") != -1 4 && navigator.userAgent.indexOf("MSIE 4") != -1)) { 5 main();// 6} 7function main() { 8 sheetTitles=""; 9 if(document.styleSheets){ 10 ChangeStyleAlter(); 11 } 12} 13function ChangeStyleAlter(sheetTitle) { 14 sS=document.getElementsByTagName('link');// document.styleSheetsの代り 15 if(sS) {///* ここでスタイルシートの一覧を取得する */ 16 for( i=0; i<sS.length; i++) 17 { 18 if( sS[i].type!="text/css" )continue; 19 if ( sS[i].title || sS[i].title!="" ) {//titleあり(優先・代替スタイルシートあり) 20 sS[i].disabled = (sS[i].title==sheetTitle) ? false:true;//優先・代替か否か 21 sS[i].disabled = !sS[i].disabled; sS[i].disabled = !sS[i].disabled;//Chrome対策これでよい? 22 } 23 if (sheetTitles.indexOf(sS[i].title)==-1) 24 { 25 sheetTitles+=sS[i].title; 26 sheetTitles+=","; 27 } 28 if (sheetTitles.indexOf(sS[i].title)>-1) var rel = sS[i].rel;//LINK要素のrel属性 29 if (rel == 'stylesheet' && !sS.preferredTitle) sS.preferredTitle = sS[i].title; 30 else if(rel=='alternate stylesheet' && !sS.alternateTitle) sS.alternateTitle = sS[i].title; 31 } 32 if (!sS.preferredTitle) sheetTitles='Default,'+sheetTitles; 33 sheetTitles+="スタイル解除"; 34 sheetTitle=sheetTitles.split(","); 35 } 36} 37function fChangeSS(sheetTitle) {///* スタイルシートの動的切替 */ 38 if(sS) { 39 for(var i=0; i<sS.length; i++) { 40 if( sS[i].type.toLowerCase()!="text/css" )continue; 41 sS[i].disabled = 42 sheetTitle=='NoStyle' ? true : 43 sheetTitle=='Default' ? (sS[i].title!=sS.preferredTitle && sS[i].title) : 44 (sS[i].title!=sheetTitle && sS[i].title); 45 } 46 } 47} 48function DoSelect(sheetTitle) { 49 var sl = document.StyleChangeForm.SEL; 50 sheetTitle = sl.options[sl.selectedIndex].value; 51 fChangeSS(sheetTitle); 52 return false; 53} 54// スタイル変更フォーム(セレクト・メニュー)を出力 55 var select = createSelect(); 56 if (document.styleSheets) 57 { 58 document.writeln('<form action="" name="StyleChangeForm" id="StyleChangeForm" onSubmit="return DoSelect(this);" style="clear:both;">'); 59 document.writeln(select + '&nbsp;<input type="submit" value="切替">'); 60 document.writeln('</form>'); 61 } 62function createSelect(){ 63 var links = document.all && document.all.tags('link') || document.getElementsByTagName('link'); 64 var titles = new Array(); 65 var select = '<label>スタイル選択:<select name="SEL" id="SEL" size="1">'; 66 select += '<option value="Default"'+ ' style="background:#e5e5ff;">初期設定</option>';//title無し(スタイルシート無し、もしくは固定シート) 67 for(var i=0, sheetTitle; i<links.length; i++) { 68 sheetTitle = links[i].title; 69 if(links[i].type.toLowerCase() == 'text/css' && sheetTitle && !titles[sheetTitle]) { 70 titles[sheetTitle] = true; 71 select += '<option value="' + sheetTitle + '"' 72 + '>' 73 + sheetTitle + '</option>'; 74 } 75 } 76 select += '<option value="NoStyle"' + '>スタイル解除</option>'; 77 select += '</select></label>'; 78 return select; 79}

試したこと

下記を参考にしました。

環境

Windows 10 Home 21H2
Firefix106.0.3
Google Chrome 107.0.5304.88
Microsoft Edge 106.0.1370.52
Opera 92.0.4561.43
Falkon 3.1.0

追記

上掲JavaScriptプログラム中、Chrome対策のif ( sS[i].title || sS[i].title!="" ) {以下五行を、スタイルシート一覧取得の函数からスタイルシート動的変更の函数へ移すと、ちょっと見には、うまくいったかと見えた。もろもろ修正したその改訂プログラムは下記の通り。

JavaScript

1//** 改訂SwitchStyle.js **// 2if (document.styleSheets 3 && !(navigator.userAgent.indexOf("Mac_PowerPC") != -1 4 && navigator.userAgent.indexOf("MSIE 4") != -1)) { 5 main(); 6} 7function main() { 8 sheetTitles=""; 9 if(document.styleSheets){ 10 setSS(); 11 } 12} 13// ///////////* スタイルシートの一覧を取得する *////// 14function setSS() { 15 sS=document.getElementsByTagName('link');//document.styleSheets;の代り、Chrome対策 16 if(sS) { 17 for(var i=0; i<sS.length; i++) 18 { 19// if(sS[i].type!="text/css")continue;//Chrome対策だがHTML5以降はtype属性省略可 20 if(sS[i].rel.toLowerCase().indexOf("stylesheet")==-1)continue;//Chrome対策改 21 var isSameTitle = false;/// 既に同じスタイル名がある場合は除く 22 for (var j = 0; j < i; j++) { 23 if (sS[j].title == sS[i].title) { 24 isSameTitle = true; 25 break; 26 } 27 } 28 if (!isSameTitle) 29 { 30 sheetTitles+=sS[i].title; 31 sheetTitles+=","; 32 } 33 if (sheetTitles.indexOf(sS[i].title)>-1) 34 var rel = sS[i].getAttribute("rel").toLowerCase();// sS[i].rel.toLowerCase(); 35 if (rel == 'stylesheet' && !sS.preferredTitle) sS.preferredTitle = sS[i].title; 36 else if(/alternate/i.test(rel)/**/ && !sS.alternateTitle) 37 sS.alternateTitle=sS[i].title;//不用? 38 } 39 if (!sS.preferredTitle) sheetTitles='初期設定,'+sheetTitles;// 'Default,' 40 sheetTitles+="スタイル解除";// 'NoStyle' 41 sheetTitle=sheetTitles.split(","); 42 } 43} 44// /////////////* スタイルシートの動的切替 */////////// 45function ChangeStyleAlter(selectedTitle) { 46 if(sS) { 47 for(var i=0; i<sS.length; i++) { 48 if(sS[i].rel.toLowerCase().indexOf("stylesheet")==-1) continue;//Chrome対策改 49 if ( sS[i].title || sS[i].title!="" ) //Chrome対策 50 {// titleがある(優先or代替スタイルシート) 51 sS[i].disabled = (sS[i].title==sheetTitle) ? false:true;//優先か代替か 52 sS[i].disabled = !sS[i].disabled; sS[i].disabled = !sS[i].disabled;//これでよい? 53 } 54 sS[i].disabled = 55 selectedTitle=='スタイル解除' ? true : 56 selectedTitle=='初期設定' ? (sS[i].title!=sS.preferredTitle && sS[i].title) ://優先シート以外無効 57 (sS[i].title!=selectedTitle && sS[i].title);//選択シート以外の代替シート無効 58 } 59 } 60} 61// ///////* ドロップダウン・リストから変更する *////////////// 62function DoSelect() { 63 var sl = document.StyleChangeForm.SEL; 64 selectedTitle = sl.options[sl.selectedIndex].value; 65 ChangeStyleAlter(selectedTitle); 66 return false; 67} 68// スタイル変更フォーム(セレクト・メニュー)を出力 69 var select = createSelect(); 70 if (document.styleSheets) 71 { 72 document.writeln('<form action="" name="StyleChangeForm" id="StyleChangeForm" onSubmit="return DoSelect();" style="clear:both;">'); 73 document.writeln(select + '&nbsp;<input type="submit" value="切替">'); 74 document.writeln('</form>'); 75 } 76 77function createSelect(){ 78 var select = '<label>スタイル選択:<select name="SEL" id="SEL" size="1">'; 79 for(var i=0; i<sheetTitle.length; i++){ 80 select += '<option value="' + sheetTitle[i] + '"' 81 + (sheetTitle[i] == sS.preferredTitle ? ' selected="selected"' : '')//Firefox不能? 82 + '>' 83 + sheetTitle[i] + '</option>'; 84 } 85 select += '</select></label>'; 86 return select; 87} 88// このファイルが表示された場合、ブラウザーの戻るボタンを押してみて下さい。-->

しかし、このプログラムは下記のごとき優先スタイルシートありの場合に、不具合が生じた。

html

1<head> 2<link rel="stylesheet" type="text/css" href="../persistent.css"><!-- 固定シート --> 3<link rel="stylesheet" type="text/css" href="../preferred.css" title="優先シート(背景色=赤)"> 4<link rel="alternate stylesheet" type="text/css" href="../alternate.css" title="代替シート(文字色=青)"> 5<script TYPE="text/javascript" charset="Shift_JIS" src="../SwitchStyle.js"></script> 6</head>

これで代替シートを選択して実行したら、Firefoxでは固定シートに代替スタイルが重ねられる形でスタイル指定が適用されて問題無かったが、ChromeやEdgeやOperaだと固定シートのみならず優先シートのスタイル指定(上記例では背景色)までもが継承されてしまって、そこに代替シートの指定が上書きされた表示となり、優先/代替の切換(スイッチ)にはなってくれない。但し、そのままプルダウン・メニューで代替シートを選択した状態でsubmitボタンの「切替」をもう一度押し直すと、優先シートのスタイルを切って代替シートのみ適用される。さらにそのまま三度目のsubmitボタンのクリックでは、また優先シートの指定が反映される状態に戻る。
また、リロード直後いったん「スタイル解除」(NoStyle)を選択・実行してから次いで代替シートを選択・実行すると、最初から優先シートのスタイルを引き継がずに代替シートだけが正しく適用される。この場合も、そのままサブミット・ボタンの二度押しをすれば優先シートも有効化するし、三度押し目ではまた優先シートの無効状態になる。

サブミット・ボタンの二度押しをプログラムに仕組めば良いのかとも思ったものの、二重送信を防止するプログラムはサンプルが多々見つかるのに対し、その逆に連続クリックを強制させるプログラムは見当たらない。試しにwindow.onloadイベントでdocument.getElementById('StyleChangeForm').submit();とかdocument.getElementsByTagName('input').click();とかやってみたが、作動しないみたいだった。それに、直前に選択されたメニューによって対応を変更せねばならないから場合分け(分岐)がややこしくて手にあまる。
Chrome対策用のsS[i].disabled = !sS[i].disabled;の二重化が悪さをしたのかもしれないけれど、これを削ってしまったら、改訂前の最初のプログラムと同じく代替シート選択時にまともに動作しなくなる。これ以外にChrome対策の手法を見出せないのだが……もし他にあるのなら御教示戴きたい。
或いは、スタイルシート選択時には一度sS[i].disabled=true;の値を渡して「スタイル解除」(document.getElementById('SEL').value='NoStyle';とか?)させてから選択したスタイルシート名の値を実行するといった流れのプログラムを仕込めればいいのかもしれないが、ちゃんと動かすにはどうやればよいのやら……?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

上掲プログラムで問題があったのは、下記の五行中sS[i].disabled = !sS[i].disabled;の箇所だった。

JavaScript

1if ( sS[i].title || sS[i].title!="" ) //Chrome対策 2 {// titleがある(優先or代替スタイルシート) 3 sS[i].disabled = (sS[i].title==sheetTitle) ? false:true;//優先か代替か 4 sS[i].disabled = !sS[i].disabled; sS[i].disabled = !sS[i].disabled;//これでよい? 5 }

これを、二重化したsS[i].disabled = !sS[i].disabled;の行は削除した上で、代りにif文ブロック先頭にsS[i].disabled = true;を挿入し、次の通り改めた。

JavaScript

1if ( sS[i].title || sS[i].title!="" ) //Chrome対策 2 {// titleがある(優先or代替スタイルシート) 3 sS[i].disabled = true;//追加 4 sS[i].disabled = (sS[i].title==sheetTitle) ? false:true;//優先か代替か 5///*削除*/ sS[i].disabled = !sS[i].disabled; sS[i].disabled = !sS[i].disabled; 6 }

スタイル切替の前に一遍、外部スタイルシート全部を無効にする手順を踏んでから、メニューで選択したシートを有効にする次第。
Firefox、Chrome、Edge、Operaいづれでも正常に動作した。

参考にしたのは、下記サイト「代替スタイルシート切替JavaScript」である。
http://confetto.s31.xrea.com/misc/switchstyles
優先スタイルシートありの状態でちゃんと代替スタイルとかぶらないでスイッチできるみたいなので、ソースを覗き、そのstyles.js 中「スタイルシートを切り替える。」Switch : function(name) {以下、特に「Opera9で必要?」とコメントのある行を真似た。

原因説明としては、「IE9、Chrome 22、Safari 5で確認したところ、代替スタイルシートが適用されていなくてもdisabledがfalseとなっていました。その状態でfalseに設定してもスタイルシートは有効とならないため」「あらかじめ無効に設定することで、有効の設定が機能する」との記述が当て嵌まるか。
Cf. JavaScript プログラミング解説「スタイルの制御」中「スタイルシートの切り替え
https://so-zou.jp/web-app/tech/programming/javascript/css/#no3

「新しいスタイルシートに動的に切り替えるには、まず利用可能なすべてのオプショナルスタイルシートを無効にする必要があります」云々と「HTML5でオプションのスタイルシートを使ってWebサイトやアプリケーションにダークモードを追加する方法を解説」にも見える。
https://www.binarydevelop.com/article/html5web-6927

また、より新しいヴァージョンでも、「document.styleSheets で取得した代替スタイルシートの disabled の値が Firefox 76, IE 11, Opera 12 は true で、 Chrome 83, Edge 83 は false になる」とのこと。
Cf.富永日記帳「印刷用スタイルを @media print から代替スタイルシートへ変更
https://blog.w0s.jp/612#section-ブラウザが代替スタイルシートの切替機構を有しているかどうか調べる

しかしChromium Blog(邦訳Google Developers Japan2020年8月18日)によれば、Chrome 85では「HTMLLinkElement の "disabled" 属性の動作のアップデート」がなされ、以下の動作が削除されたともある。

  • document.stylesheets から disabled 属性の値にアクセスできませんでした。
  • disabled 属性を false に変更した後 true に戻すと、document.stylesheets に表示され、そこに残ったままになっていました。
  • 代替スタイルシートを有効にする唯一の方法は、無効にした後再度有効にすることでした。

このアップデート後のヴァージョンなのに、disabled=true(無効)にしてからでないとdisabled=false(有効)にならないのは、どう理解したものか?

念の為、下記のJavaScriptプログラムを仕込んだページをリロードして確認した所、各タイトル毎の代替スタイルシートについてdisabledかどうかの真偽値がfalseと出たのは、FirefoxでもChromeやEdgeやOperaでも(ついでに別系統エンジンのFalkonでも)みな同じで、結果に差は無かった。

JavaScript

1<script type="text/javascript"> 2var Links = document.getElementsByTagName('link');// =document.styleSheets; だとFirefox以外は代替シート認識しない 3for(var i=0; i<Links.length; i++) { 4 if (Links[i].title !== null && Links[i].rel.indexOf("alternate")!=-1) /* title属性が存在し且つrel属性値に'alternate'が含まれるならば代替スタイルシートである。 */ 5 alert(Links[i].title + "=" + Links[i].disabled);//結果の出力 6} 7</script>

スタイル切替プログラム全体も、もっとすっきりと書き直すべきなのかもしれないが、不得手なので、うまい書き方があれば御教示を得たい。

投稿2022/11/09 12:17

編集2022/11/27 22:42
M.Y.

総合スコア29

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問