web-dev-qa-db-fra.com

Faire flotter une image en bas à droite avec un texte enveloppant

J'ai un conteneur de texte avec des paragraphes et des titres. Au bas de la page, je veux faire flotter une image à droite de la page, tandis que le texte s'enroule autour de l'image. Le bas de l'image doit être aligné avec le bas du dernier paragraphe.

La largeur de la page est variable (sensible), mais les dimensions de l'image sont fixes. Est-il possible d'accomplir cela en HTML et CSS (CSS3 est très bien)? Sinon, cela peut-il être fait avec une quantité minimale de Javascript?

Voici un exemple schématique de ce que je veux accomplir:

Floating image to the bottom right

Le code HTML ressemble actuellement à ceci, mais il peut être modifié si nécessaire. Peu m'importe où se trouve l'image dans le document. Utiliser des images d'arrière-plan à la place serait bien aussi.

<section>
  <h2>...</h2>
  <p>... ...</p>
  <p>... ...</p>
  ...
  <img src="...">
</section>

Quand je mets float: right sur l'image, il flotte vers la droite mais je n'arrive pas à l'aligner en bas de la page. Suggestions?

Edit: le plus proche que j'ai obtenu est this ...: -)

47
molf

Créez un élément d'espacement avec float: right et height égal à la hauteur du contenu moins la hauteur de l'image. Utilisez ensuite float: right et clear: right sur l'image:

<div class="spacer"></div>
<img class="bottomRight" src="" />
<div class="content"></div>
.spacer {
    height: calc(100% - 200px);
    width: 0px;
    float: right;
}
.bottomRight {
    height: 200px;
    float: right;
    clear: right;
}

http://cssdesk.com/bLNWs

Ma démo utilise des dimensions fixes dans l'élément conteneur. Comme il s'agit rarement d'un cas réaliste, il est probablement plus logique d'utiliser JavaScript pour dimensionner l'espaceur. Appelez cette fonction en passant une référence à l'élément d'espacement lorsque le document est prêt et pendant le window.onresize un événement.

function sizeSpacer(spacer) {
    spacer.style.height = 0;
    var container = spacer.parentNode;
    var img = spacer.nextElementSibling || spacer.nextSibling;
    var lastContentNode = container.children[container.children.length - 1];
    var h = Math.max(0, container.clientHeight - img.clientHeight);
    spacer.style.height = h + "px";
    while (h > 0 && img.getBoundingClientRect().bottom > lastContentNode.getBoundingClientRect().bottom) {
        spacer.style.height = --h + "px";
    }
}

Cette fonction fonctionne ( voir la démo ), et peut être retravaillée pour jQuery ou votre bibliothèque de choix. Il ne s'agit pas d'un code de qualité plug-in, mais sert à illustrer le concept.

jsfiddle.net/n5RPV/9

Edit: J'ai créé une version du plugin jQuery ( github | ( démo jsFiddle ) qui prend en charge flottant en bas à gauche ou en bas à droite. Il prend également en charge la spécification de l'élément avec lequel aligner le bas.

Soit dit en passant, je n'ai pas pris la peine d'essayer de prendre en charge IE7.

55
gilly3

Je pense que la façon future de résoudre ce problème sera avec Exclusions CSS .

Les exclusions CSS étendent la notion d'habillage de contenu auparavant limitée aux flottants. ... Les éléments mettent en page leur contenu en ligne dans leur zone de contenu et encapsulent les zones d'exclusion dans leur contexte d'habillage associé (--extraits de la spécification )

Cette article msdn explique également les exclusions

... les auteurs Web peuvent désormais envelopper le texte afin qu'il entoure complètement les éléments, évitant ainsi les limitations traditionnelles des flottants. Au lieu de limiter les éléments à flotter à gauche ou à droite par rapport à leur position dans le flux de documents, les exclusions CSS peuvent être positionnées à une distance spécifiée du haut, du bas, de la gauche ou de la droite d'un bloc conteneur, tout en restant une partie de le flux de documents.

Ironiquement, à ce jour, cela ne fonctionne que dans IE10 (recherchez wrap-flow: les deux ici )

Découvrez ce violon dans IE10 +

