web-dev-qa-db-fra.com

Faire en sorte que Iframe s'adapte à 100% de la hauteur restante du conteneur

Je souhaite concevoir une page Web avec une bannière et un iframe. J'espère que l'iframe pourra remplir toute la hauteur de page restante et être redimensionné automatiquement lorsque le navigateur redimensionne. Est-il possible de le faire sans écrire de code Javascript, uniquement avec CSS?

J'ai essayé de définir height:100% sur iframe, le résultat est assez proche, mais l'iframe a essayé de remplir toute la hauteur de la page, y compris la hauteur 30px de l'élément div bannière, de sorte que j'ai obtenu un scrollbar vertical inutile. Ce n'est pas parfait 

Notes de mise à jour : Excusez-moi de ne pas avoir bien décrit la question. J'ai essayé la marge CSS, l'attribut de remplissage sur DIV pour occuper toute la hauteur restante d'une page Web, mais l'astuce ne fonctionnait pas sur iframe.

 <body>
    <div style="width:100%; height:30px; background-color:#cccccc;">Banner</div>
    <iframe src="http: //www.google.com.tw" style="width:100%; height:100%;"></iframe>
</body>

Toute idée est appréciée.

213
Darkthread

L'astuce consiste à comprendre de quoi est fait le 100%. La lecture des spécifications CSS peut vous aider.

Pour faire une histoire courte - il existe une chose telle que "bloc contenant" - qui n'est pas nécessairement l'élément parent. En termes simples, c’est le premier élément de la hiérarchie qui a la position: relative ou position: absolue. Ou l'élément body lui-même s'il n'y a rien d'autre. Ainsi, lorsque vous dites "width: 100%", il vérifie la largeur du "bloc conteneur" et définit la largeur de votre élément sur la même taille. S'il y avait quelque chose d'autre, alors vous pourriez obtenir le contenu d'un "bloc conteneur" plus grand que lui-même (donc "débordant").

La hauteur fonctionne de la même manière. À une exception près. Vous ne pouvez pas obtenir la hauteur à 100% de la fenêtre du navigateur. L'élément de très haut niveau, contre lequel 100% peut être calculé, est l'élément body (ou html? Non sûr) et qui s'étire juste assez pour contenir son contenu. Spécifier hauteur: 100% n'aura aucun effet, car il n'y a pas d '"élément parent" avec lequel mesurer 100%. La fenêtre elle-même ne compte pas. ;)

Pour que quelque chose s'étire exactement à 100% de la fenêtre, vous avez deux choix:

  1. Utiliser JavaScript
  2. N'utilisez pas DOCTYPE. Ce n'est pas une bonne pratique, mais cela place les navigateurs en mode "quirks", dans lequel vous pouvez faire height = "100%" sur les éléments et les étendre à la taille de la fenêtre. Notez que le reste de votre page devra probablement également être modifié pour tenir compte des modifications de DOCTYPE.
</ s>

Mise à jour: Je ne suis pas sûr de ne pas m'être trompé quand j'ai posté ceci, mais c'est certainement obsolète maintenant. Aujourd'hui, vous pouvez le faire dans votre feuille de style: html, body { height: 100% } et cela s'étendra à l'ensemble de votre fenêtre d'affichage. Même avec un DOCTYPE. min-height: 100% pourrait également être utile, selon votre situation.

Et je ne conseillerais à personne de créer un document en mode quirks plus non plus, car il provoque beaucoup plus de maux de tête que de solutions. Chaque navigateur ayant un mode quirks différent, il est donc plus difficile de faire en sorte que votre page ait une apparence uniforme sur tous les navigateurs. Utilisez un DOCTYPE. Toujours. De préférence le HTML5 - <!DOCTYPE html>. Il est facile à retenir et fonctionne comme un charme dans tous les navigateurs, même ceux âgés de 10 ans.

La seule exception est quand vous devez supporter quelque chose comme IE5 ou quelque chose. Si vous y êtes, alors vous êtes seul. Ces anciens navigateurs ne ressemblent en rien aux navigateurs d’aujourd’hui, et les quelques conseils donnés ici vous aideront à les utiliser. Le bon côté des choses, si vous y êtes, vous devrez probablement juste supporter UN type de navigateur, qui élimine les problèmes de compatibilité.

