2012年2月20日月曜日

css3のセレクタでツリーリストを実装してみる

cssだけでできそうだなぁってものをcssだけで実現するのはロマンです.

css3で追加された各種セレクタを応用すると上位階層をチェックすると下位要素が表示されるというツリー構造の記述が簡単に出来る.
入れ子になったul要素の前にチェックボックスを配置し,「チェックされていないチェックボックスの後ろにあるul要素を隠す」と記述するだけで大体動作する.
…のだが,実はここからが面倒なのな.
  • チェックボックスの見た目を変更するためinput[type="checkbox"]は非表示とするが,後続のlabel要素を関連付けてクリック可能としている.
  • 下位ul要素を含むli要素にはclass=direcを設定しておき,スタイルの差別化を行う.
  • ツリー表示を実現するため,li要素のborderとli要素のafter擬似要素のborderを使う.
  • label要素のbefore擬似要素とli要素のbefore擬似要素を使ってアイコンの表示を行う.
それで出来たのが下のサンプル.出来ればチェックボックスとlabel要素との関連付けは行いたくなかったのだけれど,チェックボックスそのものを非表示とする都合上こうしないと上手く行かない.
form要素はCSS実装状況がブラウザ間でえらく異なるのでどうにも思うような機能を作り込むのが難しいのであった.


    <!DOCTYPE html>
    <html>
     <head>
     <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <style type="text/css">
    
    /*チェックされてなかったらリストを非表示とする*/
    #tree_main input[type="checkbox"]:not(:checked)~ul{
     display:none;
    }
    
    /*以下見た目の調整用コード*/
    #tree_main{
     /*基準となる行の高さ.*/
     line-height:1em;
    }
    /*チェックボックスは非表示*/
    #tree_main input[type="checkbox"]{
     display:none;
    }
    /*そのかわりlabelがクリック可能*/
    #tree_main li>label{
     cursor:pointer;
    }
    
    /*ディレクトリアイコンの生成*/
    #tree_main input[type="checkbox"]:not(:checked)+label:before{
     content: url(close.png);
    }
    #tree_main input[type="checkbox"]:checked+label:before{
     content: url(open.png);
    }
    /*NOTE:AとBの大きさを揃える*/
    #tree_main ul{
     list-style-type:none;
     padding:0;
     margin:0;
    }
    #tree_main li{
     overflow:hidden;/*はみ出た罫線を非表示とする*/
     position:relative;/*:after擬似要素の表示位置設定を有効化する*/
     border-left:solid 1px black;/*B*/
     margin-left:0.5em;/*縦罫線のズレ具合*/
    }
    /*幅の調整*/
    #tree_main li>*,#tree_main li:not(.direc):before{
     padding-left:1em;/*A*/
    }
    /*ファイルアイコンの生成*/
    #tree_main li:not(.direc):before{
     content:url(file.png);
    }
    /*罫線の生成に無理やりafter擬似要素を用いる*/
    #tree_main li:after{
     content:" ";
     border-bottom:solid 1px black;
     border-left:solid 1px black;/*B*/
     position:absolute;
     top:-0.5em;
     left:-1px;/*B…親のli要素とborderを重ねている.*/
     width:1em;/*A*/
    }
    /*最下要素の罫線の調整*/
    #tree_main ul>li:last-child{
     border:none;
     padding-left:1px;/*B…上位要素のborderの分だけずらす*/
    }
    #tree_main ul>li:last-child:after{
     left:0;
    }
    </style>
     </head>
     <body>
    <div id="tree_main">
    <input type="checkbox" id="c1"/><label for="c1">title</label>
    <ul>
    <li>node</li>
    <li>node</li>
    <li class="direc"><input type="checkbox" id="c2"/><label for="c2">title</label><ul>
    <li>node</li>
    <li>node</li>
    <li></li>
    …
    </div>
     </body>
    </html>
    
    



    0 件のコメント:

    コメントを投稿