Rodapé na parte inferior da página ou conteúdo, o que for inferior

92

Tenho a seguinte estrutura:

<body>
    <div id="main-wrapper">
        <header>
        </header>
        <nav>
        </nav>
        <article>
        </article>
        <footer>
        </footer>
    </div>
</body>

Eu carrego conteúdo dinamicamente no <article>usando javascript. Por causa disso, a altura do <article>bloco pode mudar.

Quero que o <footer>bloco fique na parte inferior da página quando houver muito conteúdo, ou na parte inferior da janela do navegador quando houver apenas algumas linhas de conteúdo.

No momento, posso fazer um ou outro ... mas não ambos.

Então, alguém sabe como posso fazer isso - conseguir <footer>que se fixe na parte inferior da página / conteúdo ou na parte inferior da tela, dependendo de qual estiver abaixo.

Vai
fonte
As pessoas se importariam em comentar por que votaram contra uma questão de 2 anos?
Será
Vamos lá, já se passaram quase 6 anos ...
Will

Respostas:

99

O rodapé pegajoso de Ryan Fait é muito bom, mas acho que sua estrutura básica está ausente *.


Versão Flexbox

Se você tiver a sorte de poder usar o flexbox sem precisar oferecer suporte a navegadores mais antigos, os rodapés fixos se tornam trivialmente fáceis e oferecem suporte a um rodapé de tamanho dinâmico.

O truque para fazer com que os rodapés fiquem fixos na parte inferior com o flexbox é ter outros elementos no mesmo contêiner flexíveis verticalmente. Tudo o que é necessário é um elemento wrapper de altura total com display: flexe pelo menos um irmão com um flexvalor maior que 0:

CSS:
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#main-wrapper {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

article {
  flex: 1;
}


Se você não pode usar o flexbox, minha estrutura base de escolha é:

<div class="page">
  <div class="page__inner">
    <header class="header">
      <div class="header__inner">
      </div>
    </header>
    <nav class="nav">
      <div class="nav__inner">
      </div>
    </nav>
    <main class="wrapper">
      <div class="wrapper__inner">
        <div class="content">
          <div class="content__inner">
          </div>
        </div>
        <div class="sidebar">
          <div class="sidebar__inner">
          </div>
        </div>
      </div>
    </main>
    <footer class="footer">
      <div class="footer__inner">
      </div>
    </footer>
  </div>
</div>

O que não está tão longe de:

<div id="main-wrapper">
    <header>
    </header>
    <nav>
    </nav>
    <article>
    </article>
    <footer>
    </footer>
</div>

O truque para fazer o rodapé aderir é ter o rodapé ancorado no preenchimento inferior do elemento que o contém. Isso requer que a altura do rodapé seja estática, mas descobri que os rodapés normalmente têm uma altura estática.

HTML:
<div id="main-wrapper">
    ...
    <footer>
    </footer>
</div>
CSS:
#main-wrapper {
    padding: 0 0 100px;
    position: relative;
}

footer {
    bottom: 0;
    height: 100px;
    left: 0;
    position: absolute;
    width: 100%;
}

Com o rodapé ancorado em #main-wrapper, agora você precisa #main-wrapperter pelo menos a altura da página, a menos que seus filhos sejam mais longos. Isso é feito criando #main-wrapperum min-heightde 100%. Você também deve lembrar que seus pais, htmle bodyprecisam ser tão altos quanto a página também.

CSS:
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
}

#main-wrapper {
    min-height: 100%;
    padding: 0 0 100px;
    position: relative;
}

footer {
    bottom: 0;
    height: 100px;
    left: 0;
    position: absolute;
    width: 100%;
}

Claro, você deve estar questionando meu julgamento, já que este código está fazendo com que o rodapé caia da parte inferior da página, mesmo quando não há conteúdo. O último truque é mudar o modelo de caixa utilizado pelo #main-wrappermodo que o min-heightde 100%inclui o 100pxpreenchimento.

CSS:
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
}

#main-wrapper {
    box-sizing: border-box;
    min-height: 100%;
    padding: 0 0 100px;
    position: relative;
}

footer {
    bottom: 0;
    height: 100px;
    left: 0;
    position: absolute;
    width: 100%;
}

E aí está, um rodapé com sua estrutura HTML original. Apenas certifique-se de que o footer's heighté igual a #main-wrapper' s padding-bottom, e você deve estar configurado.


