【问题标题】:CSS 100% width but avoid scrollbarCSS 100% 宽度但避免滚动条
【发布时间】:2011-04-02 07:05:09
【问题描述】:

这可能是已经解决了几十次的问题的变体,但 CSS 真的让我觉得自己像个傻瓜。

我正在尝试构建一个可以以多种方式定位和调整大小的小部件。这是一个非常简单的布局——固定高度的页眉、固定高度的页脚和占据剩余空间的正文。整体宽度和高度各不相同。正文的内容需要滚动。我的整体容器、页眉、页脚和正文大小都可以。

但我想要的是当滚动条出现时,身体在需要时滚动而不向左收缩内容。也就是说,我希望主体尽可能宽,减去如果它需要滚动时会出现的滚动条,这样当它确实需要滚动时就不会收缩。实际上,我想要这个:

| - - - unknown width - - -|
+--------------------------+
| content                |*|
| might                  |*|
| scroll                 |*|
+--------------------------+

我希望可能滚动的内容尽可能宽,减去潜在的滚动条宽度(|*| 区域)。

我现在是这样的:

<div id="content" style="position: absolute; overflow-y: auto; width: 100%">
    <div id="scrollContent" style="???">
    </div>
</div>

我已经尝试了最里面的 div 的边距、填充,甚至 %-widths 以及所有“做转变”的事情。我还需要它在 FF3、IE7/8 和(幻想?)IE6 中工作。

【问题讨论】:

标签: css


【解决方案1】:

为什么不总是显示滚动条,即使不需要滚动?

您可以通过将overflow:scroll; 设置为容器来实现此目的。

