JavaScriptでHTML要素のスタイルを知りたいという時、どうしていますか?
jQueryを使っているのであれば jQuery.css(element, 'property')
や jQuery(selector).css('property')
で取得している人もいるかと思いますが、jQueryを使わずとも window.getComputedStyle()
というメソッドで取得可能です。(jQuery.css()
もこれを使っています)
なにそれなにそれー!
#window.getComputedStyle() とは?
指定した要素の現在の状態のスタイル情報を CSSStyleDeclaration
(Firefoxでは CSS2Properties
)という名前の読み取り専用の(配列のように扱う事もできる)オブジェクトを返すメソッドです。すっごーい!
MDNでも見てみましょう。
要素の算出スタイルを返します。算出スタイルは、要素に対して適用される全ての CSS プロパティにおいて最終的に算出された値です。
window.getComputedStyle - Web API インターフェイス | MDN
あれあれ? なんだか直訳したかのようなよくわからない感じの日本語だ……
というか、日本語版は最終更新が 2008年01月27日 と、9年も前(2017年3月現在)のまま止まっていてなんだか心配になってきた……
そんなわけで、英語版の方も見てみましょう。
The Window.getComputedStyle() method gives the values of all the CSS properties of an element after applying the active stylesheets and resolving any basic computation those values may contain.
Window.getComputedStyle() - Web APIs | MDNwindow.getComputedStyle() メソッドは、要素に適用されたスタイルの値を基本的な値に計算しなおした後、すべてのCSSプロパティの値を返します。(意訳)
なるほどー! こっちの方がわかりやすいですね。
###対応しているブラウザ
現在主流のブラウザはすべて対応していますが、IE8以下では使えません。IE11未満は滅んでいいです。
##使い方
例えば、以下のようなHTMLがあったとします。(いろいろ省略)
<style>
#sampleBlock {
width: 150px;
height: 150px;
padding: 10px;
background-color: #0b398c;
color: #fff;
font-size: 1em;
font-weight: bold;
text-align: center;
box-sizing: border-box;
}
#sampleBlock::before {
content: "たーのしー!";
}
</style>
<div id="sampleBlock"></div>
これを以下のように書くことで div#sampleBlock
のスタイルが取得できます。(以下の例はChromeで実行した場合です)
var sampleBlock = document.getElementById('sampleBlock');
// ブラウザが使用できるCSSのプロパティがオブジェクトになって返ってくる
var style = window.getComputedStyle(sampleBlock);
// それぞれの値を取得可能(キャメルケースで取得)
console.log(style.display); // "block"
console.log(style.width); // "150px"
console.log(style.margin); // "0px"
console.log(style.paddingTop); // "10px"
console.log(style.color); // "rgb(255, 255, 255)"
console.log(style.background); // "rgb(11, 57, 140) none repeat scroll 0% 0% / auto padding-box border-box"
console.log(style.fontSize); // "16px"
// CSSStyleDeclaration.getPropertyValue() で取得(チェインケースで取得)
console.log(style.getPropertyValue('display')); // "block"
console.log(style.getPropertyValue('width')); // "150px"
console.log(style.getPropertyValue('margin')); // "0px"
console.log(style.getPropertyValue('padding-top')); // "10px"
console.log(style.getPropertyValue('color')); // "rgb(255, 255, 255)"
console.log(style.getPropertyValue('background')); // "rgb(11, 57, 140) none repeat scroll 0% 0% / auto padding-box border-box"
console.log(style.getPropertyValue('font-size')); // "16px"
// 擬似要素の値も取得できる
var pseudo = window.getComputedStyle(sampleBlock, '::before');
console.log(pseudo.content); // "たーのしー!"
console.log(pseudo.getPropertyValue('content')); // "たーのしー!"
background-color: #0b398c;
としか書いていないのに、window.getComputedStyle()
は計算して background: rgb(11, 57, 140) none repeat scroll 0% 0% / auto padding-box border-box;
という値を返してくれます。
他にも、font-size: 1em;
と相対的なサイズ指定も計算されて font-size: 16px;
となっているのがわかります。
計算が得意なフレンズなんだね!
CSSStyleDeclaration.getPropertyValue()
を使う事で、CSSで普段使っているチェインケース(ハイフンでつなぐ書き方)でも取得できるのがいいですね。
第2引数に ::before
や ::after
など擬似要素名を指定してやると、擬似要素に適用されているスタイルも取得できます。すっごーい!
##中身はどうなっているのか
window.getComputedStyle()
が返すオブジェクトはChromeの場合以下のようになっています。(数が多すぎるので省略しています)
// [object CSSStyleDeclaration]
style = {
0: "animation-delay",
1: "animation-direction",
// 省略
261: "rx",
262: "ry",
alignContent: "stretch",
alignItems: "stretch",
// 省略
left: "auto",
length: 263,
letterSpacing: "normal",
// 省略
zIndex: "auto",
zoom: "1",
}
length
プロパティがあり、CSSのプロパティ名(こちらはスネークケース)が配列のように入っているのもわかります。
##Firefox以外のブラウザは cssText も取得できる
全てのCSSをテキストにした cssText
も取得できますが、Firefoxでは空文字になってしまいます。
console.log(style.cssText);
animation-delay: 0s; animation-direction: normal; animation-duration: 0s; animation-fill-mode: none; animation-iteration-count: 1; animation-name: none; animation-play-state: running; animation-timing-function: ease; background-attachment: scroll; background-blend-mode: normal; background-clip: border-box; background-color: rgb(11, 57, 140); background-image: none; background-origin: padding-box; background-position: 0% 0%; background-repeat: repeat; background-size: auto; border-bottom-color: rgb(255, 255, 255); border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-bottom-style: none; border-bottom-width: 0px; border-collapse: separate; border-image-outset: 0px; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: rgb(255, 255, 255); border-left-style: none; border-left-width: 0px; border-right-color: rgb(255, 255, 255); border-right-style: none; border-right-width: 0px; border-top-color: rgb(255, 255, 255); border-top-left-radius: 0px; border-top-right-radius: 0px; border-top-style: none; border-top-width: 0px; bottom: auto; box-shadow: none; box-sizing: border-box; break-after: auto; break-before: auto; break-inside: auto; caption-side: top; clear: none; clip: auto; color: rgb(255, 255, 255); content: ; cursor: auto; direction: ltr; display: block; empty-cells: show; float: none; font-family: "ヒラギノ角ゴ Pro W3"; font-kerning: auto; font-size: 16px; font-stretch: normal; font-style: normal; font-variant: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: normal; font-weight: bold; height: 150px; image-rendering: auto; isolation: auto; left: auto; letter-spacing: normal; line-height: normal; list-style-image: none; list-style-position: outside; list-style-type: disc; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; max-height: none; max-width: none; min-height: 0px; min-width: 0px; mix-blend-mode: normal; object-fit: fill; object-position: 50% 50%; offset-distance: 0px; offset-path: none; offset-rotate: auto 0deg; offset-rotation: auto 0deg; opacity: 1; orphans: 2; outline-color: rgb(255, 255, 255); outline-offset: 0px; outline-style: none; outline-width: 0px; overflow-anchor: auto; overflow-wrap: normal; overflow-x: visible; overflow-y: visible; padding-bottom: 10px; padding-left: 10px; padding-right: 10px; padding-top: 10px; pointer-events: auto; position: static; resize: none; right: auto; speak: normal; table-layout: auto; tab-size: 8; text-align: center; text-align-last: auto; text-decoration: none; text-indent: 0px; text-rendering: auto; text-shadow: rgb(255, 255, 255) 0px 0px 0.001px; text-size-adjust: auto; text-overflow: clip; text-transform: none; top: auto; touch-action: auto; transition-delay: 0s; transition-duration: 0s; transition-property: all; transition-timing-function: ease; unicode-bidi: normal; vertical-align: baseline; visibility: visible; white-space: normal; widows: 2; width: 150px; will-change: auto; word-break: normal; word-spacing: 0px; word-wrap: normal; z-index: auto; zoom: 1; -webkit-appearance: none; backface-visibility: visible; -webkit-background-clip: border-box; -webkit-background-origin: padding-box; -webkit-border-horizontal-spacing: 0px; -webkit-border-image: none; -webkit-border-vertical-spacing: 0px; -webkit-box-align: stretch; -webkit-box-decoration-break: slice; -webkit-box-direction: normal; -webkit-box-flex: 0; -webkit-box-flex-group: 1; -webkit-box-lines: single; -webkit-box-ordinal-group: 1; -webkit-box-orient: horizontal; -webkit-box-pack: start; -webkit-box-reflect: none; column-count: auto; column-gap: normal; column-rule-color: rgb(255, 255, 255); column-rule-style: none; column-rule-width: 0px; column-span: none; column-width: auto; align-content: stretch; align-items: stretch; align-self: stretch; flex-basis: auto; flex-grow: 0; flex-shrink: 1; flex-direction: row; flex-wrap: nowrap; justify-content: flex-start; -webkit-font-smoothing: auto; -webkit-highlight: none; hyphens: manual; -webkit-hyphenate-character: auto; -webkit-line-break: auto; -webkit-line-clamp: none; -webkit-locale: auto; -webkit-margin-before-collapse: collapse; -webkit-margin-after-collapse: collapse; -webkit-mask-box-image: none; -webkit-mask-box-image-outset: 0px; -webkit-mask-box-image-repeat: stretch; -webkit-mask-box-image-slice: 0 fill; -webkit-mask-box-image-source: none; -webkit-mask-box-image-width: auto; -webkit-mask-clip: border-box; -webkit-mask-composite: source-over; -webkit-mask-image: none; -webkit-mask-origin: border-box; -webkit-mask-position: 0% 0%; -webkit-mask-repeat: repeat; -webkit-mask-size: auto; order: 0; perspective: none; perspective-origin: 75px 75px; -webkit-print-color-adjust: economy; -webkit-rtl-ordering: logical; shape-outside: none; shape-image-threshold: 0; shape-margin: 0px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0.180392); -webkit-text-combine: none; -webkit-text-decorations-in-effect: none; -webkit-text-emphasis-color: rgb(255, 255, 255); -webkit-text-emphasis-position: over; -webkit-text-emphasis-style: none; -webkit-text-fill-color: rgb(255, 255, 255); -webkit-text-orientation: vertical-right; -webkit-text-security: none; -webkit-text-stroke-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px; transform: none; transform-origin: 75px 75px; transform-style: flat; -webkit-user-drag: auto; -webkit-user-modify: read-only; user-select: text; -webkit-writing-mode: horizontal-tb; -webkit-app-region: no-drag; buffered-rendering: auto; clip-path: none; clip-rule: nonzero; mask: none; filter: none; flood-color: rgb(0, 0, 0); flood-opacity: 1; lighting-color: rgb(255, 255, 255); stop-color: rgb(0, 0, 0); stop-opacity: 1; color-interpolation: sRGB; color-interpolation-filters: linearRGB; color-rendering: auto; fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; marker-end: none; marker-mid: none; marker-start: none; mask-type: luminance; shape-rendering: auto; stroke: none; stroke-dasharray: none; stroke-dashoffset: 0px; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-opacity: 1; stroke-width: 1px; alignment-baseline: auto; baseline-shift: 0px; dominant-baseline: auto; text-anchor: start; writing-mode: horizontal-tb; vector-effect: none; paint-order: fill stroke markers; d: none; cx: 0px; cy: 0px; x: 0px; y: 0px; r: 0px; rx: auto; ry: auto;
Firefoxでも使いたいのであれば、このようにするしかなさそうです。
// window.getComputedStyle() の返すオブジェクトには
// CSSのプロパティが配列のように入っている
var
cssText = '',
length = style.length;
if (style.cssText === '') {
for (var i = 0; i < length; i++) {
// チェインケースなので、CSSStyleDeclaration.getPropertyValue で取得
cssText += style[i] + ': ' + style.getPropertyValue(style[i]) + '; ';
}
cssText = cssText.trim();
} else {
cssText = style.cssText;
}
#おわりに
window.getComputedStyle()
に関する記事などが結構古い事が多いので、改めて書いてみました。
そのせいもあるのか、結構使いそうなメソッドなのに個人的に影が薄い印象です。