JeffreyFrancesco.org 公開日 タグ Tag Permalink 現在地 Facebook page Twitter RSS feed

という訳で、前回#wrapper が幅固定だったので、ウィンドウ幅を変えてもセンターからの距離が不変であるため単純にオフセット分移動すれば任意の位置に配置出来たのですが、今回は可変幅で同じ事が出来ないか?という話。

前回同様に基準となるサンプルを置いておきますが、前回との違いは #wrapperwidth: 80% であるという部分。なのでウィンドウ幅を変更すれば中央からのピクセルオフセットも右端からのピクセルオフセットも変化しますし、また、

パーセント値で指定する場合、ボックスの左上端からの位置と画像の左上端からの位置を合わせます。たとえば、”0% 0%” の指定ではボックスの左上に画像の左上を合わせ、”100% 100%” の指定でボックスの右下に画像の右下を合わせます。”50% 50%” と指定すると、ボックスの真ん中に画像の真ん中を合わせます。つまり画像は真ん中に表示されます。”23% 81%” と指定すると、ボックスの上から 23%、左から 81% の点に、画像の上から 23%、左から 81% の点が重ねられます。長さで指定する場合と違い、画像の左上頂点の位置を指定するわけではありません。

という具合に background-position プロパティで%値を指定した際の挙動はその他の単位を指定した場合と違うので、単純に%値をマイナスに指定して動かす、という訳にもいきません。困りましたね、さてどうしましょう?

「可変といっても%指定だから、画面左端からセンタリングしたボックス左端までの距離は常に10%じゃないの?」と思ったあなたは鋭い。笑 そうですね、ならここを起点にグラデーションを置いて右に80px動かせば上手くいきそうな気もしますね。やってみましょう(サンプル/スクリーンショット)。

body {
    background-image: -moz-radial-gradient(
        10% 0,
        circle,
        rgba(255, 255, 255, 0.8),
        rgba(255, 255, 255, 0.0) 250px,
        rgba(255, 255, 255, 0.0)
    );
    background-image: -webkit-gradient(
        radial,
        10% 0, 0,
        10% 0, 250,
        from(rgba(255, 255, 255, 0.8)),
          to(rgba(255, 255, 255, 0.0))      
    );
    background-repeat: no-repeat;
    background-position: 80px 0;
}

うーん残念。起点は上手くロゴの上に移動出来たものの、左側に隙間ができてしまいます。画面の左端より向こうにはグラデーションが描かれてないから、右に動かしてもその分は隙間になってしまうのですね。でも方向としては間違ってなさそうです。あとは隠れた部分にグラデーションさえ描ければ何とかなるのですが…

こういう場合は body ではなく #wrapper をベースにした方が早い気がする

と、ここでふと気付きました。body にグラデーションを置くのは諦めて #wrapper に移動。んで左側に大きなパディングを付けて、その分をネガティブマージンで画面の外に出してしまえば、その辺上手くいきそうな予感。という訳でまずは一旦 body のグラデーションを削除して、#wrapper のスタイリングを少し変更します。今まではこうなってました。

#wrapper {
    margin: 0 auto;
    width: 80%;
}

これを、ネガティブマージンと通常パディングを加えつつ内側のコンテンツが幅80%でセンタリングされるように、次のように変更します。

#wrapper {
    margin: 0 0 0 -100%;
    padding: 0 10% 0 110%;
    width: 80%;
}

イメージ図: パディングを含んだ #wrapper の幅が合計200%になるよう調整し、マイナス100%のネガティブマージンで左側半分を画面の外側に追い出してやる。画面内に残った右半分は、左右に10%ずつパディングが残っているので、コンテンツ幅は80%でセンタリングした場合と同様の幅が確保出来ている

イメージとしては上の図ような感じ。左に加える(ネガティブマージンで追い出す)パディングの量は、グラデーションが収まりさえすれば別に何%でもいいのですが、この後の計算がしやすいように100%で設定しておきます。これにコンテンツ幅80%プラス左右パディング10%ずつを加えて、#wrapper の幅は合計200%。こいつの左マージンに-100%を指定する事で、#wrapper の左半分は画面の外側に隠れる、という案配ですね。

んで、もう一度先の図をよーく見てみますと、全体を200とした場合左パディング部分は110ですから、コンテンツ部分の左端は 110/200 で55%。つまりグラデーションの起点を55%から始めてやれば、コンテンツ部分の左上角を起点にグラデーションが描かれる事になります。