Bonne chance!

Mise à jour 2: Hé, ça fait longtemps! 6 ans plus tard, de nouvelles options s'offrent à vous. Je viens d'avoir une discussion dans les commentaires ci-dessous, voici d'autres astuces pour vous qui fonctionnent dans les navigateurs d'aujourd'hui.

Option 1 - positionnement absolu. Nice et propre pour quand vous connaissez la hauteur précise de la première partie.

body, html {width: 100%; height: 100%; margin: 0; padding: 0}
.first-row {position: absolute;top: 0; left: 0; right: 0; height: 100px; background-color: Lime;}
.second-row {position: absolute; top: 100px; left: 0; right: 0; bottom: 0; background-color: red }
.second-row iframe {display: block; width: 100%; height: 100%; border: none;}
<div class="first-row">
  <p>Some text</p>
  <p>And some more text</p>
</div>
<div class="second-row">
  <iframe src="https://jsfiddle.net/about"></iframe>
</div>

Quelques notes - le conteneur second-row est nécessaire car bottom: 0 et right: 0 ne fonctionnent pas sur les iframes pour une raison quelconque. Quelque chose à voir avec le fait d'être un élément "remplacé". Mais width: 100% et height: 100% fonctionnent parfaitement. display: block est nécessaire car il s'agit par défaut d'un élément inline et, sinon, les espaces blancs créent des débordements étranges.

Option 2 - tables. Fonctionne lorsque vous ne connaissez pas la hauteur de la première partie. Vous pouvez utiliser les balises <table> réelles ou à la manière élégante avec display: table. Je vais aller pour le dernier, car il semble être à la mode ces jours-ci.

body, html {width: 100%; height: 100%; margin: 0; padding: 0}
.row-container {display: table; empty-cells: show; border-collapse: collapse; width: 100%; height: 100%;}
.first-row {display: table-row; overflow: auto; background-color: Lime;}
.second-row {display: table-row; height: 100%; background-color: red; overflow: hidden }
.second-row iframe {width: 100%; height: 100%; border: none; margin: 0; padding: 0; display: block;}
<div class="row-container">
  <div class="first-row">
    <p>Some text</p>
    <p>And some more text</p>
  </div>
  <div class="second-row">
    <iframe src="https://jsfiddle.net/about"></iframe>
  </div>
</div>

Quelques notes - le overflow: auto s'assure que la ligne inclut toujours tout son contenu. Sinon, des éléments flottants peuvent parfois déborder. Le height: 100% sur la deuxième ligne permet de s’étendre autant que possible, car il est possible de compresser la première ligne aussi petite que possible.

Option 3 - flexbox. Le plus propre de tous, mais avec un support de navigateur moins que stellaire. IE10 aura besoin des préfixes -ms- pour les propriétés de flexbox, et rien de moins ne le supportera pas du tout.

body, html {width: 100%; height: 100%; margin: 0; padding: 0}
.row-container {display: flex; width: 100%; height: 100%; flex-direction: column; background-color: blue; overflow: hidden;}
.first-row {background-color: Lime; }
.second-row { flex-grow: 1; border: none; margin: 0; padding: 0; }
<div class="row-container">
  <div class="first-row">
    <p>Some text</p>
    <p>And some more text</p>
  </div>
  <iframe src="https://jsfiddle.net/about" class="second-row"></iframe>
</div>

Quelques notes - le overflow: hidden est dû au fait que l’iframe génère toujours une sorte de débordement même avec display: block dans ce cas. Il n'est pas visible dans la vue plein écran ou dans l'éditeur d'extraits, mais la petite fenêtre d'aperçu reçoit une barre de défilement supplémentaire. Aucune idée de ce que c'est, les iframes sont bizarres.

183
Vilx-

Nous utilisons un JavaScript pour résoudre ce problème; voici la source.


var buffer = 20; //scroll bar buffer
var iframe = document.getElementById('ifm');

function pageY(elem) {
    return elem.offsetParent ? (elem.offsetTop + pageY(elem.offsetParent)) : elem.offsetTop;
}

