小ネタ:レスポンシブのページで改行位置を調整しよう!

ちょっと長めの見出しをレスポンシブサイトで表示すると、
PCでは

こんな感じで一行にすっきり表示されている見出し


スマホなどの幅の狭いデバイスになると

こんな感じで一行にすっきり表
示されている見出し


変なところで強制的に折り返されてしまうことがあります

今までは、対策として<br>タグを書いて幅の広いデバイスではdisplay:noneで隠していたのですが、もっとスマートな方法を思いつきました

<span class=”nobraking”>こんな感じで一行に</span><span class=”nobraking”>すっきり表示されている見出し</span>

と、「ここからここまでは途中改行されるとおかしい」と思う文節をspanでくくっておいて、それぞれにスタイルシートでdisplay:inline-blockを指定しておくのです

こんな感じで一行に
すっきり表示されている見出し

てな感じで回り込んでくれるはずです

Googleが推奨する「戻るボタン対応・SEO」の無限スクロールを使ってみた

無限スクロール、いいですよね。
ところが巷に配布されているプラグインの多くは、ブラウザのバックボタンで戻ったら最初から読み込み直しでヴァー、ということがあってユーザビリティ上よろしくないのです。

Google先生が対応策としてサンプルのJavascriptをつくってくれたので、いろんな案件で使えるようにちょっと手を入れてみました。

元にしたのはこちらのサンプルです。
http://scrollsample.appspot.com/items

解説は下記ブログ記事をご覧ください。
Googleが推奨するSEOに適した無限スクロールの構成方法

  • あらかじめページを分割しておく。いわゆるページネーション
  • 分割されたページのうち1つを表示(1ページ目でなくても見られるようにする)
  • その上下に前のページ、次のページをAjaxで読み込んでいく
  • 今表示している部分が何ページ目に相当するかに合わせて、URLを動的に書き換える

自分なりに書き換えてみたソースは下記です。jQueryを読み込んだ後に実行してください。


$(function (){
//infinite scroll
var prev_data_selector = '.prev.page-numbers'; //「前へ」リンクのaタグのセレクタ
var next_data_selector = '.next.page-numbers'; //「次へ」リンクのaタグのセレクタ
var itemWrapperSelector = '.list_infinite'; //無限ローディングのwrapperとなるタグのセレクタ
var itemWrapper = $(itemWrapperSelector);
var itemInnerSelector = '.list_infinite_item'; //無限ローディングの本体(本文)となるタグのセレクタ
var itemPagerSelector = '.pagination'; //ページャーのセレクタ
var itemPager = $(itemPagerSelector);
var prev_data_url;
var next_data_url;
var next_data_cache;
var prev_data_cache;
var last_scroll = 0;
var is_loading = 0;

if(itemWrapper[0]) {
	prev_data_url = $(prev_data_selector).attr('href');
	next_data_url = $(next_data_selector).attr('href');
	fadeInItem(true);
	initPaginator();
	loadPrevious();
    // if we have enough room, load the next batch
    if ($(window).height()>itemWrapper.height()) {
      if (next_data_url!== '') {
        loadFollowing();
      } 
    }
}

function initPaginator() {
	$(document).off( 'scroll');
  $(document).on( 'scroll', function(){
    // handle scroll events to update content
    var scroll_pos = $(window).scrollTop();
    if (scroll_pos >= 0.9*($(document).height() - $(window).height())) {
      if (is_loading===0) {
		  loadFollowing();
	  }
    }
    if (scroll_pos <= 0) {
      if (is_loading===0) {
		  loadPrevious();
	  }
    }
    // Adjust the URL based on the top item shown
    // for reasonable amounts of items
    if (Math.abs(scroll_pos - last_scroll)>$(window).height()*0.1) {
      last_scroll = scroll_pos;
      $(itemInnerSelector).each(function() {
        if (mostlyVisible(this)) {
          history.replaceState(null, null, $(this).attr('data-url'));
          return(false);
        }
      });
    }
  });
}


function loadFollowing() {
  if (next_data_url){
    is_loading = 1; // note: this will break when the server doesn't respond
    itemPager.hide();
    if (next_data_cache) {
      showFollowing(next_data_cache);
      is_loading = 0;
    } else {
		$.ajax({
			url: next_data_url,
			type: 'get',
			dataType: 'html',
		}).success(function(data){
	        showFollowing(data);
   		     is_loading = 0;
		});
    }
  }
}
    function showFollowing(data) {
	var out_html = $($.parseHTML(data));
      itemWrapper.append(out_html.find(itemWrapperSelector).filter(itemWrapperSelector)[0].innerHTML);
	  initPaginator();
      next_data_url = out_html.find(next_data_selector).filter(next_data_selector).attr('href');
      next_data_cache = false;
		$.ajax({
			url: next_data_url,
			type: 'get',
			dataType: 'html',
		}).success(function(preview_data){
	        next_data_cache = preview_data;
		});
    }

function loadPrevious() {
  if (prev_data_url){
    is_loading = 1; // note: this will break when the server doesn't respond
    itemPager.hide();
    if (prev_data_cache) {
      showPrevious(prev_data_cache);
      is_loading = 0;
    } else {
		$.ajax({
			url: prev_data_url,
			type: 'get',
			dataType: 'html',
		}).success(function(data){
	        showPrevious(data);
   		     is_loading = 0;
		});
    }
  }
}
    function showPrevious(data) {
	var out_html = $($.parseHTML(data));
      itemWrapper.prepend(out_html.find(itemWrapperSelector).filter(itemWrapperSelector)[0].innerHTML);
	  initPaginator();
      var item_height = $(itemInnerSelector + ':first').height();
      window.scrollTo(0, $(window).scrollTop()+item_height); // adjust scroll
	  prev_data_url = out_html.find(prev_data_selector).filter(prev_data_selector).attr('href');
      prev_data_cache = false;
		$.ajax({
			url: prev_data_url,
			type: 'get',
			dataType: 'html',
		}).success(function(preview_data){
	        prev_data_cache = preview_data;
		});
    }

function mostlyVisible(element) {
  var scroll_pos = $(window).scrollTop();
  var window_height = $(window).height();
  var el_top = $(element).offset().top;
  var el_height = $(element).height();
  var el_bottom = el_top + el_height;
  return ((el_bottom - el_height*0.25 > scroll_pos) && 
          (el_top < (scroll_pos+0.5*window_height)));
}


});

