jQuery / Comparar width, innerWidth e outerWidth

.width() mede conteúdo, .innerWidth() acrescenta padding horizontal e .outerWidth() também bordas. .outerWidth(true) inclui margens horizontais. Retornam números em pixels, diferentes de uma string CSS width.

Escolher o limite da medição

O modelo de caixa CSS envolve conteúdo com padding, borda e margem. Escolha o limite necessário; um número maior não é automaticamente mais preciso.

Chamada Inclui content-box border-box
.width() Conteúdo 200 150
.innerWidth() Conteúdo + padding 240 190
.outerWidth() Conteúdo + padding + borda 250 200
.outerWidth(true) Anterior + margem 270 220
.css("width") String CSS calculada 200px 200px

Condições: CSS width 200px, padding 20px, borda 5px e margem 10px por lado. .width() continua medindo conteúdo em border-box; .innerWidth() e .outerWidth() acrescentam seus limites.

Com box-sizing content-box, o exterior é 200+40+10=250. Em border-box, padding e borda cabem em CSS 200, deixando conteúdo 150. O significado de .width() permanece; muda o alcance da atribuição CSS.

Exemplo completo de comparação

Salve tudo em UTF-8 como width-demo.html e abra no navegador. A Internet carrega o arquivo oficial do jQuery 4.0.0. Não exige servidor nem pacotes. Valores iniciais, mudanças e restauração de padding e frações foram executados no Edge para Windows com 3.7.1 e 4.0.0.

As condições iniciais diferem apenas em box-sizing. .case permite rolagem horizontal local em telas estreitas. margin na saída é o total .outerWidth(true), não só a margem.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Compare jQuery width measurements</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 20px; }
    button { font: inherit; margin: 4px; }
    .case { overflow-x: auto; background: #f4f7f8; margin: 12px 0; }
    .box { width: 200px; padding: 20px; border: 5px solid teal; margin: 10px; background: #fff; }
    #content { box-sizing: content-box; }
    #border { box-sizing: border-box; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <button type="button" id="padding">Toggle padding 20 / 40</button>
  <button type="button" id="fraction">Toggle width 200 / 200.5</button>
  <button type="button" id="reset">Reset</button>
  <div class="case"><div class="box" id="content">content-box</div></div>
  <div class="case"><div class="box" id="border">border-box</div></div>
  <pre id="result" aria-live="polite"></pre>
  <script>
    $(function () {
      let padding = 20, width = 200;
      function report() {
        const lines = [];
        $(".box").each(function () {
          const $box = $(this);
          lines.push(`${this.id}: css=${$box.css("width")}; width=${$box.width()}; inner=${$box.innerWidth()}; outer=${$box.outerWidth()}; margin=${$box.outerWidth(true)}`);
        });
        $("#result").text(lines.join("\n"));
      }
      $("#padding").on("click", function () {
        padding = padding === 20 ? 40 : 20;
        $(".box").css("padding", padding + "px"); report();
      });
      $("#fraction").on("click", function () {
        width = width === 200 ? 200.5 : 200;
        $(".box").css("width", width + "px"); report();
      });
      $("#reset").on("click", function () {
        padding = 20; width = 200;
        $(".box").css({ padding: "20px", width: "200px" }); report();
      });
      report();
    });
  </script>
</body>
</html>

Saída inicial: mesma largura CSS, medidas diferentes de conteúdo e borda.

content: css=200px; width=200; inner=240; outer=250; margin=270
border: css=200px; width=150; inner=190; outer=200; margin=220
  1. Toggle padding 20 / 40 mantém width=200 em content-box; inner=280, outer=290 e margin=310.
  2. border-box mantém exterior 200: width=110, inner=190, outer=200 e margin=220. O conteúdo diminui.
  3. Pressione novamente para restaurar padding 20 e a saída inicial.
  4. Toggle width 200 / 200.5 aumenta cada medida em 0,5. Não suponha resultados inteiros.
  5. Reset restaura width e padding das duas caixas sem alterar CSS global.

Números e vários elementos

Sem argumentos, o getter mede o primeiro elemento correspondente. Use .each() ou .map() para todos. Após Reset, execute nas ferramentas de desenvolvimento:

console.log($("#content, #border").width());
console.log($(".box").map(function () { return $(this).width(); }).get().join(","));
console.log($(".missing").width(), $(".missing").innerWidth(), $(".missing").outerWidth());

A primeira linha mede apenas content-box; a seguinte, ambos os conteúdos. Um conjunto vazio retorna undefined nas versões testadas 3.7.1 e 4.0.0.

200
200,150
undefined undefined undefined

Diferencie largura zero de coleção vazia. Confira length e resultado para evitar NaN ao calcular com undefined. .css("width") contém unidades e pode concatenar em vez de somar. Truncar sempre com parseInt acumula erros entre elementos.

O artigo trata de getters. Um argumento como .width(200) define largura; omita-o para apenas medir.

Momento e limites visíveis

Não dependa de medidas com display:none no elemento ou ancestrais. Exibir temporariamente pode ser pouco confiável e caro; meça após layout real. visibility:hidden preserva o espaço. Imagens, fontes e conteúdo dinâmico podem mudar dimensões depois de o DOM estar pronto.

Para limites após transformações CSS, considere getBoundingClientRect(). scale(0.5) em content-box produziu .outerWidth()=250 e retângulo=125. Rotação também muda o retângulo envolvente; as APIs não são intercambiáveis.

Não aplique innerWidth ou outerWidth de elementos normais a window ou document; use os .width() apropriados. Somar margens não explica toda ocupação do pai ou espaçamento entre irmãos.

Confira barras de rolagem, bordas de tabela colapsadas, zoom, arredondamento e mudanças de layout no ambiente real. Alternar escritas de estilo e leituras de dimensão pode aumentar cálculos de layout; agrupe as operações necessárias.