function resizeIframe() {
    var height = document.documentElement.clientHeight;
    height -= pageY(document.getElementById('ifm'))+ buffer ;
    height = (height < 0) ? 0 : height;
    document.getElementById('ifm').style.height = height + 'px';
}

// .onload doesn't work with IE8 and older.
if (iframe.attachEvent) {
    iframe.attachEvent("onload", resizeIframe);
} else {
    iframe.onload=resizeIframe;
}

window.onresize = resizeIframe;

Remarque: ifm est l'ID iframe.

pageY() a été créé par John Resig (l'auteur de jQuery)

65
MichAdel

Une autre façon de faire consiste à utiliser le position: fixed; sur le nœud parent.
Si je ne me trompe pas, position: fixed; lie l'élément à la fenêtre d'affichage. Ainsi, une fois que vous aurez attribué à ce nœud les propriétés width: 100%; et height: 100%;, il s'étendra sur tout l'écran. À partir de là, vous pouvez insérer la balise <iframe> dans la balise et l'étendre sur l'espace restant (en largeur et en hauteur) à l'aide de la simple instruction width: 100%; height: 100%; CSS.

Exemple de code


    body {
        margin: 0px;
        padding: 0px;
    }

    /* iframe's parent node */
    div#root {
        position: fixed;
        width: 100%;
        height: 100%;
    }

    /* iframe itself */
    div#root > iframe {
        display: block;
        width: 100%;
        height: 100%;
        border: none;
    }
   <html>
        <head>
            <title>iframe Test</title>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        </head>
        <body>
            <div id="root">
                <iframe src="http://stackoverflow.com/">
                    Your browser does not support inline frames.
                </iframe>
            </div>
        </body>
    </html>

45
D1SoveR

Vous pouvez le faire avec DOCTYPE, mais vous devez utiliser table. Regarde ça:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<style>
*{margin:0;padding:0}
html, body {height:100%;width:100%;overflow:hidden}
table {height:100%;width:100%;table-layout:static;border-collapse:collapse}
iframe {height:100%;width:100%}

.header {border-bottom:1px solid #000}
.content {height:100%}
</style>
</head>
<body>
<table>
    <tr><td class="header"><div><h1>Header</h1></div></td></tr>
    <tr><td class="content">
        <iframe src="http://google.com/" frameborder="0"></iframe></td></tr>
</table>
</body>
</html>
37
ducu

Voici quelques approches modernes:


  • Approche 1 - Combinaison des unités relatives de la fenêtre / calc() .

    L'expression calc(100vh - 30px) représente la hauteur restante. Où 100vh est la hauteur du navigateur et l'utilisation de calc() déplace effectivement la hauteur de l'autre élément.

    Exemple ici

    body {
        margin: 0;
    }
    .banner {
        background: #f00;
        height: 30px;
    }
    iframe {
        display: block;
        background: #000;
        border: none;
        height: calc(100vh - 30px);
        width: 100%;
    }
    <div class="banner"></div>
    <iframe></iframe>

    Prise en charge de calc() here ; soutien pour viewport unités relatives ici .


  • Approche 2 - approche Flexbox

    Exemple ici

    Définissez la display de l'élément parent commun sur flex, ainsi que flex-direction: column (en supposant que vous souhaitiez que les éléments s'empilent les uns sur les autres). Puis définissez flex-grow: 1 sur l'élément enfant iframe afin qu'il remplisse l'espace restant.

    body {
        margin: 0;
    }
    .parent {
        display: flex;
        flex-direction: column;
        min-height: 100vh;
    }
    .parent .banner {
        background: #f00;
        width: 100%;
        height: 30px;
    }
    .parent iframe {
        background: #000;
        border: none;
        flex-grow: 1;
    }
    <div class="parent">
        <div class="banner"></div>
        <iframe></iframe>
    </div>

    Puisque cette approche a moins de soutien1, Je suggérerais d’adopter l’approche susmentionnée. 

1Bien que cela semble fonctionner dans Chrome/FF, cela ne fonctionne pas dans IE (la première méthode fonctionne dans tous les navigateurs actuels).

31
Josh Crozier