/* 先の CSS に以下を追加 */
    background-image: -moz-radial-gradient(
        55% 0,
        circle,
        rgba(255, 255, 255, 0.8),
        rgba(255, 255, 255, 0.0) 250px,
        rgba(255, 255, 255, 0.0)
    );
    background-image: -webkit-gradient(
        radial,
        55% 0, 0,
        55% 0, 250,
        from(rgba(255, 255, 255, 0.8)),
          to(rgba(255, 255, 255, 0.0))      
    );
    background-repeat: no-repeat;

ここまで出来ればあとは簡単。background-position: 80px 0; としてグラデーション全体をロゴの真上まで移動すればOKです(サンプル/スクリーンショット)。

つまり、この辺は全ての CSS テクニックに関していえる事ですが、一つの事を実現する記述方法は一つではないって事です。コンテンツ部分のセンタリングも、決して幅指定して margin: 0 auto; するのだけが許されている訳ではないですし、この辺りは柔軟に考える事が必要かと私は思います。

とはいえ場合によっては「旧バージョンの IE のバグに対処」という後ろ向きな懸案事項もない訳ではないので、この辺は兼ね合いですが…涙

けど、もっと複雑なコンテンツ幅指定をしたい場合は?

そういえばありますね…「基本的には幅80%だけど max-width プロパティで最大幅(あるいは最小幅も)を指定したい場合」とか。そうなってくると今度はウィンドウ幅を大きくした場合はコンテンツの左端が固定%という訳にいきませんから、先の方法では難しくなります。

この場合はもうさらにその内側のボックス(このサンプルの場合だと h1 要素)に指定するのがよいかと思います。先と同様にネガティブマージンと通常パディングを使ってコントロールしてみます。

とはいってもこの場合だと、グラデーション収まる程度のパディングを指定すれば十分です。左端から80pxの位置を基準にするのは変わらないので、250 - 80 = 170px があればいいでしょう。逆に高さが小さいと今度はグラデーションの下が切れる結果になりますので、その分の指定を忘れてはいけないですね(今回は上パディングに既に100pxとロゴ画像の高さが105pxありますので、残りの45pxは下パディングで調整が必要です)。

という訳で h1 要素のマージンとパディングを次のように変更。

h1 {
    margin: 0 0 -45px -170px;
    padding: 100px 0 45px 170px;
}

ここまで指定したサンプル(04-1.html)先のサンプル(04.html)を見比べると、ヘディング部分が見た目上は全く違いがないのがお分かりいただけるかと思います。あとはこれにグラデーションを指定するだけ、しかも起点は(パディングを含めた)左上角を起点に250px離してやればいいだけですね(サンプル/スクリーンショット)。

/* 先の CSS に以下を追加 */
    background-image: -webkit-gradient(
        radial,
        250 0, 0,
        250 0, 250,
        from(rgba(255, 255, 255, 0.8)),
          to(rgba(255, 255, 255, 0.0))
    );
    background-image: -moz-radial-gradient(
        250px 0,
        circle,
        rgba(255, 255, 255, 0.8),
        rgba(255, 255, 255, 0.0) 250px,
        rgba(255, 255, 255, 0.0)
    );
    background-repeat: no-repeat;

簡単!つーか、先の幅80%指定だけのやつもこっちだけ説明すれば良かったかもですね。無駄に話題を引っぱってしまった気がしないでもありません…まあ、色々やり方がありますよっていう事で。汗

CSS3 calc() 使えたらいいのに!

今のところまだ実装が Firefox 4 だけなので触れませんでしたが、先の%指定幅の例で CSS3 calc() が使えるのであれば、わざわざグラデーションを #wrapper に移動しなくても、もっと簡単に書けるのですよ…グラデーションの起点を次のようにすればいいだけなので。

body {
    background-image: -moz-radial-gradient(
        -moz-calc(10% + 80px) 0,
        circle,
        rgba(255, 255, 255, 0.8),
        rgba(255, 255, 255, 0.0) 250px,
        rgba(255, 255, 255, 0.0)
    );
    background-repeat: no-repeat;
}

ご参考までに一応サンプル(Firefox 4 でしかグラデーションが表示出来ませんが…)をアップしておきます。スクリーンショットの表示は先のものとほぼ見た目一緒ですから、無駄なのでアップは止めておきます。なので Firefox 使いの方もそうでない方も、よろしければバージョン4にアップデートまたはダウンロードしてサンプルをご覧いただければと。

という訳で、このように便利に使えますし、他の場面でも今まで「ああ、ここで計算式が使えたら…うがー!」と思う時はありましたので、そろそろいい加減に他のブラウザも CSS3 Calc() を実装してくれないかなあ、と願う今日この頃なのでございました。

このシリーズは一応以上です。ご覧いただきました皆様も楽しいグラデーション・ライフを!(何