GWTが生成するスタイルシート

2018年11月21日

GWTはコンパイル時に自動的にスタイルシートを生成する。これは、開発モードでも行われる。

例として、最新Eclipse(2018/1 Oxygen)でGWTサンプルを動かすまでで作成したEclipseのGWTプラグインが生成するサンプルを使用する。

gwt.xmlの例

サンプルでは、以下のようなgwt.xmlが自動生成されている。

<?xml version="1.0" encoding="UTF-8"?>
<!--
  When updating your version of GWT, you should also update this DTD reference,
  so that your app can take advantage of the latest GWT module capabilities.
-->
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.8.2//EN"
  "http://gwtproject.org/doctype/2.8.2/gwt-module.dtd">
<module rename-to='sample'>
  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>

  <!-- Inherit the default GWT style sheet.  You can change       -->
  <!-- the theme of your GWT application by uncommenting          -->
  <!-- any one of the following lines.                            -->
  <inherits name='com.google.gwt.user.theme.clean.Clean'/>
  <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->

  <!-- Other module inherits                                      -->

  <!-- Specify the app entry point class.                         -->
  <entry-point class='sample.client.Sample'/>

  <!-- Specify the paths for translatable code                    -->
  <source path='client'/>
  <source path='shared'/>

  <!-- allow Super Dev Mode -->
  <add-linker name="xsiframe"/>
</module>

コメントにもあるのだが、<inherits name=’com.google.gwt.user.theme.clean.Clean’/>という記述によって、スタイルシートが生成されているのである。

スタイルシートはどこにあるのか?

開発モードの実行でもコンパイルでも同じなのだが、この記述によって自動的にスタイルシートが生成され、以下に格納される。

モジュール名がsampleなので、war/sampleの下のgwtの中に作られる。

スタイルシートの中身は何か?

この中のclean.cssを見てみると以下のような記述になっている。

/**
 * The file contains styles for GWT widgets in the Clean theme.
 */

body, table td, select, button {
  font-family: Arial Unicode MS, Arial, sans-serif;
  font-size: small;
}
pre {
  font-family: "courier new", courier;
  font-size: small;
}
body {
  color: black;
  margin: 10px;
  border: 0px;
  padding: 0px;
  background: #fff;
  direction: ltr;
}
a, a:visited {
  color: #0066cc;
  text-decoration:none;
}

a:hover {
  color: #0066cc;
  text-decoration:underline;
}

select {
  background: white;
}

/**
 * The reference theme can be used to determine when this style sheet has
 * loaded.  Create a hidden div element with absolute position, assign the style
 * name below, and attach it to the DOM.  Use a timer to detect when the
 * element's height and width are set to 5px.
 */
.gwt-Reference-clean {
  height: 5px;
  width: 5px;
  zoom: 1;
}

.gwt-Button {
  margin: 0;
  padding: 5px 7px;
  text-decoration: none;
  cursor: pointer;
  cursor: hand;
  font-size:small;
  background: url("images/hborder.png") repeat-x 0px -2077px;
  border:1px solid #bbb;
  border-bottom: 1px solid #a0a0a0;
  border-radius: 3px;
 -moz-border-radius: 3px;
}
.gwt-Button:active {
  border: 1px inset #ccc;
}
(略)

基本的には、GWTに備わっているウィジェトのためのスタイルを決めている。例えば、ChromeのデベロッパーツールでButtonウィジェットを見てみると、gwt-Buttonというclassが指定されている。

先の生成スタイルシートの.gwt-Buttonが使われるというわけである。

スタイルシートを変更するには?

最初のgwt.xmlのコメントにあるように、GWTには複数のスタイルシートが提供されており、これを変更するだけで別のスタイルシートになるようだ。試しに、darkというスタイルシートに変更してみる。

  <!-- Inherit the default GWT style sheet.  You can change       -->
  <!-- the theme of your GWT application by uncommenting          -->
  <!-- any one of the following lines.                            -->
  <!-- <inherits name='com.google.gwt.user.theme.clean.Clean'/>   -->
  <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
  <inherits name='com.google.gwt.user.theme.dark.Dark'/>

アプリ画面は以下に変わり、

war/sample/gwtは以下に変わる(削除しなければcleanは残ったまま)

複数指定するとどうなるのか?

例えば以下のように指定する。

  <inherits name='com.google.gwt.user.theme.clean.Clean'/>
  <inherits name='com.google.gwt.user.theme.standard.Standard'/>
  <inherits name='com.google.gwt.user.theme.chrome.Chrome'/>
  <inherits name='com.google.gwt.user.theme.dark.Dark'/>

すると、指定通りすべてが生成される。が、実際に使用されるのは最後のもの、つまりDarkになるようだ。

また、スタイルシートではない、通常のモジュールの中でスタイルシートが指定されていた場合、それも有効になってしまう。

例えば、以下のように指定する。

  <inherits name='com.google.gwt.user.theme.clean.Clean'/>
  <inherits name='foo.bar.Bar'/>

Barモジュールの中でDarkが指定されていた場合、Clean、Dark共に生成されて、Darkが有効になる。

※非常に面倒になるので、他で使用されるモジュールにはスタイルシートを指定すべきではない。

無くすことはできるのか?

ときにはGWTのウィジェットを全く使わない場合もありうる。すべてを異なるウィジェットセットにし、専用のスタイルシートを使う場合である。しかし、この場合でもGWTの生成するスタイルシートにはbody等へのfont-familyが指定されており、場合によってはGWTの指定が採用されてしまう。

この場合にはgwt.xmlでどのスタイルシートもコメントアウトしてしまう。すると、当然GWTはスタイルシートを生成しなくなる。結果以下のような表示になり、war/sample/gwtフォルダ自体が生成されない。

独自のGWT用スタイルシートモジュールを作るには?

では、GWTのウィジェットを使いつつ、例えばfont-familyを変更することはできるのだろうか。GWTの提供するモジュールがそのまま生成するスタイルシートでは以下のようになるが、より日本語に適したフォントを使いたいのである。

body, table td, select, button {
  font-family: Arial Unicode MS, Arial, sans-serif;
  font-size: small;
}

単純なことだった。単にスタイルシート及び必要なイメージを特定のフォルダに入れ、モジュールとして参照するだけだ。例えば、Cleanの場合を見てみる。

gwt-user.jarの中の「com.google.gwt.user.theme.clean」パッケージを見てみると以下のようになっている。

Clean.gwt.xmlを見てみると以下の記述になっている。

<module>
  <inherits name='com.google.gwt.user.User'/>
  <public path="public" />
  <stylesheet src="gwt/clean/clean.css"/>
</module>

「public path」の意味は、Organizing Projectsの中の「Public Path」にある。

つまり、public pathとして指定されたpublicというフォルダ以下が、Cleanをinheritsしたモジュールの下にコピーされる。この場合は、gwt以下がコピーされていたわけである。

そして、コピーされるだけではなく、stylesheetとして使われなければならないので、そのパスを<stylesheet src=”gwt/clean/clean.css”/>で指定しているわけである。この説明も先のマニュアルの中にある。

ちなみに、CleanRTL.gwt.xmlは右から左に書く言語のためのもの、CleanResources.gwt.xmlはstylesheet指定が無く、単純にコピーするだけのものらしい。

関連する議論

これに関連する議論がStackOverflowにある。