【讨论】:

    【解决方案2】:

    使用overflow: scroll 而不是overflow: auto - 这将强制滚动条始终出现。

    【讨论】:

    • 嗯,这当然可以防止移位/收缩,但我真的希望不必这样做。
    • @n8wrl:这确实是你可以单独使用 CSS 做的最好的事情。
    • 感谢您抽出宝贵时间
    • 我有overflow: scroll;width: 100%;,但元素还是太宽(有水平滚动条)。
    【解决方案3】:

    在元素内添加另一个包装器,该包装器将具有溢出:自动样式并将其设置为窄约 18 像素。滚动条应该出现在 18px 的间隙中。

    【讨论】:

    • +1,但是由于 OP 不知道容器的宽度,所以他需要 JavaScript 来实现。
    • 使用 FF 和 IE9(来到您附近的浏览器!)执行类似 (FF) width: -moz-calc(100% - 16px);
    • @Stephen 滚动条为 27 倍(或其他)除外。万岁。
    • 我使用了 16px,我宁愿滚动条剪辑一点点也不愿留下一个小间隙。还通过使用包装器并设置 margin-right 16px 来做到这一点,从而允许原始元素保持在 100% 且没有 tomfoolery。
    【解决方案4】:

    问题是,一旦您将鼠标悬停在容器上并出现滚动条,内容宽度就会缩小。所以即使你使用宽度等于容器减去滚动条的嵌套容器,嵌套容器的宽度也会缩小。

    一种解决方案是通过悬停时滚动条的宽度来增加内容的大小。这是一个不需要使用任何嵌套外部容器的解决方案(categoryCont 是滚动容器,每个 menuBlock 是要滚动的项目之一):

    <div id="categoryCont" style="position:relative;width:200px; overflow:hidden;">
        <div class="menuBlock" style="width:200px">a</div>
        <div class="menuBlock" style="width:200px">b</div>
        <div class="menuBlock" style="width:200px">c</div>
        ...
    </div>
    
    <style type="text/css">
        #categoryCont:hover{
            overflow-y: auto;
        }
        #categoryCont:hover .menuBlock{
        /* Increase size of menu block when scrollbar appears */
            width: 218px;    /* Adjust for width of scroll bar. */
        }
    </style>
    

    上面的一个问题是滚动条的宽度在不同的浏览器中略有不同。以下其中一项应该会有所帮助:

    • 通过使用像素

    使内容为绝对值,左缩进为绝对值

    <div class="menuBlock" style="width:200px">
        a
    </div>
    

    更改为

    <div class="menuBlock" style="width:200px">
        <span>a</span>
    </div>
    
    <style>
        .menuBlock span{        /* Good cross-browser solution but cannot use % */
            position:absolute;
            left:70px;
        }
    </style>
    
    • 通过使用 %

    CSS 和 jQuery 都需要(第一步相同)

    <div class="menuBlock" style="width:200px">
        a
    </div>
    

    更改为

    <div class="menuBlock" style="width:200px">
        <span>a</span>
    </div>
    
    <style>
        .menuBlock span{        /* Good cross-browser solution but cannot use % */
            position:absolute;  /* This one does not use 'left' */
        }
    </style>
    
    <script>
        // Indent left 30% because container width remains same but content width changes
        var leftIndent = (30/100) * $("#categoryCont").width();
        $(".menuBlock span").css({"left":leftIndent});
    </script>
    

    【讨论】:

      【解决方案5】:

      我遇到了一个与我使用以下解决方案类似的问题,我不确定这是否可以解决您想要做的事情,但它可能是。

      我有一个 div 可以根据内容自动调整大小,然后添加滚动条,缩小内部,以便其中的表格包含文本,而不是使容器更宽。如果 textarea 向下调整大小并出现滚动,则在下面的旧示例中可以看到不需要的效果。

      我丑陋的解决方案是在 overflow-y:auto-div 中添加一个具有 display:inline-block 的 div,并在其后添加另一个小的 inline-block div,宽度为 19 像素(保留用于滚动条)和一个像素高。当浏览器将 div 调整为内容的大小时,那个小 div 会出现在真实 div 的旁边,当滚动条出现时,小 div 会被向下推到真实 div 的下方,而真实 div 会保持它的状态。它会导致一个像素的底部“边距”,但希望不是问题。当没有滚动条出现时,真实的 div 旁边还有 19 像素的未使用空间,如问题中所述。

      (最外面的 div 只是用来复制我的设置/问题。)

      旧:

      <div style="display:inline-block">
        <div style="max-height:120px; overflow-y:auto; border:1px solid gray">
          <table border=1><tr>
             <td>I do not</td><td>want this to</td>
             <td>add breaks in the text.</td>
          </tr></table>
          <textarea rows=3 cols=15>Resize me down</textarea>
        </div>
      </div>
      <br>
      

      新:

      <div style="display:inline-block">
        <div style="max-height:150px;overflow-y:auto; border:1px solid gray">
          <div style="display:inline-block">
            <table border=1><tr>
                <td>I do not</td><td>want this to</td>
                <td>add breaks in the text.</td>
            </tr></table>
            <textarea rows=3 cols=15>Resize me down</textarea>
          </div>
          <div style="display:inline-block; width:19px; height:1px"></div>
        </div>
      </div>
      <br>
      

      【讨论】:

        【解决方案6】:
        You can do it with using this css on the content element: `calc(100% - 15px)`.
        // calc(100% - the width we want to give on right hand side of content)
        

        请阅读以下内容以了解其工作原理。

        绝对是使用overflow:scroll. 修复它的最简单且不那么混乱的方法

        但是,如果您不想在不需要时显示滚动,那么您应该使用相对于viewport (vw) 的宽度,而不是使用 100%。由于滚动条出现在视口宽度中,如果我们知道滚动条的宽度,那么我们可以使用以下公式完成我们的任务。在这里,我将内容宽度设置为视口宽度减去滚动条的宽度(比如说 15px)。

        您需要提供宽度为:calc(100% - 15px)。您可以提供以 %、em 等为单位的宽度。

        最好的方法是覆盖滚动条的宽度,如下所示,然后在公式中使用该宽度值进行减法。

        /* width */
        ::-webkit-scrollbar {
          width: 10px;
        } 
        #content {
          width: calc(100% - 10px).
        }
        

        注意:Firefox 或 Edge 79 之前的版本不支持自定义滚动条。而且此 CSS 仅适用于 webkit 浏览器,因此它可能不适用于 IE。

        所以你可以使用 20px 的最大宽度来减去,因为滚动条的宽度永远不会超过 20px。请在下面找到工作代码。

        .scroll {
            height: 100px;
            overflow: auto;
            border: 1px solid black;
            width: 75%;
        }
        
        .zui-table {
              width: calc(100% - 10px);
            border: solid 1px #DDEEEE;
            border-collapse: collapse;
            border-spacing: 0;
            font: normal 13px Arial, sans-serif;
        }
        .zui-table thead th {
            background-color: #DDEFEF;
            border: solid 1px #DDEEEE;
            color: #336B6B;
            padding: 10px;
            text-align: left;
            text-shadow: 1px 1px 1px #fff;
        }
        .zui-table tbody td {
            border: solid 1px #DDEEEE;
            color: #333;
            padding: 10px;
            text-shadow: 1px 1px 1px #fff;
        }
        <div class="scroll">
          <table class="zui-table">
            <thead>
              <tr>
                <th>Name</th>
                <th>Position</th>
                <th>Height</th>
                <th>Born</th>
                <th>Salary</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>DeMarcus Cousins</td>
                <td>C</td>
                <td>6'11"</td>
                <td>08-13-1990</td>
                <td>$4,917,000</td>
              </tr>
              <tr>
                <td>Isaiah Thomas</td>
                <td>PG</td>
                <td>5'9"</td>
                <td>02-07-1989</td>
                <td>$473,604</td>
              </tr>
              <tr>
                <td>Ben McLemore</td>
                <td>SG</td>
                <td>6'5"</td>
                <td>02-11-1993</td>
                <td>$2,895,960</td>
              </tr>
              <tr>
                <td>Marcus Thornton</td>
                <td>SG</td>
                <td>6'4"</td>
                <td>05-05-1987</td>
                <td>$7,000,000</td>
              </tr>
              <tr>
                <td>Jason Thompson</td>
                <td>PF</td>
                <td>6'11"</td>
                <td>06-21-1986</td>
                <td>$3,001,000</td>
              </tr>
            </tbody>
          </table>
        </div>

        【讨论】:

        • 来自问题整体宽度和高度各不相同。。您假设宽度等于屏幕宽度
        • 在这种情况下,我们可以使用我给定的宽度设置最顶层封闭父级的宽度。因此,当滚动条出现或消失时,它不会切换。在我看来,我们绝对可以使用这种方法解决问题。
        • @TemaniAfif,然后是calc(100% - 10px)。这是最好的答案,只需将100vw 替换为100%。水平滚动条很难以这种方式解决,但幸运的是 OP 似乎不需要。
        • @Slbox calc(100% - 10px) 的行为与 100% 相同,因为它已经考虑了滚动条。这个答案的诀窍是使用 vw 单位,其尺寸不受滚动条宽度的影响,但(如像素,但像素不响应)
        • 100% 如果元素已经占用了100vw 将表现相同,否则,它会不一样。您自己注意这一点,“您假设宽度等于屏幕宽度”。所以使用100% 这不是问题。就它占据整个宽度而言,是的 - 这就是calc() 在答案中的用途。
        【解决方案7】:

        The answer by Mattias Ottosson 到另一个问题提供了一条关键信息 - vw 单位基于视口宽度包括滚动条,而百分比将基于可用宽度 包括滚动条占用的空间。也就是说,对于占据整个页面宽度的元素,滚动条的宽度可以表示为calc(100vw - 100%)

        如果我们有一个顶级元素占用100% 的可用宽度,那么我们可以使用它来控制滚动条变得可见时改变大小的内容。假设我们的目标布局是这样的:

        .app {
          display: grid;
          grid-template-columns: 1fr 50vh 1fr;
        }
        

        我们希望中间列的宽度为视口高度的 50%,其余的宽度在左右列之间划分。如果我们使用它,那么添加滚动条意味着滚动条损失的水平空间(chrome 上大约 15px)从左右列的宽度中相等地取出。当 ui 更改导致滚动条出现而网格中的主要内容保持相同或相似时,这可能会导致丑陋的转变。请参阅下面的第一个 sn-p。

        我们可以使用计算出的滚动条宽度来代替只缩小右列:

        .app {
          display: grid;
          grid-template-columns: calc((100vw - 50vh)/2) 50vh calc(100% - (50vh + 100vw)/2);
        }
        

        请参阅下面的第二个 sn-p。不幸的是,这意味着不能使用fr 单位,并且必须手动指定列的宽度。在这种情况下,左列的宽度是视口宽度减去中心列占用的50vh 的一半。右列的宽度是可用宽度100% 而不是100vw)减去左列和中间列的组合宽度后的剩余空间。这在公式中更清楚:

        calc(100% - ((100vw - 50vh)/2) - (50vh))
        

        减少到上面那个

        第一个sn-p,滚动条出现时丑陋的跳转

        $('button').click(() => {
          $('.footer').toggle()
        })
        body, html {
          height: 100%;
          width: 100%;
          padding: 0;
          margin: 0;
          overflow: auto;
          font-family: 'Archivo', sans-serif ;
        }
        .app {
          margin: auto;
          display: grid;
          grid-template-columns: 1fr 50vh 1fr;
          text-align: center;
          height: 100%;
          width: calc(100% - 10px);
        }
        .left-column, .center-column, .right-column {
          padding: 10px;
          min-height: 50vh;
          border: 1px solid black;
        }
        .left-column {
          border-right: none;
          background-color:#def;
        }
        .center-column {
          background-color:#e1ebbd;
        }
        .right-column {
          text-align: left;
          border-left: none;
          background: #fb1;
        }
        .footer {
          grid-column: 1 / span 3;
          height: 2000px;
          background: #753;
        }
        <!DOCTYPE html>
        <html>
        <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width">
          <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        
        </head>
        <body>
          <div class="app">
            <div class="left-column">
              Left
            </div>
            <div class="center-column">
              Center
        <script src="https://code.jquery.com/jquery-3.1.0.js"></script><br>
              <button>Toggle footer</button>
            </div>
            <div class="right-column">
              Right
            </div>
            <div class="footer">
         </div>
          </div>
        </body>
        </html>

        第二个sn-p,出现滚动条时右栏缩小

        $('button').click(() => {
          $('.footer').toggle()
        })
        body, html {
          height: 100%;
          width: 100%;
          padding: 0;
          margin: 0;
          overflow: auto;
          font-family: 'Archivo', sans-serif ;
        }
        .app {
          margin: auto;
          display: grid;
          grid-template-columns: calc((100vw - 50vh)/2) 50vh calc(100% - (50vh + 100vw)/2);
          text-align: center;
          height: 100%;
          width: calc(100% - 10px);
        }
        .left-column, .center-column, .right-column {
          padding: 10px;
          min-height: 50vh;
          border: 1px solid black;
        }
        .left-column {
          border-right: none;
          background-color:#def;
        }
        .center-column {
          background-color:#e1ebbd;
        }
        .right-column {
          text-align: left;
          border-left: none;
          background: #fb1;
        }
        .footer {
          grid-column: 1 / span 3;
          height: 2000px;
          background: #753;
        }
        <!DOCTYPE html>
        <html>
        <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width">
          <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        
        </head>
        <body>
          <div class="app">
            <div class="left-column">
              Left
            </div>
            <div class="center-column">
              Center
        <script src="https://code.jquery.com/jquery-3.1.0.js"></script><br>
              <button>Toggle footer</button>
            </div>
            <div class="right-column">
              Right
            </div>
            <div class="footer">
         </div>
          </div>
        </body>
        </html>

        【讨论】:

          【解决方案8】:

          我知道您只想使用 CSS 来实现这一点,但我提供了一个 jQuery 解决方案以防有人寻求帮助。

          使用 jQuery,您可以获取滚动条大小,然后对容器应用边距。

          类似这样的:

          var checkScrollBars = function(){
              var b = $('body');
              var normalw = 0;
              var scrollw = 0;
              if(b.prop('scrollHeight')>b.height()){
                  normalw = window.innerWidth;
                  scrollw = normalw - b.width();
                  $('#container').css({marginRight:'-'+scrollw+'px'});
              }
          }
          

          上面的代码sn-p会在所有内容的高度大于容器高度的时候加一个边距。

          如果不需要,我们也可以移除水平滚动条:

          body{
              overflow-x:hidden;
          }
          

          【讨论】:

          • 这是 jQuery。您应该始终说明您正在使用的库/框架
          • @GustvandeWal 感谢您的建议。我已经改了。
          【解决方案9】:

          您可以“获取”并将滚动条宽度与纯 CSS 一起使用的唯一方法是让滚动条 be 存在。现在,我们不想强制滚动条一直可见,所以我们要做的是: 为始终显示滚动条的所有网站内容创建一个容器,并将其隐藏。这非常简单!
          我创建了a Fiddle。这是一个sn-p:

          /* The trick: */
          
          html {
            overflow-x: hidden;
          }
          
          body {
            margin: 0;
            width: 100vw;
          }
          
          body > * {
            overflow-y: scroll;
            margin-right: -100px;
            padding-right: 100px;
          }
          
          /* Other styling: */
          
          body {
            font-family: sans-serif;
            user-select: none;
            --color: rgb(255 191 191);
          }
          
          header {
            position: sticky;
            top: 0;
            z-index: 1;
            --color: rgb(191 191 255);
          }
          
          body > * > div {
            background-color: var(--color);
            border: 3px solid;
            margin: 10px;
            padding: 20px;
            font-size: 20px;
            font-weight: bold;
          }
          
          label::before {
            position: relative;
            content: '';
            display: inline-block;
            width: 1em;
            height: 1em;
            margin: 0 10px;
            top: .2em;
            border: 1px solid;
            border-radius: .1em;
          }
          
          input:checked + label::before {
            background-color: var(--color);
            box-shadow: inset 0 0 0 1px #FFF;
          }
          
          input {
            display: none;
          }
          
          input:not(:checked) ~ div {
            display: none;
          }
          
          input ~ div {
            height: 200vh;
          }
          <header>
            <div>I am sticky!</div>
          </header>
          <main>
            <div>Hello world!</div>
            <input id="foo-2" type="checkbox" />
            <label for="foo-2">Click me</label>
            <div>Let's scroll</div>
          </main>

          诀窍是给包含的元素一个负边距和正向填充。用于这两个属性的偏移量可以超过滚动条宽度,因此将其设为100px 就足够了——我无法想象任何浏览器或网站的滚动条宽度超过20px,更不用说100px


          顺便说一句:我之所以将这些样式应用于body 的每个直接子元素,而不是使用单个#container 元素,是因为否则position: sticky 将不起作用。要让该功能在一个元素上工作,它只能有一个具有滚动功能的祖先。

          html 包含 #container 包含 sticky element ->不起作用

          html 包含 sticky container ->确实有效

          【讨论】:

          • 很好的答案
          • 和这个问题无关,在你的sn-p中,为什么要把checkbox换成你自己的?
          • @huyz,谢谢!如果它可以保持可访问性(它不在 sn-p 中,顺便说一句),我会重新创建几乎每个 UI 元素。这样,我可以 1. 更好地为元素设置动画(例如,input 元素是 void 元素,不能有伪元素)和 2. 提供更强大的实现(更跨浏览器和面向未来不允许浏览器样式开始,而是从头开始创建我自己的样式)。见this Fiddle
          【解决方案10】:
          * {
              overflow: hidden;
          }
          

          隐藏滚动条的简单方法

          【讨论】:

          【解决方案11】:

          我不太确定您的要求是什么(抱歉,我的 CSS 经验很少),但我认为您想使用 CSS 将 HTML div 元素的宽度设置为 100%,而无需滚动栏出现。这是一个解决方案。

          #element {
            background-color: blue;
            height: 40px;
            position: relative;
            margin-left: 0px;
            margin-right: 0px;
            padding-left: 0px;
            padding-right: 0px;
            width: 100%;
          }
          <!DOCTYPE html>
          <html lang="en">
            <body>
              <div id="element"></div>
            </body>
          </html>

          由于div 元素的positionmarginpadding 属性而出现滚动条。如果将margin-rightmargin-leftpadding-rightpadding-left 属性设置为0,并将position 属性设置为relative,则不会出现滚动条。

          【讨论】:

            猜你喜欢
            • 2011-09-13
            • 2014-01-25
            • 2023-01-19
            • 2023-03-03
            • 2012-04-05
            • 1970-01-01
            • 2013-03-29
            • 2017-03-02
            • 1970-01-01
            相关资源
            最近更新 更多