* O motivo pelo qual encontro falhas na estrutura do Fait é porque ele define os elementos .footere .headerem diferentes níveis hierárquicos enquanto adiciona um .pushelemento desnecessário .

zzzzBov
fonte
Eu precisava adicionar #main-wrapper *:first-child { margin-top: 0; }, caso contrário, a página ficaria muito longa na margem superior do primeiro filho (causando uma barra de rolagem desnecessária em páginas curtas).
Florian Brucker
Obrigado, @zzzzBov por esta explicação completa, e especialmente por mencionar o flex-direction (gostaria de ter descoberto isso antes - teria me economizado algumas horas! :)
ea0723
A versão Flexbox não está funcionando para mim no IE11, mas a outra abordagem é adequada para mim! Obrigado e +1!
Matt
@Matt, você precisa usar prefixos de navegador para fazer o flexbox funcionar no IE11. use uma ferramenta como o autoprefixer e você nunca precisará se preocupar em adicioná-los manualmente.
zzzzBov
2
O link de rodapé fixo parece estar quebrado devido ao site ter sido convertido em um aviso In Memoriam para ele. Além disso, não há versões em cache devido às configurações de robots.txt
tzrlk
13

O rodapé autocolante de Ryan Fait é uma solução simples que usei várias vezes no passado.

HTML básico :

<div class="wrapper">
    <div class="header">
        <h1>CSS Sticky Footer</h1>
    </div>
    <div class="content"></div>
    <div class="push"></div>
</div>
<div class="footer"></div>

CSS :

* {
    margin: 0;
}
html, body {
    height: 100%;
}
.wrapper {
    min-height: 100%;
    height: auto !important;
    height: 100%;
    margin: 0 auto -142px; /* the bottom margin is the negative value of the footer's height */
}
.footer, .push {
    height: 142px; /* .push must be the same height as .footer */
}

/*

Sticky Footer by Ryan Fait
http://ryanfait.com/

*/

Traduzir isso para ser semelhante ao que você já tem resultados com algo neste sentido:

HTML :

<body>
    <div class="wrapper">
        <header>
        </header>
        <nav>
        </nav>
        <article>
        </article>
        <div class="push"></div>
    </div>
    <footer>
    </footer>
</body>

CSS:

* {
    margin: 0;
}
html, body {
    height: 100%;
}
.wrapper {
    min-height: 100%;
    height: auto !important;
    height: 100%;
    margin: 0 auto -142px; /* the bottom margin is the negative value of the footer's height */
}
footer, .push {
    height: 142px; /* .push must be the same height as .footer */
}

Só não se esqueça de atualizar o negativo na margem do wrapper para coincidir com a altura do seu rodapé e pressione div. Boa sorte!

Josh Mein
fonte
4
Eu adoro a maneira como ele colocou o comentário no final, apropriado para uma solução de rodapé: D
Fantasma de Madara
Não há necessidade de alterar a marcação para este estilo específico.
zzzzBov
@zzzzBov Não tenho muito tempo para examinar isso mais profundamente agora, mas o que exatamente você quer dizer?
Josh Mein
Estou em meu caixa eletrônico móvel, então não posso escrever uma resposta completa, caso contrário, já teria feito isso. O comentário foi mais para que eu me lembrasse de adicionar uma resposta mais tarde.
zzzzBov
@JoshMein, adicionei uma resposta que explica como fazer o rodapé ficar sem bagunçar a estrutura fornecida.
zzzzBov
0

Eu estava tentando resolver esse problema sem adicionar nenhuma marcação adicional, então acabei usando a seguinte solução:

article {
  min-height: calc(100vh - 150px); /* deduct the height or margins of any other elements within wrapping container*/
}

footer {
  height: 50px;
}

header {
   height: 50px;
}

nav {
  height: 50px;
}
<body>
  <div id="main-wrapper">
    <header>
    </header>
    <nav>
    </nav>
    <article>
    </article>
    <footer>
    </footer>
  </div>
</body>

Você tem que saber as alturas do cabeçalho, do nav e do rodapé para poder definir a altura mínima do artigo. Com isso, se o artigo tiver apenas poucas linhas de conteúdo, o rodapé ficará na parte inferior da janela do navegador, caso contrário, ficará abaixo de todo o conteúdo.

Você pode encontrar essa e outras soluções postadas acima aqui: https://css-tricks.com/couple-takes-sticky-footer/

Galina E
fonte