Peut-être a-t-on déjà répondu à cette question (quelques réponses ci-dessus sont des façons "correctes" de le faire), mais je pensais que j'ajouterais simplement ma solution.

Notre iFrame est chargé dans une div, il me fallait donc autre chose que window.height. Et comme notre projet repose déjà beaucoup sur jQuery, je trouve que c'est la solution la plus élégante:

$("iframe").height($("#middle").height());

Où bien sûr "#middle" est l'identifiant de la div. La seule chose supplémentaire à faire est de rappeler ce changement de taille lorsque l'utilisateur redimensionne la fenêtre.

$(window).resize(function() {
    $("iframe").height($("#middle").height());
});
17
Tim Geerts

Le code MichAdel fonctionne pour moi, mais j'ai apporté quelques modifications mineures pour le faire fonctionner correctement.

function pageY(elem) {
    return elem.offsetParent ? (elem.offsetTop + pageY(elem.offsetParent)) : elem.offsetTop;
}
var buffer = 10; //scroll bar buffer
function resizeIframe() {
    var height = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight;
    height -= pageY(document.getElementById('ifm'))+ buffer ;
    height = (height < 0) ? 0 : height;
    document.getElementById('ifm').style.height = height + 'px';
}
window.onresize = resizeIframe;
window.onload = resizeIframe;
6
asimrafi

Voici ce que j'ai fait. J'ai eu le même problème et j'ai fini par chercher des ressources sur le Web pendant des heures.

<style type="text/css">
   html, body, div, iframe { margin:0; padding:0; height:100%; }
   iframe { position:fixed; display:block; width:100%; border:none; }
</style>

J'ai ajouté ceci à la section head.

Veuillez noter que mon iframe est situé à l'intérieur de la cellule du milieu d'une table comportant 3 lignes et 1 colonne.

6
Danut Milea

essayez ce qui suit:

<iframe name="" src="" width="100%" style="height: 100em"/>

ça a fonctionné pour moi 

4
sree

Vous pouvez le faire avec html/css comme ceci:

<body>
    <div style="width:100%; height:30px; background-color:#cccccc;">Banner</div>
    <iframe src="http: //www.google.com.tw" style="position:fixed;top:30px;bottom:0px;width:100%;"></iframe>
</body>
3
vdbuilder

