SimpleIsm

舞台裏は乱雑に、見えるところはシンプルに。

CSSで背景画像の配置を右から指定する方法

今仕事でスマホ用のサイトを作っているのだけど、ページの先頭へ戻るボタンをCSSで実装したかった。ので、実装した。

こんな感じの。
ページの先頭へ戻るボタンのサンプル

実際はbox-shadowとかtext-shadowとか細かい指定をしているのだけど、今回の例では割愛。ちなみにHTMLは以下。

<p class="hoge">
    <span>hogera</span>
    <a href="#top">TOP</a>
</p>

単純に考えると、a要素にboder指定してグラデーションかけて、矢印の背景とか位置とかを指定して、適当にpadding付ければOKなはず。

.hoge a {
    background-image: url("arrow.png"), -webkit-gradient(linear, left top, left bottom, from(#FFF), to(#999));
    background-image: url("arrow.png"), -webkit-linear-gradient(top, #FFF, #999);
    background-image: url("arrow.png"),    -moz-linear-gradient(top, #FFF, #999);
    background-image: url("arrow.png"),         linear-gradient(to bottom, #FFF, #999);
    background-position: 40px 50%, 0 0;
    background-repeat: no-repeat;
    border: 1px solid #999;
    border-radius: 3px;
    color: #000;
    display: inline-block;
    font: 16px/24px "Helvetica", "Arial", sans-serif;
    padding: 0 17px 0 6px;
    text-decoration: none;
}

View Demo: Right Start Background Position – Demo1

これで想定通りの見た目になる。現時点での最新であるFirefox 18.0.2とChrome 24.0.1312.57 mでは。IEは知らない。で、スマホを想定するならこれでOKなのだけど、いかんせん機種依存という厄介な代物があって、機種によってフォントが違っていたり、文字間隔が違っていたりするので(と言うか、環境によって表示や挙動に違いが出るのはスマホもPCも同じだった)、背景画像を左から指定していると、テキストと重なってしまう可能性がある。というか実際重なった。

今回の場合、左右のpaddingを6px、矢印の画像とテキストの間を2px取りたい。で、今回矢印の画像の横幅は9pxなので、右側のpaddingは9px + 6px + 2px = 17pxとなる。あとは矢印の画像の位置を縦に50%でセンタリングし、横は右から6pxの位置に指定すればOK。なのだけど、現状背景画像は右から指定できない。

背景画像、右から指定させてよー>< w3.org/TR/css3-backgr…

Twitter / yoruaki: 背景画像、右から指定させてよー>< http://t …

ってな具合に、思わずつぶやいちゃうレベル。

で、ここからが本題。背景画像の配置を右から指定する方法。

.hoge a {
    background-image: -webkit-gradient(linear, left top, left bottom, from(#FFF), to(#999));
    background-image: -webkit-linear-gradient(top, #FFF, #999);
    background-image:    -moz-linear-gradient(top, #FFF, #999);
    background-image:         linear-gradient(to bottom, #FFF, #999);
    border: 1px solid #999;
    border-radius: 3px;
    color: #000;
    display: inline-block;
    font: 16px/24px "Helvetica", "Arial", sans-serif;
    padding: 0 17px 0 6px;
    position: relative;
    text-decoration: none;
}

.hoge a:after {
    background: transparent url("arrow.png") no-repeat 0 0;
    content: "";
    height: 12px;
    position: absolute;
    right: 6px;
    top: -webkit-calc(50% - (12px / 2));
    top:    -moz-calc(50% - (12px / 2));
    top:         calc(50% - (12px / 2));
    width: 9px;
}

View Demo: Right Start Background Position – Demo2

a要素にposition:relative;で予め基準点を明示しておき、after擬似要素で矢印の画像をposition:absolute;で右から絶対配置してやるというやり方。縦に関しては、50%で真ん中に指定すると、画像の上部が50%の部分に配置されてしまうので、画像の上部を50%の位置に配置して、その画像の縦半分のサイズを上にずらしている。

ただ、今回は割り切れるから良いのだけど、小数点以下のピクセル値の扱いは各ブラウザによって違うようなので、注意が必要かも。

@yoruaki border-right: 10px transparent; padding-right:20px; background-position:right center;とか

Twitter / forty4_jp

背景画像を右配置にしておき、透明なborderで幅を取るというアドバイスを頂いたので、実験してみた。コードは以下。

hoge a {
    background-image: url("arrow.png"), -webkit-gradient(linear, left top, left bottom, from(#FFF), to(#999));
    background-image: url("arrow.png"), -webkit-linear-gradient(top, #FFF, #999);
    background-image: url("arrow.png"),    -moz-linear-gradient(top, #FFF, #999);
    background-image: url("arrow.png"),         linear-gradient(to bottom, #FFF, #999);
    background-position: 100% 50%, 0 0;
    background-repeat: no-repeat;
    border: 1px solid #999;
    border-right: 6px transparent;
    border-radius: 3px;
    color: #000;
    display: inline-block;
    font: 16px/24px "Helvetica", "Arial", sans-serif;
    padding: 0 11px 0 6px;
    text-decoration: none;
}

View Demo: Right Start Background Position – Demo3

今回の仕様上、すでにborderが指定されているので、右のボーダーを透明にすると、ボタンの右ボーダーが透明になってしまうので今回の仕様にはそぐわなかった。けど、borderを指定しないボタンなどなどには有効な記述方法だと思う。アドバイスありがとうございました。

上記のコード3つを比較したものが以下。多分スマホで見ると、それぞれ表示が異なってくると思う。Demo2が今回の仕様に沿った実装方法。

View Demo: Right Start Background Position – Comparison

追記

早速の反応ありがとうございます!

というわけで、もっとスマートで良い記述を教えてもらったので紹介。

hoge a {
    background-image: url("arrow.png"), -webkit-gradient(linear, left top, left bottom, from(#FFF), to(#999));
    background-image: url("arrow.png"), -webkit-linear-gradient(top, #FFF, #999);
    background-image: url("arrow.png"),    -moz-linear-gradient(top, #FFF, #999);
    background-image: url("arrow.png"),         linear-gradient(to bottom, #FFF, #999);
    background-position: -webkit-calc(100% - 6px) 50%, 0 0;
    background-position:    -moz-calc(100% - 6px) 50%, 0 0;
    background-position:         calc(100% - 6px) 50%, 0 0;
    background-position: right 6px top 50%, 0 0;
    background-repeat: no-repeat;
    border: 1px solid #999;
    border-radius: 3px;
    color: #000;
    display: inline-block;
    font: 16px/24px "Helvetica", "Arial", sans-serif;
    padding: 0 17px 0 6px;
    text-decoration: none;
}

View Demo: Right Start Background Position – Demo4

100%(right)から6px分引いたやり方。あんだけcalc()使ってたのにここを見逃すとは…。ばかが!あとはもっとスマートに4値構文を使うというやり方もあった。ので追加。Chromeも26.0から4値構文に対応するみたいだし。

あとどうでもいい解説。linear-gradientはto bottomが正。

Re: CSSで背景画像の配置を右から指定する方法 – ひあ的な生活。

-webkit-linear-gradient(top, #FFF, #999);をコピペしてたから全部topになってた…ので修正しました。

これで解決かと思いきや、iOS 5とかAndroid 4.2とかだとcalc()に対応していないので、やっぱりafter擬似要素を使うか画像自体に(今回の場合)6px分の透明な領域を追加して右から指定するとかかな。

で、今書いてて思ったのが、iOS 5とかでcalc()対応してないなら、自分が書いたafter擬似要素の記述もダメじゃん!ってことで、書き直し。多分これでOK。

.hoge a {
    background-image: -webkit-gradient(linear, left top, left bottom, from(#FFF), to(#999));
    background-image: -webkit-linear-gradient(top, #FFF, #999);
    background-image:    -moz-linear-gradient(top, #FFF, #999);
    background-image:         linear-gradient(to bottom, #FFF, #999);
    border: 1px solid #999;
    border-radius: 3px;
    color: #000;
    display: inline-block;
    font: 16px/24px "Helvetica", "Arial", sans-serif;
    padding: 0 17px 0 6px;
    position: relative;
    text-decoration: none;
}

.hoge a:after {
    background: transparent url("arrow.png") no-repeat 0 50%;
    content: "";
    height: 100%;
    position: absolute;
    right: 6px;
    width: 9px;
}

View Demo: Right Start Background Position – Demo5

a要素で指定したline-height:24px;と同じ高さの24px(height:100%;)にして、真ん中に持ってくるという方法。これでOKでしょう。

View Demo: Right Start Background Position – Comparison

サイト実装時に調べたことまとめ

まだ固定ページとか全部終わってないけど、作っている時に調べたこと(サイト)のまとめ。主にWordPress、というかPHPについて。ノンプログラマがやるとこうやって回り道することもあるけれど、それらを調べてる時間も本当に楽しい。

WordPress Codex 日本語版

WordPressの公式オンラインマニュアル。大抵のことはここを見れば載っている。はず。詳しく知りたいときは原文を見に行く。でも、それを言い訳にはしたくないけど、ノンプログラマは原文見たって翻訳見たって分からないものは分からない。

WordPressをカスタマイズするなら絶対覚えておきたいテンプレートファイルの使い方 | Webデザインレシピ

テンプレートファイルの役割とか基本的なことを知るのに良いまとめ。自分は仕事で元々ある静的なサイトをCMS化したりとかしてたので、ある程度はテンプレートファイルの仕組みを理解していたので、理解しやすかった。

WordPressでカテゴリ一覧リストの様にタグ一覧リストを表示する方法 | ale cole blog

カテゴリ一覧はwp_list_categories()という関数で出せるのだけど、タグ一覧を出す関数が無いっぽかったので、こちらの記事を参考にした。当サイトのサイドバーのタグ一覧は以下のコードでABC順で出力させている。

<h1>Tag</h1>
<ul>
    <?php
        $tagList = $wpdb->get_results($wpdb->prepare("
            SELECT t.term_id,t.name,t.slug,tt.count
            FROM $wpdb->terms AS t
            JOIN $wpdb->term_taxonomy AS tt
            USING(term_id)
            WHERE tt.taxonomy = 'post_tag'
            ORDER BY t.name ASC
        "));
        foreach ($tagList as $value) {
    ?>
    <li><a href="/tag/<?php echo $value->slug; ?>/"><?php echo $value->name . '<span class="post-count"><span class="paren">(</span>' . $value->count . '<span class="paren">)</span></span>'; ?></a></li>
    <?php } ?>
</ul>

How to Customize the Display of WordPress Archives in Your Sidebar | WPBeginner

月別一覧を「/yyyy/mm/」形式で出力させたかったのだけど、相当調べたつもりだけどうまくいかず、たどり着いたのがこの記事。なんとなくやってることは分かるのだけど、もっとスマートな方法がありそうな気がするので、詳しい説明は省く。当サイトのサイドバーの月別一覧を出力させているコードは以下。

<h1>Archive</h1>
<ul>
    <?php
        global $wpdb;
        $limit = 0;
        $year_prev = null;
        $months = $wpdb->get_results("SELECT DISTINCT MONTH( post_date ) AS month , YEAR( post_date ) AS year, COUNT( id ) as post_count FROM $wpdb->posts WHERE post_status = 'publish' and post_date <= now( ) and post_type = 'post' GROUP BY month , year ORDER BY post_date DESC");
        foreach($months as $month) {
    ?>
    <li><a href="<?php bloginfo('url') ?>/<?php echo $month->year; ?>/<?php echo date("m", mktime(0, 0, 0, $month->month, 1, $month->year)) ?>/"><?php echo date("Y-m", mktime(0, 0, 0, $month->month, 1, $month->year)) . '<span class="post-count"><span class="paren">(</span>' . $month->post_count . '<span class="paren">)</span></span>'; ?></a></li>
    <?php } ?>
</ul>

ヘッダーバナー(画像)をトップページ(index)以外に表示させない方法(wordpress) – バングラデシュに愛の花を咲かせよう

こちらの記事を参考に、トップページ(http://simpleism.net/)以外ではtitle属性に「○○ | SimpleIsm」というように、タイトルとサイト名を出力するようにしている。普通にCodexを見れば分かりそうだけど、何も知らないのでとりあえず「WordPress トップ以外」というような検索の仕方をして、その時に出てきたこちらの記事を参考にさせていただいた。title属性は以下のようなコードを書いて出力させている。

<title>
    <?php if(!is_home()) { echo the_title() . ' | '; } ?>SimpleIsm
</title>

wp_list_categories() を使わずに get_terms() でカテゴリ一覧を表示する | MacBook Air とWordPressでこうなった

カテゴリ一覧を出力させるコードの参考にさせていただいた。この記事のあとにWordPress でカテゴリ一覧を取得する場合は get_terms() じゃなくて get_categories() を使った方がラクチンという記事を書いておられていて、確かにその通りなのだけど、rel属性が付加されて、その属性値(category tag)だとHTML5でinvalidになってしまう。WordPressのカテゴリーリストからrel属性をカットする | LD.ymst.net | 郡山市でホームページを制作している人のブログのコードをfunctions.phpに書くと消せるらしいけど、当時function.php(sが抜けてる)というファイル名で編集しており、全然反映されねー!ってなり、get_terms()で出力させている。パフォーマンスに影響を与えないのであれば、このままでいいかなと思っている。ちなみに、現時点で当サイトではfunctions.phpは使用していない。

<h1>Category</h1>
<ul>
    <?php
        $terms = get_categories();
        foreach ($terms as $term) {
    ?>
    <li><a href="<?php echo get_category_link($term->term_id); ?>"><?php echo $term->name . '<span class="post-count"><span class="paren">(</span>' . $term->count . '<span class="paren">)</span></span>'; ?></a></li>
    <?php } ?>
</ul>

WordPressで指定した固定ページを読み込む方法 | bl6.jp

固定ページ専用のsection要素のid属性を出力させるコードの参考に。

PHPでURLに対するfacebookのいいね!数とtwitterのtweet数を取得する « Just Another Life

各記事のソーシャルボタンをテキストベースで表示したかったため、参考にさせていただいた記事。

WordPressのタグをurlエンコード | Base Views

ソーシャルボタンのhref属性には記事のタイトルが入るのだけど、当然日本語などのマルチバイト文字が入ることもあり、それをエスケープするためのコードを書くときの参考にさせていただいた。

null判定や空文字判定からPHP関数の動きに気を付けることを学ぶ | 村式流 イッパシエンジニアへの道

PHPのisset,empty,is_null – モトクロスとプログラムと粉砕骨折と

ソーシャルボタンではてブのみ、ブックマークされていないと何も表示されないため、ブックマークされていないときでも”0″と表示されるようにしたかったので、そのときの参考にさせていただいた。

ちなみに、ブックマークされていないURL(file_get_contents(URL))をvar_dump($hoge)するとstring(0) ""という結果になる。で、これを”0″と表示させる判定は以下のどれがプログラマ的なのかを同僚に聞いてみた。

if($hoge == null) {
    echo "0";
}

if ($hoge == "") {
    echo "0";
}

if(empty($hoge)) {
    echo "0";
}

で、答えとしては明確に""を判定したいのなら、イコールを3つ使うのが一番厳密だけど、nullや数値型の0のときも”0″と表示したいなら、emptyで問題ないとのこと。全部まとめたのが以下のコード

<div class="social">
    <?php
        $get_twitter = 'http://urls.api.twitter.com/1/urls/count.json?url=' . get_permalink();
        $json = file_get_contents($get_twitter);
        $json = json_decode($json);
        $tweets = $json->{'count'}; //ツイート数

        $get_facebook = 'http://api.facebook.com/restserver.php?method=links.getStats&urls=' . get_permalink();
        $xml = file_get_contents($get_facebook);
        $xml = simplexml_load_string($xml);
        $likes = $xml->link_stat->like_count; //いいね!数

        $get_hatebu = 'http://api.b.st-hatena.com/entry.count?url=' . get_permalink();
        $hatebu = file_get_contents($get_hatebu); //はてなブックマーク数
        if(empty($hatebu)) {
            $hatebu = '0';
        }
    ?>
    <ul>
        <li class="twitter">
            <a href="http://twitter.com/share?text=<?php echo urlencode(the_title("","",0)) ?>&url=<?php the_permalink(); ?>" onclick="window.open(this.href,'window','toolbar=no,width=650,height=450');return false;">t</a>
            <span class="count"><?php echo $tweets ?></span>
        </li>
        <li class="facebook">
            <a href="http://www.facebook.com/sharer.php?u=<?php the_permalink(); ?>&t=<?php echo urlencode(the_title("","",0)) ?>" onclick="window.open(this.href,'window','toolbar=no,width=650,height=450');return false;">f</a>
            <span class="count"><?php echo $likes; ?></span>
        </li>
        <li class="hatena">
            <a href="http://b.hatena.ne.jp/add?mode=confirm&url=<?php the_permalink(); ?>&title=<?php echo urlencode(the_title("","",0)) ?>" onclick="window.open(this.href,'window','toolbar=no,width=510,height=500');return false;">B!</a>
            <span class="count"><?php echo $hatebu; ?></span>
        </li>
    </ul>
</div>

WordPress 記事ページが404エラーで表示されなくなった時の対処法 覚書 | ブログアフィリエイトとメルマガで稼ぐ アフィリエイト講座

タイトルの通り。助かった…。

以上が調べたことまとめ。301リダイレクトとかも調べたけど、それは今回は割愛。コードも冗長的で汚かったりするものもありそうだけど、まずは形にすることが大事だと思うので今のところはOK。調べてトライアンドエラーを繰り返してる間本当に楽しかった!やっぱこういうのだよなーと改めて思った。

それでは、このサイトを作った当時も書いていたけど、参考にさせていただいたサイト及び管理人の方々、どうもありがとうございました。

CMSをMTからWPに変更 & サーバをロリポップ!からさくらインターネットに変更

大分遅くなりましたが、明けましておめでとうございます。

実は去年からちょいちょい作業はしていたのですが、2013年一発目ということで、デザインを変更しました。さらに心機一転、CMSをMovable TypeからWordPressに変更しました。新しく設計し直したので、HTML5で書き直しました。昔と比べて大分柔軟というか、良い意味で適当にマークアップするようになった気がします。何でもかんでもラップ(wrap)したがるようになったのは仕事柄かな。

理由はいくつかありますが、サーバもロリポップ!からさくらインターネットに変更しました。CMSとサーバを変更しましたが、きちんと昔の記事も見られるようにしてあります(MTは静的に出力するので、移行は簡単だった)。その際にPHPファイルへのコンテントネゴシエーションでのリンクで、404が返ってきてしまい、ほとんどのページをPHPで出力しているので、ディレクトリ以外のほぼすべてのページが見られなくなってしまい(HTMLファイルやCSSファイル、画像などは拡張子無しでも見られる)、しばらくハマっておりました。

さくらインターネットでは.htaccessにOptions +MultiViewsは書けないので、にっちもさっちもいかず問い合わせてみたところ、ロリポップ!とのApacheのバージョンの違いによるもののようでした。以下引用。

現在さくらのレンタルサーバサービスでは、新規にお申し込みいただきましたサーバは Apache 2.2 系がインストールされております。

Apache 2 系では、MultiViews のデフォルトの設定が Any から NegotiatedOnly に変更されております。この為、以前にご利用しておられましたサーバが Apache 1.3 系であった場合、動作に違いが出る事が考えられます。

Apache 1.3 系と同様に Any での動作をご希望されます場合は、.htaccess にて、MultiviewsMatch ディレクティブの設定をご変更くださいますようお願いいたします。

▽ 参考リンク
http://httpd.apache.org/docs/2.0/mod/mod_mime.html#multiviewsmatch

さくらインターネット カスタマーセンター

というわけで、.htaccessにMultiviewsMatch Anyを追記したら直りました。問い合わせしてからもググりながらトライアンドエラーしてたのですが、結局解決に2日ぐらいかかってしまいました…。

まぁ直ったのでとりあえず結果オーライです。まだIEでの見た目とか検索用ページとかちょこちょこできてない部分があるのですが、そこは今週中ぐらいに終わればいいかな。それにしてもWordPressもといPHP楽しいー!

ではでは、今年もどうぞよろしくお願いいたします。