Para una solución CSS pura, desplácese después de la 2da <hr>
. La primera es la respuesta inicial (dada en 2016)
El principal defecto de las soluciones anteriores es que tienen una altura fija para el pie de página.
Y eso simplemente no es suficiente en el mundo real, donde las personas usan una infinidad de dispositivos y tienen el mal hábito de rotarlos cuando menos lo esperan y ** ¡Puf!** ¡ahí va el contenido de tu página detrás del pie de página!
En el mundo real, necesita una función que calcule la altura del pie de página y ajuste dinámicamente el contenido de la página padding-bottom
para acomodar esa altura. Y debe ejecutar esta pequeña función en la página load
y los resize
eventos, así como en el pie de página DOMSubtreeModified
(en caso de que su pie de página se actualice dinámicamente de forma asincrónica o contenga elementos animados que cambien de tamaño cuando interactúa).
Aquí hay una prueba de concepto, usando jQuery v3.0.0
y Bootstrap v4-alpha
, pero no hay ninguna razón por la cual no debería funcionar en versiones inferiores de cada uno.
jQuery(document).ready(function($) {
$.fn.accomodateFooter = function() {
var footerHeight = $('footer').outerHeight();
$(this).css({
'padding-bottom': footerHeight + 'px'
});
}
$('footer').on('DOMSubtreeModified', function() {
$('body').accomodateFooter();
})
$(window).on('resize', function() {
$('body').accomodateFooter();
})
$('body').accomodateFooter();
window.addMoreContentToFooter = function() {
var f = $('footer');
f.append($('<p />', {
text: "Human give me attention meow flop over sun bathe licks your face wake up wander around the house making large amounts of noise jump on top of your human's bed and fall asleep again. Throwup on your pillow sun bathe. The dog smells bad jump around on couch, meow constantly until given food, so nap all day, yet hiss at vacuum cleaner."
}))
.append($('<hr />'));
}
});
body {
min-height: 100vh;
position: relative;
}
footer {
background-color: rgba(0, 0, 0, .65);
color: white;
position: absolute;
bottom: 0;
width: 100%;
padding: 1.5rem;
display: block;
}
footer hr {
border-top: 1px solid rgba(0, 0, 0, .42);
border-bottom: 1px solid rgba(255, 255, 255, .21);
}
<link href="http://v4-alpha.getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="http://v4-alpha.getbootstrap.com/examples/starter-template/starter-template.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.2.0/js/tether.min.js"></script>
<script src="http://v4-alpha.getbootstrap.com/dist/js/bootstrap.min.js"></script>
<nav class="navbar navbar-toggleable-md navbar-inverse bg-inverse fixed-top">
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="#">Navbar</a>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="http://example.com" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<div class="container">
<div class="starter-template">
<h1>Feed that footer - not a game (yet!)</h1>
<p class="lead">You will notice the body bottom padding is growing to accomodate the height of the footer as you feed it (so the page contents do not get covered by it).</p><button class="btn btn-warning" onclick="window.addMoreContentToFooter()">Feed that footer</button>
<hr />
<blockquote class="lead"><strong>Note:</strong> I used jQuery <code>v3.0.0</code> and Bootstrap <code>v4-alpha</code> but there is no reason why it shouldn't work with lower versions of each.</blockquote>
</div>
</div>
<footer>I am a footer with dynamic content.
<hr />
</footer>
Inicialmente, publiqué esta solución aquí, pero me di cuenta de que podría ayudar a más personas si se publica bajo esta pregunta.
Nota: Me han envuelto a propósito del $([selector]).accomodateFooter()
como un plugin de jQuery, por lo que podría ser ejecutado en cualquier elemento DOM, como en la mayoría de los diseños que no es el $('body')
's bottom-padding
que las necesidades de ajuste, pero alguna página envoltorio elemento con position:relative
(por lo general el padre inmediato del footer
) .
Edición posterior (más de 3 años después de la respuesta inicial):
En este punto, ya no considero aceptable el uso de JavaScript para colocar un pie de página de contenido dinámico en la parte inferior de la página. Se puede lograr solo con CSS, usando flexbox, a la velocidad del rayo, entre navegadores.
Aquí está:
// Left this in so you could inject content into the footer and test it:
// (but it's no longer sizing the footer)
function addMoreContentToFooter() {
var f = $('footer');
f.append($('<p />', {
text: "Human give me attention meow flop over sun bathe licks your face wake up wander around the house making large amounts of noise jump on top of your human's bed and fall asleep again. Throwup on your pillow sun bathe. The dog smells bad jump around on couch, meow constantly until given food, so nap all day, yet hiss at vacuum cleaner."
}))
.append($('<hr />'));
}
.wrapper {
min-height: 100vh;
padding-top: 54px;
display: flex;
flex-direction: column;
}
.wrapper>* {
flex-grow: 0;
}
.wrapper>main {
flex-grow: 1;
}
footer {
background-color: rgba(0, 0, 0, .65);
color: white;
width: 100%;
padding: 1.5rem;
}
footer hr {
border-top: 1px solid rgba(0, 0, 0, .42);
border-bottom: 1px solid rgba(255, 255, 255, .21);
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<div class="wrapper">
<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<main>
<div class="container">
<div class="starter-template">
<h1>Feed that footer - not a game (yet!)</h1>
<p class="lead">Footer won't ever cover the body contents, as its not fixed. It's simply placed at the bottom when the page should be shorter using `min-height:100vh` on container and using flexbox to push it down.</p><button class="btn btn-warning" onclick="addMoreContentToFooter()">Feed that footer</button>
<hr />
<blockquote class="lead">
<strong>Note:</strong> This example uses current latest versions of jQuery (<code>3.4.1.slim</code>) and Bootstrap (<code>4.4.1</code>) (unlike the one above).
</blockquote>
</div>
</div>
</main>
<footer>I am a footer with dynamic content.
<hr />
</footer>
</div>