Position element without using absolute positioning

118 views Asked by At

I have the following requirements:

  • a <p> element filled with text
  • a <img> element
  • the coordinates (x/y) where to position the image

Now I want to position the <img> element according to my server side calculated x and y pixel values. I do not want to use position:absolute because I also want the text inside the <p> element to wrap itself around the image.

JsFiddle here.

Css only would be nice, but using javascript is also possible.

3

There are 3 answers

1
Ionic On BEST ANSWER

Probably one solution for your problem could be the usage of shape-outside with a polyfill for older versions of IE/FF/Chrome.

I've added some code to your example: http://jsfiddle.net/dnmbpa7f/4/

img{
    shape-outside: polygon(10px 200px, 10px 500px, 550px 500px, 550px 200px);
    shape-margin: 1em;
    margin:25px;
    float:left;
    margin-top:200px;
}

div#container{
    clear:both;
}
<div id="container">
    
<img src="https://www.estella-kochlust.de/media/image/thumbnail/burger_520x520.png"/>  
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,   consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, <span>popop</span>sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
        
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
    
    </p>
</div>

For further infos about the polyfill see: http://blogs.adobe.com/webplatform/2014/05/12/css-shapes-polyfill/

Best regards, Ionic

1
6502 On

Something that almost works in the toy case is this:

  1. Get the full text of the <p> element
  2. Depending on x form 0 to the length of text split the content in a "before", "after" <span> elements.
  3. Do a dichotomic search to find the x splitting point so that after.offsetTop is the expected value.
  4. Create the final content by adding the span before, the image and the span after.

In code:

function add(img, textdiv, y) {
    var t = textdiv.textContent;
    var a = 0, b = t.length;
    var bef = document.createElement("span");
    var aft = document.createElement("span");
    while (a < b-1) {
        var x = (a + b) >> 1;
        bef.textContent = t.substr(0, x);
        aft.textContent = t.substr(x);
        textdiv.innerHTML = "";
        textdiv.appendChild(bef);
        textdiv.appendChild(aft);
        if (aft.offsetTop > y) {
            b = x;
        } else {
            a = x;
        }
    }
    textdiv.innerHTML = "";
    textdiv.appendChild(bef);
    textdiv.appendChild(img);
    textdiv.appendChild(aft);
}

Something that is missing from this solution but not hard to add is moving the detected split point to next word boundary (currently it could split the text in the middle of a word).

With both google chrome and firefox I don't see any flicker (but I've done this call only once, not under a timer).

In a real case where it's not just text but arbitrary HTML things are much more complex.

0
Florian Gl On

After hours of trying and failing I decided shapes-polyfill doesn't fit my needs. Thats why I build my own solution (inspired by shapes-polyfill) which you can have a look at here.

Cause we are using jQuery I build a solution which uses it, but it can easily be turned into plain javascript (all I use jQuery for is to set some css and append html). Also it is quick and dirty and could be refactored, but atm I am to lazy to do so. ;)