グループを繰り返せるカスタムフィールド用プラグインを探してみた

みんな使っているのになぜか標準仕様がおざなりで使えない「Wordpressのカスタムフィールド」、プラグインをいろいろためしているのですが、グループ化したカスタムフィールドを繰り返す(「画像とキャプションの組み合わせ」を任意の個数追加、ってかんじ)のを実現できるもの、となるとかなり候補が絞られます。CMSとして使う際には頻出テクニックなんだけどね。

Custom Field Suite

http://docs.customfieldsuite.com/

おそらく現状最良の選択。ただ、細かいけど困るバグが多くてバグ対応も遅いのがなあ。「必須」にチェックを入れているのに保存したらチェックが消えている、とか。「次のアプデで対応します」て言ったきり1ヶ月放置されてたり。

グループ化した時だけテンプレートでの出力時に独自の関数を使うが、他はpost_customのままでいけそうなのも好感触。最初にグループ化するための操作が少しだけわかりづらいが、わかってしまえばOKだし、更新する人には関係ないことなので大丈夫。

※備考:「チェックボックスのリスト」は作れません。カスタマイズして追加する方法もあるようですが、ここはWordpress本来の仕様である 「カスタムフィールドは名前:値の1対1の組み合わせ」というのを尊重して、各チェックボックスの項目ごとに「真/偽(簡易チェックボックス)」を増やし て対応してみます

ACF

https://www.advancedcustomfields.com/

超有名プラグインだけど、繰り返しフィールド機能は有料。しかも内部的に独自のデータ処理をやっているみたいで、他のプラグインへの乗り換えが難しかったりWordpress標準の関数が一部使えなかったりと悪い評判も聞いたりする。

Smart Custom Fields

http://2inc.org/blog/category/products/wordpress_plugins/smart-custom-fields/

必要最小限の機能を、できるだけWordpressの仕様に則って実現するというコンセプトなので後々乗り換えることになっても安心そう。
ただし、現状では「必須項目」を設定できないので、仕事としての制作にはまだ使えないと思う。

カスタムフィールドテンプレート

http://ja.wpcft.com/

おれの環境では本文が文字化けして使えなかった。同様の報告例あり。
それと、エディタ画面でのボタン配置や操作感が悪く、仕事として作る際にはお客さんに説明しづらい。
プラグインは無料だがマニュアルが有料。