absoluteで重なるとき右に避けて表示したい

このQ&Aのポイント
  • float: leftなどでは横に並ぶ要素のwidthが親を超えると下段にずれる問題があります。
  • position: absoluteを使って要素を重ならせる場合に、要素が重なった際に右にずれて表示したい課題があります。
  • 配列を用いた方法では最大で要素のサイズ分だけ検索する必要があり、効率的ではありません。より賢い解決策を模索しています。
回答を見る
  • ベストアンサー

absoluteで重なるとき右に避けて表示したい

より賢い解決策を探しています。 "float: left"などでは、横に並ぶ要素のwidthが親を超えると下段にずれると思います。例えば下記のように。 <div style="width:100px">   <div style="width:40px;float:left">test</div>   <div style="width:40px;float:left">test</div>   <div style="width:40px;float:left">test</div>   <div style="clear:both"><!--とりあえず--></div> </div> これは横並びですが、訳あって"position:absolute"を使って表示し、要素が重なる場合は、右に避けて表示をしたいのです。(もちろん各要素のtopとleftを指定します) これを行うために、JavaScriptで配置状態を管理する配列を用意しました。下記のようなテーブルです。 [   [0,0,0,0,0,0,0,0,0],   [0,0,0,1,1,0,0,0,0],   [0,0,0,1,1,1,1,0,0],   [0,0,0,0,0,1,1,0,0],   [0,0,0,0,0,1,1,0,0] ] "bottom - top"または"right - left"のいずれかの位置に"1"があるとき、"0"の場所まで右にずれる、というものです。 このうち"1"と"0"を for で探しているのですが、最大で要素のサイズ分だけ調べる回数がある、ただの力技です。 for(var i=y, j; i<y1; i++){   for(j=x; j<x1; j++){    if(table[i][j]){      // どうのこうの    }   } } もしかすると賢い解決策があるんじゃないかということで、質問させていただきました。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

<!DOCTYPE html> <meta charset="UTF-8"> <title></title> <style> ul {  list-style: none;  position:relative; } li {  position: absolute;  margin : 0;  padding: 0;  border: 1px red solid;  text-align :center;  font-size: 10px;  color: red;  width : 60px;  height: 80px; } </style> <body> <h1>Position Test</h1> <ul>  <li style="width: 50px; height:130px;">ABC  <li style="width: 40px; height:80px;">DEF  <li style="width: 100px; height:140px;">GHI  <li style="width: 60px; height:70px;">JKL  <li style="width: 150px; height:50px;">MNO  <li style="width: 70px; height:30px;">PQR </ul> <script> (function () {  // 四角形のオブジェクト  function Square (element, top, left, right, bottom) {   this.type  = 'square';   this.element = element.tagName ? element: null;   this.top   = top;   this.left  = left;   this.right  = right;   this.bottom = bottom; }    // 引数(point) が四角形の内側にあるか?  function isOverlap (point) {   var x = point.x;   var y = point.y;   if (this.top <= y)    if (y <= this.bottom)     if (this.left <= x)      if (x <= this.right)       return true;   return false;  }    // 位置を指定する  function setPosition (position) {   var d;   if ((d = position.x)) {    this.right = d + (this.right - this.left);    this.left = d;   }   if ((d = position.y)) {    this.bottom = d + (this.bottom - this.top);    this.top = d;   }  }  // 四角形のオブジェクトの生成  Square_create = function (e, x, y) {   if (1 > arguments.length)    throw new Error;   x = x || 0, y = y || 0;   return new Square (e, y, x, x + e.offsetWidth, y + e.offsetHeight);  };  //______  Square.prototype.isOverlap = isOverlap;  Square.prototype.setPosition = setPosition;  Square.create = Square_create;  this.Square = Square;   //______   // エリアにすでに領域があるかを調べるモノ。  function AreaChecker () {   this.stock = [];  }  // エリアに領域を加える  function AreaChecker_add (area) {   var e, s;   if (! area)    throw new Error ();   if ((e = area.element)) {    s = e.style;    s.top = area.top + 'px';    s.left = area.left + 'px';   }   this.stock.push (area); //配列に足すだけ  };    // 点(this)が、与えられたエリアに含まれているのか?  function overlap (area) {   return this.some (area.isOverlap, area)  }  // 引数の領域が、エリアの領域とカブっているか?  function getOverlap (area) {   var points = [ ]; //検査する点   var result;   if (! area)    throw new Error ();      switch (area.type) {      case 'square' :   default :    var st = 6;    var sx = (area.right - area.left) / st;    var sy = (area.bottom - area.top) / st;    var x, y;    var i, j;           points = [     {x: area.left, y: area.top},     {x: area.right, y: area.top},     {x: area.right, y: area.bottom},     {x: area.left, y: area.bottom},     {x: (area.left + area.right)/ 2, y:(area.top + area.bottom)/ 2} //重心もチェックでごまかす     ];    for (i = 1; i < st; i++)     for (j = 1; j < st; j++)      points.push ({x: area.left + sx * i, y: area.top + sy * j});    break;   }   result = (this.stock.length)   ? this.stock.filter (overlap, points) // 重なっているものを配列で返す   : [];   return result.length ? result: null;  }     //__________________    function AreaChecker_create () {   return new AreaChecker;  }    AreaChecker.prototype.add = AreaChecker_add;  AreaChecker.prototype.getOverlap = getOverlap;    AreaChecker.create = AreaChecker_create;    this.AreaChecker = AreaChecker; }) (); // つづく

masatook
質問者

お礼

興味深い解決方法でした。ありがとうございます! つまり、既存の要素にサンプルをぶちまけて引っ掛かる場合は移動する、という手段でチェック回数を間引きした訳ですね。 納得しました。ここから考えを自分のものにしてみたいと思います。

その他の回答 (4)

回答No.5

またも、 y: top + round (sy * j); を y: top + round (sy * j) に。

回答No.4

#1~3です。ちょっとていせい。 わかっているとおもいますが、st のあたいをふやすと、けっきょくちからわざ。 四角形だけでなく丸もできそうですが、する~。  function getOverlap (area) {   var points = [ ]; //検査する点   var result;   var round = Math.round;   if (! area)    throw new Error ();      if (! this.stock.length)    return null;      switch (area.type) {      case 'square' :   default :    var st = 6;    var sx = (area.right - area.left) / st;    var sy = (area.bottom - area.top) / st;    var left = area.left;    var top = area.top;    var i, j, t;           for (i = 0; i <= st; i++) {     t = round (sx * i);     for (j = 0; j <= st; j++) {      points.push ({       x: left + t,       y: top + round (sy * j);      });     }    }    break;   }   result = this.stock.filter (overlap, points); // 重なっているものを配列で返す   return result.length ? result: null;  }

回答No.3

//------------ var randomInt = function (n) { return Math.random () * n |0; }; var A = AreaChecker.create (); var li = document.querySelectorAll ('li'); // 面積順にする li = Array.prototype.slice.call (li, 0); function area (x, y) { return x * y }; // 面積をもとめる function comp (a, b) {  var areaA = area(a.offsetWidth, a.offsetHeight);  var areaB = area(b.offsetWidth, b.offsetHeight);  return areaA == areaB ? 0: areaB - areaA; } li.sort (comp); (function () {  var maxX = 240;  var maxY = 120;  var i = 0, j = 0;  var e;  var sq;  var db;  while (e = li[i++]) {   sq = Square.create (e);   do {    sq.setPosition ({x:randomInt (maxX), y:randomInt (maxY)});    db = A.getOverlap (sq);    if (db) {     sq.setPosition ({x: db[0].right + 1});     db = A.getOverlap (sq);    }   } while (db);   A.add (sq);  } }) (); </script> ーー びみょうにかさなる! だめだこりゃ~! べつものを、しあんちゅう。

回答No.1

おはようございます。 その位置に要素があるのか?を知るすべは var element = document.elementFromPoint (x, y); element があれば、この要素の座標を調べます。 親をたどりながら、親要素の offsetTop or offsetLeft の値を加算していくか、 var point = element.getBoundingClientRect (); var x = point.left; var y = point.top; で、座標を得る(?)。 element の座標に、その element.offsetWidth と1を足すと、右隣の座標を得られる、と思う。 しかし、その座標に要素を配置しようとしたときに、その要素の幅以内に、すでに他の要素があった場合どうする?

masatook
質問者

補足

ご回答ありがとうございます。 >[...]この要素の座標を調べます。 今回は要素の配置に"position:absolute"を使う訳ですが、 そのときのtopとleftの指定はすでに別の処理で得られた 定数を使います。(JSONを取ってきて行うので) 要素幅も処理側で指定するので、基本的には情報は 揃っている状態です。(width, height, top, left) >[...]すでに他の要素があった場合どうする? そう、そこです。 例えば上記0-1テーブルの各行と列番号の積集合で 0がwidth-height以上に残っている領域を見つけ出す― とかそういうトリックが思いつかなくて 今回の質問にいたりました。

関連するQ&A

  • ブログを3カラム右右から左右両サイドにしたい。

    現在CSSは下記のようになっています。 どこをいじれば右右から左右両サイドにできるのか教えていただけたら嬉しいです。 宜しくお願い致します。 /** 03. Layout - レイアウトの設定 */ /* ----------------------------------------------- */ body { margin: 0; padding: 0; min-width: 960px; text-align: center; background-image: none; background-repeat: repeat; background-position: 50% top; } div#containerWrap { width: 960px; margin: 0 auto 5px; } div#container {} div#content { padding: 10px 0; border-width: 1px; border-style: solid; } div#main , div#sub , div#extra { overflow: hidden; } div#main { float: left; display: inline; width: 538px; } div#main div.column-inner { padding: 0 10px 10px; } div#sub { float: left; display: inline; width: 210px; } div#sub div.column-inner { padding: 5px 10px 0; overflow: hidden; border-width: 1px; border-style: none none none solid; } div#extra { float: left; display: inline; width: 210px; } div#extra div.column-inner { padding: 5px 10px 20px; overflow: hidden; border-width: 1px; border-style: none none none solid; }

    • ベストアンサー
    • HTML
  • IE6だと表示がおかしく表示される。

    添付写真の上がIE9での表示で、下はIE6(IETesterで表示)ですが。 殆んど同じ記述で「写真」の無いページは、正しく表示しています。 必要と思われるタグは、下記の内容です。なお親ホントは100%です。 <div style="width:32%;float:left;"><img src="省略></a></div> <div style="width:59%;float:left;"><img src="省略"></a></div> <div style="font:1em/2.8em 'MS 明朝',serif;width:27.9em;float:clear:both;"> <div style="margin-left:9.52em;font-weight:bold;clear:both;">九月十八日</div> <div style="clear:both;width:27.9em;"> <div style="width:11.63em;font:1em/2.8em 'MS 明朝',serif;float:left;">省略</div> <div style="width:5.81em;font:1em/1.4em 'MS 明朝',serif;float:left;">省略</div> <div style="width:10.34em;font:1em/2.8em 'MS 明朝',serif;float:left;">省略</div> 省略 </div> <div style="font:1em/2.8em 'MS 明朝',serif;width:27.9em;float:"> <div style="clear:both;width:27.9em;"> <div style="width:11.63em;font:1em/2.8em 'MS 明朝',serif;float:left;margin-top:1.5em;">省略</div> <div style="width:5.81em;font:1em/1.4em 'MS 明朝',serif;float:left;margin-top:1.5em;">省略</div> <div style="width:10.34em;font:1em/2.8em 'MS 明朝',serif;float:left;margin-top:1.5em;">省略</div> 省略 </div> 誤り内容を教えて下さい。 http://ryuso.info/test/ryu180_250.htm

    • ベストアンサー
    • CSS
  • firefoxでdivタグの体裁崩れ

    お世話になります。 以下のソースを IEで見るとリスト1、リスト2は同じ内容が表示されます FireFoxで見るとリスト2のlist3が左側につめられて表示されます。 ・これはIE or FireFoxのバグになるのでしょうか? ・IEと同じようにFireFoxで表示したいのですが出来ますでしょうか? 申し訳ありませんがご教授よろしくお願いいたします。 <html> <title>DIVタグテスト</title> <body> DIVタグテスト<br> <br> リスト1 <div style="width:300px;"> <div style="float:left;width:100px;"> <div style="width:100px;"> <div>list1</div> </div> </div> <div style="float:left;width:100px;"> <div style="width:100px;"> <div>list2</div> </div> </div> <div style="float:left;width:100px;"> <div style="width:100px;"> <div>list3</div> </div> </div> </div> <br> <br> リスト2 <div style="width:300px;"> <div style="float:left;width:100px;"> <div style="width:100px;"> <div>list1</div> </div> </div> <div style="float:left;width:100px;"> <div style="width:100px;"> <div></div> </div> </div> <div style="float:left;width:100px;"> <div style="width:100px;"> <div>list3</div> </div> </div> </div> </body> </html>

    • ベストアンサー
    • HTML
  • float: leftで横に並べたら、サファリだけ

    float: leftで横に並べたら、サファリだけ隙間が空いてしまいます。 IEやファイヤーフォックスではピッタリ表示できています。 問題の箇所は以下です。 <div style="float: left;"> <p style="position: relative;"> <img src="./img/img-001.png" width="240" height="150" /> <br /> <span style="font-size: 12px; padding: 2px 5px 2px 5px; position: absolute; top: 130px; left: 0px; width: 230px; height: 16px; color: white ; background-color: black; opacity: 0.6;">テストテスト1</span> </p> </div> <div style="float: left;"> <p style="position: relative;"> <img src="./img/img-002.png" width="240" height="150" /> <br /> <span style="font-size: 12px; padding: 2px 5px 2px 5px; position: absolute; top: 130px; left: 0px; width: 230px; height: 16px; color: white ; background-color: black; opacity: 0.6;">テストテスト2</span> </p> </div> <div style="float: left;"> <p style="position: relative;"> <img src="./img/img-003.png" width="240" height="150" /> <br /> <span style="font-size: 12px; padding: 2px 5px 2px 5px; position: absolute; top: 130px; left: 0px; width: 230px; height: 16px; color: white ; background-color: black; opacity: 0.6;">テストテスト3</span> </p> </div> どうすればサファリの隙間を消せるでしょうか?

    • ベストアンサー
    • HTML
  • DIVで表示が崩れる。

    こんにちわ。 お願いします。 TABLEから脱出してDIVで整理整頓しようとおもっているのですが なかなかうまくいきません。 ソースはっちゃいますね <DIV style="width : 780px;height : 100%;z-index : 0;"> <DIV style="width : 780px;clear : both;z-index : 1;"></DIV>(2) <DIV style="width : 200px;float : left;z-index : 2;"></DIV> <DIV style="width : 380px;float : left;z-index : 2;"></DIV> <DIV style="width : 200px;float : right;z-index : 2;"></DIV>(1) </DIV> といった感じでベースになっているDIVがデカデカとあり その中に一段目のDIV(回り込み解除/ヘッダー的役割です)があってその下にDIVが3つ回りこみで並んでる。 という。 で、問題が、HBビルダーで作っているのですが、 3つならんでるDIV、 一番左は「左に廻り込み」 真ん中は「左に廻り込み」 で、問題は一番右です。 ここを「右に廻り込み」にしなきゃ3つ並ばないのですが、(廻り込み設定しない場合一段下がってしまいます)このままだと、(1)の部分に文章やらTABLEやら画像やらいれると(2)の位置へ表示されてしまいます。(ソースは変わらないのですが)。 ならばとおもってDIVを入れると、右のDIVの下に来てしまいます。 ならばとおもい3つのDIVをDIVで囲み、その外に書いても右のDIVの下へ… 俺がしたいのは、 とにかく一段下げたいのです。TABLEでいえばTRを作りたい。 わかりますでしょうか?

    • ベストアンサー
    • HTML
  • position:absoluteが表示されない

    分からない部分が出た際にいつもお世話になっております。 今回もどなたかご回答頂けますと幸いです。 position:absoluteを指定した要素(#search_box)が、IE6でのみ表示されず困っています。 他ブラウザで見ると問題無く表示されているのですが、どこに問題があるのでしょうか。 【html】 <div id="contents_wrap" class="clearfix"> <ul id="pankuzu"> <li>テスト</li> <li>テスト</li> </ul> <div id="search_box"> <form method="get" action="./search.cgi"> <input name="query" style="width:300px;" value="テスト" /> <input type="submit" value="検索" class="button" /> </form> <!-- /search_box --> 【css】 #contents_wrap { clear: both; margin: 0 auto; width: 960px; padding-top: 10px; padding-bottom: 100px; } #pankuzu { padding-bottom: 70px; font-size: 12px; } #pankuzu li { display:inline; line-height:110%; list-style-type:none; } #search_box { position:absolute; top:200px; left:320px; } ※実物は長いのでhtmlは必要と思われる箇所だけ抜き出しています。 どうぞ宜しくお願いします。

    • ベストアンサー
    • HTML
  • リキッドレイアウトについて

    リキッドレイアウトについて、メイン部分だけ可変するようにして、サイド部分は固定することは可能でしょうか? <div style="float:left;width:?%;"></div><!--main--> <div style="float:left;width:200px;"></div><!--side1--> <div style="float:left;width:200px;"></div><!--side2-->

  • position:relativeについて教えてください

    初めて質問します。 2つの横にならんだセルをDIVによって表示しようと思い <DIV style="width:112px;height:20px;background-color:red; position:relative;left:0px;top:0px;">テスト1</DIV> <DIV style="width:112px;height:20px;background-color:yellow; position:relative;left:112px;top:-20px;">テスト2</DIV> というスタイルシートを作成しようとしたのですが、実際にはテスト10まであり、一行がいかんせん長いので次のようにしてみました。 <DIV style="width:112px;height:20px;"> <DIV style="background-color:red; position:relative;left:0px;top:0px;">テスト1</DIV> <DIV style="background-color:yellow; position:relative;left:112px;top:-20px;">テスト2</DIV> 同じように使われている記述でまとめることができるんだ、と思い、ポジションの記述もまとめてみたのですが、 <DIV style="width:112px;height:20px;position:relative;"> <DIV style="background-color:red;left:0px;top:0px;">テスト1</DIV> <DIV style="background-color:yellow;left:112px;top:-20px;">テスト2</DIV> この記述だと、セルが下にくっついてしまい、うまく表示できません。 positionは必ず記述しないといけないのでしょうか。できたらもっと1行を短くしたいのですが… 解決方法がわかる方いらっしゃいましたら、宜しくお願いします。

    • ベストアンサー
    • HTML
  • cssのfloatについて質問があります。

    cssのfloatについて質問があります。 floatがなかなか理解できずに悩んでおります。 下記のようなcssがあり、同じブロック要素でも table,pなどは右に回りこみ、divボックスはfloatを指定しないと floatボックスの下に入ってしまうのをなんか理解できません。 初歩的なことかもしれませんが、 どなたかアドバイスいただけると助かります。 宜しく尾根会い致します。 <html lang="ja"> <head> <title></title> <style type="text/css"> #con { width: 800px; border: solid 1px black; } .left { width: 300px; height: 300px; float: left; border: solid 1px blue; } .right { width: 200px; height: 200px; border: solid 1px red; } table { width: 100px; height: 100px; border: solid 1px green; } p { border: solid 1px yellow; } </style> </head> <body> <div id="con"> <div class="left"> </div> <table> <tr><td>TABLE</td></tr> </table> <p>ppppp</p> <div class="right"> </div> </div> </body> </html>

    • ベストアンサー
    • HTML
  • テキストを画像の右にしたいのですが・・

    ブログパーツで下記のものを使用しています。 <div style="text-align:left;padding-top:10px; padding-bottom:5px"> <iframe src="http://chiccuri.sakura.ne.jp/blog_parts/kisotaisya.html" width="168" height="250" frameborder="0" scrolling="no" marginwidth="0" marginheight="0" hspace="0" vspace="0"></iframe><p style="font-size:13px; margin-top:2px;"></p></div> このパーツの右に文章を回りこみさせたいのですが、どこにどのようなタグを挿入すればいいのでしょうか? <div style="text-align:left;float:left;padding-top:10px; padding-bottom:5px"> ではうまくいきませんでした。 初心者ですが、よろしくお願いいたします。

    • ベストアンサー
    • HTML