Voici à quoi ressemble le code:

 <div class="container">
    <div class="exclusion">
        Exclusion positioned at bottom right hand side of text.
    </div>
    <div class="dummy_text">
        <p>text here</p>
    </div>
</div> 

CSS

.container {
    font-size: small;
    background: aqua;
    position: relative;
}

.exclusion {

    -ms-wrap-flow: both;
    -ms-wrap-margin: 10px;
    z-index: 1;
    position:absolute;
    right:0;
    bottom:0; /* try fiddling with this. For some reason bottom: -10px (or the like) works better here */
    width: 150px;
    height: 100px;
    background: url(http://placehold.it/150x100) no-repeat;
}

Donc, comme vous pouvez le voir - même si l'exclusion est absolument positionnée - elle agit toujours comme un flottant - dans ce cas: flottant en bas à droite.

Concernant la prise en charge du navigateur:

Découvrez ce site qui montre quelles propriétés sont prises en charge par les navigateurs (à ce jour: seul IE10 + prend en charge wrap-flow:both)

PS: Les dernières mises à jour concernant les exclusions CSS (et d'autres modules similaires comme les régions CSS et les formes CSS) peuvent être trouvées sur Adobe Blog de l'équipe de la plate-forme Web

6
Danield

Je suppose que c'est résolu. Ça marche!

Avec un peu de JavaScript et CSS, je l'ai fait comme ceci:

http://jsfiddle.net/stichoza/aSScx/

Une simple fonction floatify().

  • Sensible.
  • Le redimensionnement de la fenêtre ne le cassera pas.
  • Toute largeur/hauteur d'image.
  • Mettez autant de texte que vous voulez.

Idée inspirée de: http://www.csstextwrap.com/

2
Stichoza

J'ai travaillé sur une solution basée sur jQuery - probablement pas aussi élégante que celle publiée par gilly3;) et elle est également plus lente et un peu gonflée ...

Mon astuce consiste à ajouter deux <div>s à la section, qui est flottante vers la gauche et une largeur cachée d'une largeur de 0. L'un des div, un élément fantôme désigné qui aura la même dimension que l'image, sera positionné en dessous d'un autre div qui est la hauteur désignée entretoise. Le script utilise une boucle while pour déterminer si l'élément fantôme a atteint le bas de l'élément de section parent. Si cela ne s'est pas produit, il augmentera la hauteur de l'entretoise de hauteur de 1, jusqu'à ce que la condition soit satisfaite.

Le balisage que j'ai utilisé est le suivant. J'utilise l'attribut HTML5 data-bottom-image pour identifier les sections dont l'image doit être flottante vers le bas. Bien sûr, il est dispensable, selon la façon dont vous souhaitez sélectionner l'élément de section correct.

<section id="c1" data-bottom-image>
    <h2>...</h2>
    <p>...</p>
    <img src="http://placehold.it/250x100" />
</section>

Et le script jQuery:

$(function () {
    $("section > img:last-child").each(function () {
        // Offset image based on the bottom and right padding of parent
        var $par = $(this).parent();
        $(this).css({
            bottom: $par.css('padding-bottom'),
            right: $par.css('padding-right')
        });
    });

    // Function: adjust height of height-spacer, pixel by pixel
    function adjustHeightSpacer($par, $hs, $is) {
        // Stretch height spacer
        $hs.height(0);
        $hs.css({
            height: $par.find("img").position().top - parseInt($par.css('padding-top'))
        });

        // Adjust height spacer
        while($par.height() - $is.height() > $is.position().top - parseInt($par.css('padding-top'))) {
            $hs.height("+=1");
        }

        while($par.height() - $is.height() < $is.position().top - parseInt($par.css('padding-top'))) {
            $hs.height("-=1");
        }        
    };

    $("section[data-bottom-image]").each(function() {
        // Append two spacers:
        $(this).prepend('<div class="ghost height-spacer" /><div class="ghost image-spacer" />')

        var $hs = $(this).find(".height-spacer"),
            $is = $(this).find(".image-spacer");

        // Adjust image spacer dimension
        $is.css({
            height: $(this).find("img").height(),
            width: $(this).find("img").width()
        });

        // Adjust height spacer
        adjustHeightSpacer($(this), $hs, $is);
    });

    $(window).resize($.debounce(250,function() {
        $("section[data-bottom-image]").each(function() {
            // Adjust height spacer
            adjustHeightSpacer($(this), $(this).find(".height-spacer"), $(this).find(".image-spacer"));
        });
    }));
});

Et voici le violon qui fonctionne: http://jsfiddle.net/teddyrised/xmkAP/5/

2
Terry

Solution CSS possible: ( uniquement testé en chrome)

Il semble que cela puisse fonctionner en utilisant CSS3 propriétés de la boîte flexible et une combinaison de background-image Propriétés. J'ai pu l'obtenir assez près en utilisant uniquement CSS. ( Cela fonctionne mais a besoin d'un petit ajustement) De plus, ce n'est peut-être pas idéal car j'ai dû changer un peu le balisage pour que cela fonctionne. Mais cela vaut probablement le coup si vous recherchez une solution CSS pure.

Voici une démo -> http://jsfiddle.net/ADSH2/

Nouveau balisage: ( pas trop différent)

<section >
  <h2>Some Heading:</h2>
  <p>...</p>
  <p class="last">
     <span class="image"></span>
  </p>
</section>

CSS:

.last {
    display:inline-flex;
    flex-direction:row;
}
.image {
    padding:5px 0 0 5px;
    width:100%;
    background-image:url("http://dribbble.s3.amazonaws.com/users/200359/screenshots/758731/stackoverflow_logo.png");
    background-size:100%;
    background-repeat:no-repeat;
    background-position:bottom right;
}

Ressources:

  1. http://css-tricks.com/snippets/css/a-guide-to-flexbox/
  2. http://dev.w3.org/csswg/css-flexbox-1/
2
Kris Hollenbeck

Solution CSS uniquement.

À l'aide de requêtes multimédias, on peut accomplir cette disposition.

HTML

<section>
  <h2>...</h2>
  <p>... ...</p>
  <p>... ...</p>
  <img src="..." class="show-medium">
  ...
  <img src="..." class="show-small">
</section>

CSS

html, body {
  height: 100%;
  width: 100%;
}

img {
  display: none;
  float: right;
  clear: right;
}

@media (max-width: Xpx), (max-height: Xpx) {
  /* show img for small screens */
  .show-small { display:block; }
}
@media (min-width: Xpx) and (max-width: Xpx) and (min-height:Xpx) and (max-height: Xpx) { 
 /* show img for medium screens */
 .show-medium { display:block; }
}

@media (min-width: Xpx) and (min-height: Xpx) {
  /* show img as body background for large screens */
  body {
    background: url("http://placehold.it/200x300") no-repeat fixed right bottom transparent;
  }
}

Il fonctionne bien à différentes résolutions d'écran. Voir démo .

Il faut jouer/ajuster les requêtes média CSS ainsi que la position des images dans le balisage afin de le faire fonctionner.

Les requêtes multimédia CSS sont prises en charge dans Firefox 3.5+, Opera 7+, Safari 3+, Chrome et IE9 +. Pour les anciennes versions IE, on peut utiliser ce correctif: http://code.google.com/p/css3-mediaqueries-js/

1
Oriol

Voici une solution légère avec un peu de jQuery:

http://jsfiddle.net/isherwood/6BvC2/

<section class="flagpole">
    <div class="pole"></div>
    <img class="flag" src="..." />
    <p>Paragraphs...</p>
</section>

.pole, .flag {
    float: right;
    clear: right;
}
.pole {
    width: 0.1px
}


function setFlag() {
    $('section.flagpole').each(function () {
        var poleHeight = $(this).height() - $(this).find('.flag').height();
        $(this).find('.pole').height(poleHeight);
    });
}

setFlag();

$(window).on('resize', function () {
    setFlag();
});

Pour dissiper toute inquiétude concernant le plagiat, cette solution est basée sur ne autre réponse similaire J'ai fourni il y a quelque temps.

0
isherwood

utilisez ceci :

<section class="post">
  <h2>...</h2>
  <p>... ...</p>
  <p>... ...</p>
  ...
  <img src="...">
</section>

<style>
.post img {float:right;margin-top:80%}

</style>

change 80% pour obtenir le meilleur résultat.

Bonne chance.

0
hesam jaferi