JQuery MobileでつくったページにFacebookのJavaScript SDKを組み込む場合は、Androidのブラウザで画面の向き(Screen Orientation)を変えると、ページ幅が正しく調整されないことがあるので注意したい。
画面を横にしたときに広がったページ幅が、縦に戻しても元に戻らないのだ。この現象は、JQuery Mobileの1.0 RC2でも1.0 finalでも起こる。
どうやらbodyタグの中にscriptタグがあることが、この問題の原因となっているようだ。
<script style="width:0px;">とやったら、多くの場合にこの現象を防ぐことができることを確認した。ただ、完全に防ぐことに成功したわけではなく、たまにページ幅が正しく調整されないこともある。
2011-11-19
iOS5に組み込まれたTwitter機能をアプリで使う
iOS5には、Twitterとの連携機能が含まれている。これを使えば、ユーザはアプリごとにログインを行わなくて済むようになる。
Twitterとの連携機能を、アプリに組み込むのは簡単だ。Twitter.frameworkへのリンクを追加した後で、おおよそ次のようなコードを書けばよい。
#import <Twitter/TWTweetComposeViewController.h> - (void)sendTweet { TWTweetComposeViewController *tweetViewCtrl = [[[TWTweetComposeViewController alloc] init] autorelease]; [tweetViewCtrl setInitialText:@"デフォルトのテキスト"]; [self presentModalViewController:tweetViewCtrl animated:YES]; }
2011-11-18
iPhoneアプリでTwitterやFacebookの共有機能を利用
iPhoneアプリの中で、TwitterやFacebookの共有機能を利用したい場合、ShareKitというライブラリを使うと簡単に実装できる。
しかしこのShareKit、iOS5でまともに動作しなくなってしまった。Twitterなどの共有をするためにモーダルダイアログを表示した後、キャンセルボタンを押してもダイアログが消えず、元の画面に戻れなくなってしまったのだ。現時点での最新版、バージョン0.2.1ではこの問題が修正されていない。
調査したところ、iOS5.0からUIViewController.parentViewControllerが、nilを返すようになったのが原因で正常に動作しなくなったのだと分かった。iOS4.3までは、parentViewControllerは、親のUIViewControllerを返していた。
幸いなことにShareKitはソースが公開されており、コードを数行の修正すれば問題を解決できる。修正するべき箇所は、SHK.mファイルの、-(void)hideCurrentViewControllerAnimated:(BOOL)animated の内部だ。これを次のように修正すればよい。
しかしこのShareKit、iOS5でまともに動作しなくなってしまった。Twitterなどの共有をするためにモーダルダイアログを表示した後、キャンセルボタンを押してもダイアログが消えず、元の画面に戻れなくなってしまったのだ。現時点での最新版、バージョン0.2.1ではこの問題が修正されていない。
調査したところ、iOS5.0からUIViewController.parentViewControllerが、nilを返すようになったのが原因で正常に動作しなくなったのだと分かった。iOS4.3までは、parentViewControllerは、親のUIViewControllerを返していた。
幸いなことにShareKitはソースが公開されており、コードを数行の修正すれば問題を解決できる。修正するべき箇所は、SHK.mファイルの、-(void)hideCurrentViewControllerAnimated:(BOOL)animated の内部だ。これを次のように修正すればよい。
- (void)hideCurrentViewControllerAnimated:(BOOL)animated { if (isDismissingView) { return; } if (currentView != nil) { // Dismiss the modal view if ([currentView parentViewController] != nil) { self.isDismissingView = YES; [[currentView parentViewController] dismissModalViewControllerAnimated:animated]; } else if ([currentView presentingViewController] != nil) { self.isDismissingView = YES; [[currentView presentingViewController] dismissModalViewControllerAnimated:animated]; } else { self.currentView = nil; } } }
2011-11-17
FacebookアプリとTwitterアプリのUser-Agent
iPhoneのFacebookアプリとTwitterアプリはブラウザ機能を持っていて、友達が共有したリンクを開くときはこのブラウザを利用する人も多い。
このアプリのブラウザは、それぞれ独自のUserAgentを持っているようだ。自分のiPhoneで確認してみると、次のようなUser-Agentが取得できた。
このアプリのブラウザは、それぞれ独自のUserAgentを持っているようだ。自分のiPhoneで確認してみると、次のようなUser-Agentが取得できた。
- Twitter for iPhone
- Mozilla/5.0 (iPhone; CPU iPhone OS 5_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9A405 Twitter for iPhone
- Facebook for iPhone
- Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_0_1 like Mac OS X; ja_JP) AppleWebKit (KHTML, like Gecko) Mobile [FBAN/FBForIPhone;FBAV/4.0.2;FBBV/4020.0;FBDV/iPhone3,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/5.0.1;FBSS/2; FBCR/
User-Agentによってサーバー側で処理を変える場合に利用できそうだ。
2011-11-09
Conversion to Dalvik format failed with error 1 再来
Androidでrelease用にビルドをしたときに限って、「Conversion to Dalvik format failed with error 1」というエラーになる問題が再発生した。以前にこのエラーに見舞われたときは、コンソールで、eclipse.exe -clean という具合に起動オプション付きでeclipseを立ち上げたら解決したが、今回はそれでも解決しなかった。プロジェクトをクリーンしたりFix Project Propertiesを実行したり色々ためしたが駄目だった。
気になったのは、debugのときは正常にビルドできるのに、releaseモードで失敗するということだ。これは何故だろうと思って調べたら、proguardを使っているのがエラーの原因だとわかった。proguardはreleaseモードでのみ動作するため、ここで失敗しているのだ。
proguard.cfgに、名前を書き換えないクラスなどを指定すれば、おそらく正常にビルドできるはず。たとえば、layout.xml内で参照しているクラスなどは、名前を書き換えてはいけないクラスに相当する。
だが困ったことに、このプロジェクトはandroid-support-v4.jarを参照していた。これを参照する場合に、proguard.cfgをどのように記述したらいいのか、さっぱり分からなかった。結局挫折して、proguardを使うのをあきらめた。
CentOS5にmemcachedをインストールする
どうやら昔はyumでmemcachedをインストールできたみたいだが、いまはrpmforgeを追加してもmemcacheが見つからない。そこで、次のようにしてCentOS5にmemcachedをインストールした。
なぜだか知らないが、wget http://memcached.org/latest でソースをダウンロードした場合は上手くmakeできなかった。
起動時にmemcachedが自動で起動されるように次の設定もした。
今回の目的は、Djangoでcacheを利用することだったので、yumで、python-memcachedのインストールも行った。
# yum -y install libevent-devel # wget http://memcached.googlecode.com/files/memcached-1.4.9.tar.gz # tar -zxvf memcached-1.4.9.tar.gz # cd memcached-1.4.9 # ./configure # make # make install
なぜだか知らないが、wget http://memcached.org/latest でソースをダウンロードした場合は上手くmakeできなかった。
起動時にmemcachedが自動で起動されるように次の設定もした。
# vi /etc/rc.d/init.d/memcached =====ここからviで追加===== #!/bin/bash # # memcached # # chkconfig: 345 80 20 # description: memcached TARGET=memcached DST_BIN=/usr/local/bin/${TARGET} EXEC_USER=apache CACHE_SIZE=64 start() { echo -n "Starting ${TARGET}: " ${DST_BIN} -d -u ${EXEC_USER} -m ${CACHE_SIZE} echo } stop() { echo -n "Shutting down ${TARGET}: " killall ${TARGET} echo } case "$1" in start) start ;; stop) stop ;; restart) stop start ;; *) echo "Usage: `basename $0` {start|stop|restart}" >&2 exit 1 esac exit 0 =====ここまで===== # chmod 755 /etc/rc.d/init.d/memcached # chkconfig --add memcached # chkconfig memcached on # service memcached start
今回の目的は、Djangoでcacheを利用することだったので、yumで、python-memcachedのインストールも行った。
# yum -y install python-memcached
CentOS5にGITをインストールする
# rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt
# wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.i386.rpm
# rpm -i rpmforge-release-0.5.2-2.el5.rf.i386.rpm
# yum -y install git
次のようにして、
# vim /etc/yum.repos.d/rpmforge.repo
==ここから===
#enabled = 1
enabled = 0
===
# yum -y --enablerepo=rpmforge install git
# wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.i386.rpm
# rpm -i rpmforge-release-0.5.2-2.el5.rf.i386.rpm
# yum -y install git
次のようにして、
# vim /etc/yum.repos.d/rpmforge.repo
==ここから===
#enabled = 1
enabled = 0
===
# yum -y --enablerepo=rpmforge install git
2011-11-04
Apacheのログに処理時間を残す
Apacheのaccess_logに、レスポンスを返すまでの処理時間が記録されるようにするには、httpd.confの設定を少し変更すればよい。
LogFormatで、「%D」と指定することによって、処理時間がマイクロ秒単位で記録される。
Linuxの場合は、
# vi /etc/httpd/conf/httpd.conf
とやって、
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined
と書く。httpd.confの前後の部分も抜粋すると次のようになる:
LogFormatで、「%D」と指定することによって、処理時間がマイクロ秒単位で記録される。
Linuxの場合は、
# vi /etc/httpd/conf/httpd.conf
とやって、
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined
と書く。httpd.confの前後の部分も抜粋すると次のようになる:
# The following directives define some format nicknames for use with # a CustomLog directive (see below). # LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent # "combinedio" includes actual counts of actual bytes received (%I) and sent (%O); this # requires the mod_logio module to be loaded. #LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
2011-10-30
Conversion to Dalvik format failed with error 1
EclipseでAndroidアプリのビルドを試みたら、「Conversion to Dalvik format failed with error 1」というエラーになってしまい困っていたが、
eclipse.exe -clean
というように起動オプションをつけてeclipseのキャッシュを消去したら解決した。
*後日わかったことだが、このやり方ではエラーが解決しない場合もある。エラーで困って検索しているうちに、この記事に辿り着いてしまった方は、こちらの記事も読んでいただけると解決に近づくかもしれない。http://hello-hello-world.blogspot.com/2011/11/conversion-to-dalvik-format-failed-with.html
2011-10-24
Django1.3の管理サイトが便利すぎる
Djangoの管理コンソールは昔から便利だと思っていたが、久しぶりに最新版の1.3.1を試してみたら、管理コンソールが進化してものすごく便利になっていた。
とくに、ユーザが自分で生成したオブジェクトだけを表示・編集できるようになったことはすばらしい。
バージョン1.3がリリースされてから、かなり時間が経つが、ドキュメントが日本語化されていないようなので、このことを知らない人もいるかもしれない。
以前の管理コンソールは、すべてのオブジェクトにアクセス可能なサイト運営者用にしか使えない印象だったが、いまはサイトにユーザ登録した利用者用にも使えそうだ。
ユーザが生成したオジェクトのみを管理サイトでアクセス可能にするには、django.contrib.admin.ModelAdminを継承してたクラスを定義して、queryset、has_add_permission、has_change_permission、has_delete_permissionなどをオーバーライドする。querysetをオーバーライドするだけで、表示を絞り込むことはできるが、has_add_permissionなどで権限を正しく設定しておかないといけない。
ドロップダウンリストなどに他のユーザのオブジェクトが表示されてしまうのを直したい場合は、さらに、formfield_for_foreignkeyなどをオーバーライドすればよい。
Djangoの管理サイトは、以前よりもさらに便利で強力になった。しかし、もちろんすべてのニーズを満たすというわけではない。
たとえば、list_filterで絞り込みを設定した場合にも、他のユーザのオブジェクトが表示されてしまうのだが、これを防ぐ簡単な手立てはどうやらなさそうだ。
また、DBのテーブルを列挙するページ構成は、ユーザにとって使い勝手が悪い場合が多そうだ。ページ構成は、オブジェクトの階層構造に対応していることが望ましいと思うのだが、これを実現するには割りと大掛かりなカスタマイズが必要になると思われる。
2011-10-22
MySQL-pythonをインストール
djangoをMySQLで動かすには、MySQLdbが必要みたいなので、
pip install MySQLdb
とか、
pip install MySQL-python
とか打ってみたのだがエラーになる。
次のサイトで見つけたwindows用のインストーラ実行したら無事にインストールできた。
http://servut.us/akx/2010/09/mysqldb-windows-binaries-python-26-27/
CentOSでも、pipを使うとエラーになってしまったが、
yum -y install MySQL-python
とやってインストールできた。
pip install MySQLdb
とか、
pip install MySQL-python
とか打ってみたのだがエラーになる。
次のサイトで見つけたwindows用のインストーラ実行したら無事にインストールできた。
http://servut.us/akx/2010/09/mysqldb-windows-binaries-python-26-27/
CentOSでも、pipを使うとエラーになってしまったが、
yum -y install MySQL-python
とやってインストールできた。
2011-10-05
Snow Leopard + python2.5に、PILとsslモジュールを入れる
MacBook ProにWindows7をインストールするために、Boot Campでパーティションを切ろうとしたら失敗したため、リカバリしてOSX Snow Leopardを再インストールすることになった。開発環境を再構築するのには時間がかかるし神経も消耗する。
Google AppEngine(Python)の開発環境を整えるのがとくに大変だ。PILとsslをインストールしようとしたのだが、easy_installを使っても、setup.pyを使っても失敗してしまった。昔どうやってインストールしたのかよく覚えていないが、gcc4.0を使ってコンパイルしたような記憶がおぼろげにある。おそらく、python2.5が古いXcodeでビルドされているため、gcc4.0を使ってコンパイルしないとインストールできないということなのだろう。
Xcode4にはgcc4.0が含まれていないので、まずはXcode3をインストールした(gcc-4.0のためだけにXcode3をまるごと入れた)。そして、
export CC=/usr/bin/gcc-4.0
とターミナルに入力してから、easy_installやらsetup.pyやらを使ったら、なんとかインストールできたようだ。
Xcode4にはgcc4.0が含まれていないので、まずはXcode3をインストールした(gcc-4.0のためだけにXcode3をまるごと入れた)。そして、
export CC=/usr/bin/gcc-4.0
とターミナルに入力してから、easy_installやらsetup.pyやらを使ったら、なんとかインストールできたようだ。
2011-09-30
Dropboxでバックアップをとって大失敗
Dropboxに大事なデータを入れて、イザというときのためのバックアップもとれているつもりだったのだが、これが大失敗だった。転送速度が遅すぎる!
ダウンロードが0.1KB/秒弱で、500MBのデータを同期するのに2ヵ月以上かかると計算になる。ユーザーが増えすぎて回線がパンクしているのだろうか?いずれにせよ、これでは使い物にならない。有料サービスに申し込んで、もっと大きなデータを保存していたりしたら同期に1年くらいかかってしまうことになるだろう。
Dropboxは便利なサービスだと思っていたが、思わぬ落とし穴があった。別のサービスに乗り換えたほうが良さそうだ思ってSugarSyncにアカウントとつくってみた。無料で5GB使えるということでDropboxよりも太っ腹だし、同期対象のフォルダも細かく設定できるようだ。速度に問題がなく、安定して使えればいいんだけど、これはまだ試していないのでわからない。
2011-09-13
Pythonでsite-packagesの場所を調べる
シェル(ターミナル)で次のコマンドを打ち込めば、Pythonのsite-packagesの場所が分かる。
python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
複数のバージョンのPythonがインストールされている場合は、「python -c」の部分を、「python2.5 -c」とか「python2.7 -c」とかにすればよい。
python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
複数のバージョンのPythonがインストールされている場合は、「python -c」の部分を、「python2.5 -c」とか「python2.7 -c」とかにすればよい。
2011-08-04
Chrome Extensionのポップアップを明示的に閉じる
Chrome Extensionでpupup.htmlを明示的に閉じるためには、window.close() を呼べばよい。
ここで注意したいのは、Chrome Extension APIで多用されるコールバック関数の処理がちゃんと終了してからwindow.close() を呼ぶ必要があるということだ。そうしないと、ブラウザがクラッシュすることさえあるようだ。
たとえば、Webページをタブに開いた後で、popup.htmlを閉じる場合は、次のようにコールバック関数の中でwindow.close() を実行する必要がある。
ここで注意したいのは、Chrome Extension APIで多用されるコールバック関数の処理がちゃんと終了してからwindow.close() を呼ぶ必要があるということだ。そうしないと、ブラウザがクラッシュすることさえあるようだ。
たとえば、Webページをタブに開いた後で、popup.htmlを閉じる場合は、次のようにコールバック関数の中でwindow.close() を実行する必要がある。
chrome.tabs.create( {"url": "http://bit.ly/oiWu31"}, function(tab) { window.close(); } );一挙にショッピング検索でやっているように、複数のタブを開く場合は、すべてのタブが開いたことを確認した後で、window.close() を呼ぶ必要がある。これには、setInterval() を使うことになるだろう。
2011-07-29
日本向けのChrome Extensionを公開
自作のChrome Extension第三号を公開した。こんどは日本向けのショッピング拡張機能で、名前は「一挙にショッピング検索」。
先日公開したPriceComparer USAや、PriceComparer EUとは若干コンセプトが異なる。アマゾン、楽天、ヤフオクなどのショッピングサイトを一挙に検索して、それぞれのWebページをタブに表示するのが、この拡張機能で商品のオファーは行わない。商品オファー機能を組み込むことも考えたが、それは別の独立した拡張機能として提供した方がいいのではないかと現時点では考えている。
先日公開したPriceComparer USAや、PriceComparer EUとは若干コンセプトが異なる。アマゾン、楽天、ヤフオクなどのショッピングサイトを一挙に検索して、それぞれのWebページをタブに表示するのが、この拡張機能で商品のオファーは行わない。商品オファー機能を組み込むことも考えたが、それは別の独立した拡張機能として提供した方がいいのではないかと現時点では考えている。
2011-07-27
ヨーロッパ向けにShopping Chrome Extensionを公開
自作のChrome Extension第二号を公開した。ヨーロッパ向けのショッピング拡張機能で、名前はPriceComparer EU。先日公開したPriceComparer USAのヨーロッパ版だ。機能はほとんど同じだが、コードはだいぶ書き換えたため、公開までに時間がかかってしまった。
日本向けのExtensionも近々公開する予定だ。
日本向けのExtensionも近々公開する予定だ。
2011-07-26
AppEngineのAsync Datastore APIは積極的に使いたい
Google AppEngineの進化は速い。久しぶりにドキュメントを見ると新しい機能がたくさん追加されていて驚くことがある。昔つくったWebサービスも、新しい機能を使ってより良いものにできる場合がある。
すでに最新の機能というわけではないのだが、Async Datastore APIを使えば、従来のコードをちょっと換えるだけでレスポンスを速くすることができるかもしれない。AppEngineは、データの読み込みは速いが、書き込みや削除に時間がかかるので、非同期化できる部分は非同期化するのが望ましい。db.put(model) と書いていた部分を、 db.put_async(model) と書き換えるだけの修正でも、効果が期待できる。
すでに最新の機能というわけではないのだが、Async Datastore APIを使えば、従来のコードをちょっと換えるだけでレスポンスを速くすることができるかもしれない。AppEngineは、データの読み込みは速いが、書き込みや削除に時間がかかるので、非同期化できる部分は非同期化するのが望ましい。db.put(model) と書いていた部分を、 db.put_async(model) と書き換えるだけの修正でも、効果が期待できる。
2011-07-23
Chrome ExtensionでContentScriptを実行する際の注意点
Chrome ExtensionのContent Scriptでは、JavaScriptの変数などは他から隔絶された空間に定義されるため競合の心配がない。しかし、DOMは共有されるので注意が必要だ。たとえば、
Content ScriptでDOMを操作する場合、考え得る問題のすべてを防ぐことは難しいかもしれない。しかし、DOMが共有されていることに注意してコーディングを行えば問題が生じる確率をかなり下げることができるだろう。
document.body.onmousemove = myFunc;というようにイベントを登録すると、ページや他のExtensionのイベントを上書きしてしまうので、
document.body.addEventListener( "mousemove", myFunc, false );とするべきだ。この手のバグは、すべてのWebページで問題を起こすわけではないので、テストをしても発見が難しい。
Content ScriptでDOMを操作する場合、考え得る問題のすべてを防ぐことは難しいかもしれない。しかし、DOMが共有されていることに注意してコーディングを行えば問題が生じる確率をかなり下げることができるだろう。
2011-07-15
Chrome Extensionの内部からオプション・ページを開く
Chrome Extensionの内部に設定ボタンをつくったり、あるいは初回に起動したときに、オプション・ページ(options.html)をタブに表示するには、次のようにして拡張機能の内部からオプション・ページを開けば良い。
2011-07-14
CSSでline-heightには単位を指定しない
複数行にわたる文章にサイズの異なる文字が混在する場合、ブラウザの設定で文字サイズを変更すると文字が重なってしまうことがある。こうした場合は、line-heightのプロパティの値の指定に原因がある可能性が高い。
{line-height: 1.5em;} や {line-height: 20px;} のように単位付きで値を指定するとときと、{line-height: 1.5;} のように単位なしで値を指定するときとでは、子孫要素への継承のされ方が異なる。単位なしの場合は子孫要素で高さが再計算されるのに対して、単位ありの場合は子孫要素にも同じ値が適用される。通常は、単位なしでline-heightの値を指定することで問題を解決できる。
{line-height: 1.5em;} や {line-height: 20px;} のように単位付きで値を指定するとときと、{line-height: 1.5;} のように単位なしで値を指定するときとでは、子孫要素への継承のされ方が異なる。単位なしの場合は子孫要素で高さが再計算されるのに対して、単位ありの場合は子孫要素にも同じ値が適用される。通常は、単位なしでline-heightの値を指定することで問題を解決できる。
例1:これはline-heightを1.2に指定した場合:
font-sizeを大きくしても文字が重ならないはず
コードはこちら:
font-sizeを大きくしても文字が重ならないはず
コードはこちら:
例2:これはline-heightを1.2emに指定した場合:
font-sizeを大きくすると文字が重なってしまうはず
コードはこちら:
font-sizeを大きくすると文字が重なってしまうはず
コードはこちら:
2011-07-08
Chrome Extensionを公開
最初の自作のChrome Extensionが完成しました。PriceComparer USAという名称でChrome Web Storeに公開してあります。
価格比較を行うショッピング拡張機能なのですが、対象ユーザーはアメリカ人です。
この拡張機能と同じ発想で、日本やヨーロッパ向けの拡張機能を近々公開する予定です。
価格比較を行うショッピング拡張機能なのですが、対象ユーザーはアメリカ人です。
この拡張機能と同じ発想で、日本やヨーロッパ向けの拡張機能を近々公開する予定です。
2011-07-07
CSSにおけるマージンの相殺の規則
CSSにおいてマージンの相殺される際の基本的な規則は下記の通り:
相殺後に適用されるマージンの値は下記の方法で計算される。
参考文献:
- 水平方向(左右)のマージンは相殺されない(マージンの相殺が行われるのは垂直方向のみ)。
- パディング、ボーダーによって分離されず隣接するマージンにおいては、親ボックスとの間でも相殺が生じる。
- floatされたボックスマージンは相殺されない。
- overflow属性の値に"visible"以外が指定された要素は、その子要素とのあいだでマージンを相殺しない。
- 絶対配置(position:absolute;)されたボックスのマージンは相殺されない。
- inline-block要素(display:inline-block;と指定されたボックス)のマージンは相殺されない。
- クリアランスが与えられた要素の上のマージンは相殺されない。
- ルート要素のマージンは相殺されない。
相殺後に適用されるマージンの値は下記の方法で計算される。
- 隣接するマージンがすべて正の値の場合は、もっとも大きいマージンの値が適用される。
- 隣接するマージンが負と正の値の組み合わせの場合は、両方を合計した値が適用される。
- 隣接するマージンがすべて負の値の場合は、もっとも小さい(絶対値が最大のもの)マージンの値が適用される。
参考文献:
:link、:visited、:hover、:activeの記述順
:link、:visited、:hover、:activeといった擬似クラスを指定する場合は、正しい順序で指定しないと効果が打ち消されて意図した結果が得られなくなる。
a要素にそれぞれの擬似クラスを指定する場合、通常は次のような順序で行う。
a要素にそれぞれの擬似クラスを指定する場合、通常は次のような順序で行う。
もし、マウスポインタが重なったりアクティブになったりしても、すでに訪問済みのリンクのスタイルを変化させたくないというのであれば、:visitedを最後に記述すればよい。
2011-07-06
CSSで指定したスタイルが適用される優先順位
CSSで指定したスタイルが適用される優先順位についてまとめてみる。参考にしたのは『Web標準XHTML+CSSデザイン クリエイターが身につけておくべき新・100の法則』という本の66〜67ページ。
- CSSの提供元による優先順位
下記の順に優先される。 - Webページの制作者が作成した「制作者スタイルシート」
- Webブラウザのユーザーが作成した「ユーザースタイルシート」
- Webブラウザがデフォルトで適用する「デフォルトスタイルシート」
- 個別性による優先順位
個別性の高いものが優先される。(詳細は後述) - 記述位置による優先順位
あとから出てきたものが優先される。 - !importantルール
!important宣言の付いたスタイルが最優先される。
!important宣言によって提供元による優先順位が入れ替わる。 - ユーザースタイルシート(!important宣言付き)
- 制作者スタイルシート(!important宣言付き)
- 制作者スタイルシート
- ユーザースタイルシート
- デフォルトスタイルシート
重要だが少々ややこしいのは、「個別性による優先順位」のルールだ。このルールは、ある要素に対するスタイルの指定が競合する場合に、より「個別性」の高いスタイルが優先されるという原則にもとづく。個別性は以下のようにして、最大4桁の正整数で表現される(値が大きいほど個別性が高い)。
- 要素に対して直接style属性が指定された場合は、1000の位を1つカウント
- セレクタに含まれているid属性の数だけ、100の位をカウント
- セレクタに含まれているid以外の属性と擬似クラスの数だけ、10の位をカウント
- セレクタに含まれている要素、擬似要素の数だけ、1の位をカウント
記述例 | 1000の位 | 100の位 | 10の位 | 1の位 | 個別性 |
---|---|---|---|---|---|
* { } | 0 | 0 | 0 | 0 | 0 |
li { } | 0 | 0 | 0 | 1 | 1 |
li:first-line { } | 0 | 0 | 0 | 2 | 2 |
ul li { } | 0 | 0 | 0 | 2 | 2 |
ul ol+li { } | 0 | 0 | 0 | 3 | 3 |
p[class="memo"] { } | 0 | 0 | 1 | 1 | 11 |
ul ol li.menu { } | 0 | 0 | 1 | 3 | 13 |
li.menu.service { } | 0 | 0 | 2 | 1 | 21 |
#example { } | 0 | 1 | 0 | 0 | 100 |
div#example { } | 0 | 1 | 0 | 1 | 101 |
style="" | 1 | 0 | 0 | 0 | 1000 |
HTMLの要素に直接aligh属性などを指定した場合の個別性の値は0と計算される。したがって、HTML属性の指定と、CSSのスタイル指定が競合する場合は、CSSが優先される。
Chrome Extensionのポップアップでリンクを有効化(ポップアップ内で遷移)
「Chrome Extensionのポップアップでリンクを有効化」では、ポップアップのリンクがクリックされたときに、新しく開いたブラウザのタブにページを表示する方法を紹介したが、iframeを利用すれば、ポップアップの中でページ遷移を行うこともできる。
スマートフォン用のWebページを持っているのであれば、それをそのままiframeに表示するというのも悪くないかもしれない。
スマートフォン用のWebページを持っているのであれば、それをそのままiframeに表示するというのも悪くないかもしれない。
2011-07-03
Chrome Extensionのポップアップでリンクを有効化
Chrome Extensionのポップアップ・ウィンドウ(popup.html)にリンク(アンカー・タグ)を仕込んでも、そのままではページ遷移することができない。リンクをクリックしても、何も起こらない。
リンクがクリックされたときに、タブにリンク先ページが表示されるようにするには、popup.htmlのhead要素に<base target="_blank" />を付け足せばよい。 base要素にtarget="_blank"を指定する代わりに、a要素にtarget="_blank"を指定するのでもよい。
なお、target="_self"を指定しても、ポップアップの中でページ遷移を行うことはできない。
ページ内で遷移を行いたい場合は、ここで紹介するようにiframeを使えば良い。
リンクがクリックされたときに、タブにリンク先ページが表示されるようにするには、popup.htmlのhead要素に<base target="_blank" />を付け足せばよい。 base要素にtarget="_blank"を指定する代わりに、a要素にtarget="_blank"を指定するのでもよい。
なお、target="_self"を指定しても、ポップアップの中でページ遷移を行うことはできない。
ページ内で遷移を行いたい場合は、ここで紹介するようにiframeを使えば良い。
2011-07-01
Chrome Extensionで現在表示中のページのURLとタイトルを取得
Chrome Extensionで、アイコンがクリックされたときに現在表示中のページのURLとタイトルを使って何かやりたい場合は、以下のようにしてURLとタイトルを取得する。
document.titleやlocation.hrefを、popup.html(アイコンをクリックしたときに表示されるポップアップ)で呼び出しても、表示中のタブのURLやタイトルを取得することはできないので要注意。
2011-06-24
アフィリエイト・サイトのAPIは使い物にならない
商品を検索するのにアフィリエイト・サイトのAPIを使えないかどうか検討してみたのだが、なかなか難しい。
リンクシェアなどのいつくかのアフィリエイト・サイトは、APIを備えていて、提携中のECサイトを横断して検索することができる。しかし、この検索機能を利用して商品検索を行うのにはいくつか問題がある。
まず、キーワードと関連度が高い順にソートを行うことができない。商品名でソートしたり、価格でソートを行うのでは、検索語と関連性の薄い情報が並んでしまい、ユーザーが望んでいる結果が得られないのだ。
では、JANやISBNなどの商品コードで検索する場合はどうかというと、商品コードを登録しているECサイトが少ないために検索にほとんど何もヒットしない。
また、アフィリエイト・サイトのAPIは、速度が遅いという問題を抱えていることが多いようだ。
現在のところ、アフィリエイト・サイトのAPIは、使い物にならないという結論になりそうだ。
リンクシェアなどのいつくかのアフィリエイト・サイトは、APIを備えていて、提携中のECサイトを横断して検索することができる。しかし、この検索機能を利用して商品検索を行うのにはいくつか問題がある。
まず、キーワードと関連度が高い順にソートを行うことができない。商品名でソートしたり、価格でソートを行うのでは、検索語と関連性の薄い情報が並んでしまい、ユーザーが望んでいる結果が得られないのだ。
では、JANやISBNなどの商品コードで検索する場合はどうかというと、商品コードを登録しているECサイトが少ないために検索にほとんど何もヒットしない。
また、アフィリエイト・サイトのAPIは、速度が遅いという問題を抱えていることが多いようだ。
現在のところ、アフィリエイト・サイトのAPIは、使い物にならないという結論になりそうだ。
2011-06-22
Chrome ExtensionでAdSenseを使うのは規約違反
数日前からChromeブラウザ用の拡張機能を作成している。
Androidなどのスマートフォンに比べるとマーケットが小さい印象だが、作成したアプリでお金が入ってくるようにしたいと考えている。
広告を表示するのが手っ取り早いだろうと考えて、GoogleのAdSenseをExtension内に表示させられるか調べたのだが、残念ながらこれは利用規約違反になってしまうようだ。Google AdSense プログラム ポリシーの「トラフィックソース」という項目で次のことが禁止されている。
広告収入を得る場合は、AdSense以外のサービスを利用する必要がありそうだ。
Androidなどのスマートフォンに比べるとマーケットが小さい印象だが、作成したアプリでお金が入ってくるようにしたいと考えている。
広告を表示するのが手っ取り早いだろうと考えて、GoogleのAdSenseをExtension内に表示させられるか調べたのだが、残念ながらこれは利用規約違反になってしまうようだ。Google AdSense プログラム ポリシーの「トラフィックソース」という項目で次のことが禁止されている。
ツールバーなどのソフトウェア アプリケーションを操作した結果として、Google 広告、検索ボックス、検索結果などを表示することGoogle GroupでもAdSenseを使うのは規約違反になるという議論がされているのを見つけた(英語)。
広告収入を得る場合は、AdSense以外のサービスを利用する必要がありそうだ。
登録:
投稿 (Atom)