J'ai utilisé display: table pour résoudre un problème similaire. Il presque _ fonctionne pour cela, laissant une petite barre de défilement verticale. Si vous essayez de renseigner cette colonne flexible avec autre chose qu'un iframe, cela fonctionne bien (pas 

Prenez le code HTML suivant

<body>
  <div class="outer">
    <div class="banner">Banner</div>
    <div class="iframe-container">
      <iframe src="http: //www.google.com.tw" style="width:100%; height:100%;border:0;"></iframe>
    </div>
  </div>
</body>

Changez la div externe pour utiliser display: table et assurez-vous qu’elle a une largeur et une hauteur définies.

.outer {
  display: table;
  height: 100%;
  width: 100%;
}

Faites de la bannière une rangée de table et définissez sa hauteur selon vos préférences:

.banner {
  display: table-row;
  height: 30px;
  background: #eee;
}

Ajoutez une div supplémentaire autour de votre iframe (ou de tout le contenu dont vous avez besoin) et faites-en une rangée de tableau avec une hauteur définie à 100% (il est essentiel de définir sa hauteur si vous souhaitez incorporer une iframe pour remplir la hauteur).

.iframe-container {
  display: table-row;
  height: 100%;
}

Ci-dessous, un jsfiddle le montrant au travail (sans iframe car cela ne semble pas fonctionner avec le violon)

https://jsfiddle.net/yufceynk/1/

2
daamsie

Nouveau en HTML5: Utilisez calc (en hauteur)

<html style="width:100%; height:100%; margin: 0px; padding: 0px;">
<body style="width:100%; height:100%; margin: 0px; padding: 0px;">
<div style="width:100%; height:30px; background-color:#cccccc;">Banner</div>
<iframe src="http://www.google.com.tw" style="width:100%; height: calc(100% - 30px);"></iframe>
</body>
</html>
2
Stefan Steiger

C'est vrai, vous montrez un iframe avec une hauteur de 100% par rapport à son conteneur: le corps.

Essaye ça:

<body>
  <div style="width:100%; height:30px; background-color:#cccccc;">Banner</div>
  <div style="width:100%; height:90%; background-color:transparent;">
    <iframe src="http: //www.google.com.tw" style="width:100%; height:100%;">
    </iframe> 
  </div>
</body>

Bien sûr, modifiez la hauteur de la deuxième div à la hauteur souhaitée.

2
ARemesal

Réponse similaire de @MichAdel, mais j'utilise JQuery et plus élégant.

<script type="text/javascript">
    $(document).ready(function() {
        var $iframe = $('#iframe_id')[0];

        // Calculate the total offset top of given jquery element
        function totalOffsetTop($elem) {
            return $elem.offsetTop + ($elem.offsetParent ? totalOffsetTop($elem.offsetParent) : 0);
        }

        function resizeIframe() {
            var height = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight;
            height -= totalOffsetTop($iframe);
            $iframe.height = Math.max(0, height) + 'px';
        }

        $iframe.onload = resizeIframe();
        window.onresize = resizeIframe;
    });
</script>

iframe_id est l'ID de la balise iframe

1
Roy Shmuli

Après avoir essayé la route css pendant un moment, j'ai fini par écrire quelque chose d'assez basique dans jQuery qui a fait le travail pour moi:

function iframeHeight() {
    var newHeight = $j(window).height();
    var buffer = 180;     // space required for any other elements on the page 
    var newIframeHeight = newHeight - buffer;
    $j('iframe').css('height',newIframeHeight);    //this will aply to all iframes on the page, so you may want to make your jquery selector more specific.
}

// When DOM ready
$(function() {
    window.onresize = iframeHeight;
}

Testé dans IE8, Chrome, Firefox 3.6

1
benb

Cela fonctionnera avec le code mentionné ci-dessous

<iframe src="http: //www.google.com.tw"style="position: absolute; height: 100%; border: none"></iframe>
1
mallikgm

Je pense que vous avez un problème conceptuel ici. Pour dire "J'ai essayé de définir hauteur: 100% sur iframe, le résultat est assez proche mais l'iframe a tenté de remplir toute la page", eh bien, quand "100%" n'est-il pas égal à "entier"?

Vous avez demandé à l'iframe de remplir toute la hauteur de son conteneur (le corps) mais, malheureusement, il a un frère au niveau du bloc dans la <div> au-dessus de laquelle vous avez demandé une taille de 30 pixels. Ainsi, il est maintenant demandé au total du conteneur parent d’être dimensionné à 100% + 30 px> 100%! D'où les barres de défilement.

Ce que je pense que vous voulez dire est que vous voudriez que l’iframe consomme ce qui reste comme les cadres et les cellules de tableau le peuvent, c’est-à-dire que height = "*". IIRC cela n'existe pas.

Malheureusement, à ma connaissance, il n’existe aucun moyen de mélanger/calculer/soustraire efficacement des unités absolues et relatives. Je pense donc que vous êtes réduit à deux options: 

  1. Positionnez absolument votre div, qui Le sortira du conteneur afin que Seul l'iframe consomme sa hauteur Conteneurs. Cela vous laisse Avec toutes sortes d'autres problèmes Cependant, mais peut-être que pour ce que vous êtes Opacité ou alignement serait Ok.

  2. Sinon, vous devez spécifier une hauteur de % Pour la div et réduire d'autant la hauteur de De l'iframe . Si la hauteur absolue est vraiment Importante, vous devrez l'appliquer qu’à un élément enfant de la div

1
annakata

L'attribut "seamless" est une nouvelle norme visant à résoudre ce problème:

http://www.w3schools.com/tags/att_iframe_seamless.asp

Lors de l'attribution de cet attribut, il supprimera les bordures et les barres de défilement et redimensionnera l'iframe à la taille de son contenu.

plus à ce sujet ici: HTML5 iFrame Seamless Attribute

0
user2254487

ou vous pouvez aller à la vieille école et utiliser un frameset peut-être:

<frameset rows="30,*">
  <frame src="banner.swf"/>
  <frame src="inner.html" />
</frameset>
0
Amir Arad

Je pense que la meilleure façon de réaliser ce scénario en utilisant la position CSS. définissez la position par rapport à votre div parent et la position: absolue à votre iframe.

.container{
  width:100%;
  position:relative;
  height:500px;
}

iframe{
  position:absolute;
  width:100%;
  height:100%;
}
<div class="container">
  <iframe src="http://www.w3schools.com">
  <p>Your browser does not support iframes.</p>
 </iframe>
</div>

css3 calc () est très avancé et compatible avec tous les navigateurs.

vérifier calc ()

0
Jay Patel

Une solution jQuery simple

Utilisez ceci dans un script à l'intérieur de la page iframed

$(function(){

    if(window != top){
        var autoIframeHeight = function(){
            var url = location.href;
            $(top.jQuery.find('iframe[src="'+ url +'"]')).css('height', $('body').height()+4);
        }
        $(window).on('resize',autoIframeHeight);
        autoIframeHeight();
    }

}
0
UnLoCo

Si vous avez accès au contenu de l'iframe qui sera chargé, vous pouvez demander à son parent de redimensionner chaque fois qu'il redimensionne.

    $(window).resize(function() {
        $(parent.document)
            .find("iframe")
            .css("height", $("body").css("height"));        
    }).trigger("resize");

Si vous avez plusieurs iframe sur la page, vous devrez peut-être utiliser un identifiant ou d'autres méthodes astucieuses pour améliorer .find ("iframe") afin de sélectionner celle qui convient.

0
Stephen

Bien que je sois d’accord sur le fait que JS semble une meilleure option, j’ai une solution fonctionnant un peu avec CSS. L'inconvénient est que si vous devez ajouter du contenu à votre document iframe html fréquemment, vous devrez adapter un pourcentage de temps en creux.

Solution:

Essayez en ne spécifiant pas n’importe quelle hauteur pour les DEUX documents HTML,

html, body, section, main-div {}

alors seulement coder ceci:

#main-div {height:100%;}
#iframe {height:300%;}

note: la div devrait être votre section principale.

Cela devrait relativement fonctionner. l'iframe calcule exactement 300% de la hauteur de la fenêtre visible. Si le contenu HTML du deuxième document (dans l'iframe) est d'une hauteur inférieure à 3 fois la hauteur de votre navigateur, cela fonctionne. Si vous n'avez pas besoin d'ajouter fréquemment du contenu à ce document, il s'agit d'une solution permanente et vous pouvez simplement trouver votre propre% nécessaire en fonction de la hauteur de votre contenu.

Cela fonctionne car cela empêche le 2e document html (celui qui est incorporé) d’hériter de sa hauteur depuis le document html parent. Cela l'empêche car nous n'avons pas spécifié de hauteur pour les deux. Lorsque nous donnons un% à l'enfant, il cherche son parent, sinon, il prend la hauteur de son contenu. Et seulement si les autres conteneurs ne sont pas dotés de hauteur, d'après ce que j'ai essayé.

0
pixelfe

Vous pouvez le faire en mesurant la taille du corps lors d'événements de chargement/redimensionnement et en définissant la hauteur sur (hauteur maximale - hauteur de la bannière).

Notez qu'actuellement dans IE8 Beta2, vous ne pouvez pas effectuer cette réduction de taille, cet événement étant actuellement interrompu dans IE8 Beta2.

0
scunliffe

vous ne pouvez pas définir la hauteur de l'iframe en%, car la hauteur de votre corps parent n'est pas de 100%; définissez donc la hauteur du parent sur 100%, puis appliquez-la à 100%

For eg.
<html>
<head>
<style>
html,body{height:100%}
</style> 
</head>
<body>
<iframe src="http://www.quasarinfosystem.com" height="100%" width="100%" ></iframe>
</body>
</html>
0
Pravin Abhale

Pourquoi ne pas le faire (avec un ajustement mineur pour le rembourrage du corps/les marges)

<script>
  var oF = document.getElementById("iframe1");
  oF.style.height = document.body.clientHeight - oF.offsetTop - 0;
</script>
0
access_granted