【问题标题】:CSS grid/layout framework with focus on fixed elements and single page full screen layoutsCSS 网格/布局框架,专注于固定元素和单页全屏布局
【发布时间】:2013-07-30 07:37:07
【问题描述】:

经验法则 - 如果您在布局中过多地使用 CSS,请切换到框架。我已经研究了几十个网格/布局框架,其中大部分都专注于传统的文档网格布局。

我的页面更像是一个 SPA(单页应用程序)。它类似于桌面应用程序使用的布局。显然 HTML 不能很好地处理这个问题,需要大量的 CSS 修补。

这是我尝试实现的布局示例(应该填满整个屏幕):

请注意,固定菜单不应悬停在其后面的滚动内容上。每个块应该驻留在自己单独的“框架”中 - 即左侧长列表的滚动条应该出现在固定菜单下方。

我还没有找到一个支持这个的轻量级网格框架(像 Sencha 或 Kendo UI 这样的框架有点矫枉过正)。手动完成 CSS 非常费力。特别是如果我决定显示一个模式对话框,并且需要在此对话框内进行类似的布局(顺便说一句,这最终杀死了我)。或者,如果我决定要在底部设置另一个固定菜单,那么一切都会崩溃。

我什至不确定这是否仅适用于 CSS(我知道至少固定底部菜单需要 CSS 中的一些硬编码值才能缩小其后面的内容,以免滚动条重叠)。如果需要 JS 解决方案,并且我希望它能够处理浏览器屏幕大小调整事件 - 再一次崩溃,因为没有简单的常见事件可以做到这一点。

我应该如何以可维护/灵活的方式解决这个问题?

评论:您会注意到,我自己添加了一个答案,建议使用 HTML 表格实现此布局。我真的不想接受我自己的答案。我有一种感觉,没有人会足够“勇敢”地推荐表格(毕竟这是有争议的),我愿意为了讨论而遭受反对票

澄清:似乎我说的可维护性和灵活性不够清楚。我的意思是让布局优雅地处理各种场景或需要的修改(即代表我做的工作很少)。为了绝对具体,让我们举一些例子:

  1. 布局不应该介意它是显示为整页还是在固定模式对话框(即引导对话框)中显示。在这些场景之间切换应该尽可能少地改变布局代码。

  2. 布局应支持多种描述宽度和高度的方式(即侧边栏的宽度或顶部菜单的高度)。更具体地说,应支持以下大小调整方法:

    • 精确的固定像素大小。
    • 通过使用容器的百分比来确定相对大小。例如:侧边栏宽度是整个容器(整页或对话框)宽度的 30%。另一个例子:顶部菜单高度是整个容器(整页或对话框)高度的 20%。
    • 环绕它自己的内容。示例:顶部菜单的高度将取决于其中的内容。如果您输入一行文本,它将在不滚动的情况下换行。如果您输入两行文本,它将是原来的两倍,并且按住它们而不滚动。
    • 奖励:两者的简单组合。比如侧边栏宽度为 20% 但不少于 50 像素。

正如 Ian Clark 最专业地指出的那样,CSS 可以开箱即用地实现大部分这些请求。对此没有任何争论。问题仍然存在,如果原始 CSS 是最简单的使用,是否有任何东西可以通过框架/另一种机制(如 flexbox/tables)从开发人员那里卸载。

【问题讨论】:

  • 使用固定布局创建动态网格确实很难实现。页面会不断变化,还是一旦发布就完成布局?
  • 布局是相当稳定的——它在运行时不会改变。问题是我有几个布局相似的屏幕,并且为每种情况进行所有手动计算和 CSS 技巧感觉就像是在浪费时间
  • 哦,我明白了。我想说如果它只有一页,花时间弄清楚你需要的所有东西,写下它的列表,然后用固定的布局构建你的页面,这样你只需要做一次......但是如果您有多种变体,是的,希望您能找到替代方案。祝你好运!
  • 您是要求一个库来处理一般的布局,还是尝试创建这个特定的布局?如果是前者,那么这个问题就离题了。
  • 我特别想问如何实现这个布局,但添加了一个要求,它需要通过库而不是手动完成。我正在寻找一个可维护的解决方案,而不仅仅是一些肮脏的东西

标签: html css layout frameworks single-page-application


【解决方案1】:

更新 2(这个问题似乎在演变!):

标准 1 - 在整页或内部模式之间切换应尽可能少地更改代码

因为在这种情况下,body 的宽度/高度始终是 window 宽度/高度的 100%,如果您希望您的代码轻松适应模态等,您始终可以使用 position:absolute ,因为没有任何上下文,这将与body 相关。

标准 2 - 布局应支持多种描述宽度和高度的方式

Here's a JSFiddle that can do almost everything you mention。它在固定元素上使用百分比和固定像素宽度。首先要注意的是,我必须做的唯一更改是在我们的每个元素中添加一个box-sizing:border-box。与 flexbox 不同,this has good support 回到 IE8,因此不会引起任何问题。添加它允许我们为元素添加填充,而无需更改宽度来进行补偿。

虽然左侧边栏的宽度为 20%,但它们的最小宽度也为 100 像素。为了防止与右边的主要内容重叠,我们使用一些简单的逻辑来建立逆:

Reaches Min At = Min-width / Width * 100

在我们的示例中,我们的左侧边栏因此在100/20*100 = 500px 处达到一个最小值。然后当我们达到这个窗口大小时,我们使用@media 选择器来改变我们主要内容的宽度:

@media(max-width:500px) {
  #scrolling-content { 
    left:100px;
  }
}

通过更改小提琴上的窗口大小,您会注意到当您达到最小大小时,我们的主要内容区域会改变颜色。现在我承认,这可能看起来令人困惑,但同样,通过使用诸如 Less 之类的语言,您可以轻松地将 widthmin-widths 设置为变量,并使用一个简单的函数来更改您的 CSS。现在我使用“几乎所有东西”这个短语的原因是,如果你想在模态中做类似的事情,这可能会变得更加复杂,但谁知道呢,这可能是可能的!

需要注意的一点:如果您打算使用 JavaScript 来获取调整大小事件,请务必考虑使用 jQuery debounced resize plugin,因为您不想进行比您需要的数百倍的计算! 我将在这个答案中留下额外的内容,因为大多数内容仍然与您的发展中的问题相关并且在历史上是准确的


更新:有很多答案建议使用 Flexbox,但我真的不认为这是一个很好的解决方案。不要误会我的意思,如果 FlexBox 是一个真正可行的解决方案,我会喜欢它,但现在 Support for them is terrible,如果你要 polyfill那么对于大多数网络来说,你还不如使用任何其他 JavaScript 解决方案,我认为 JavaScript 不是用于整个页面呈现的正确工具。

仍然不明白为什么使用简单的 CSS positions 很难实现您的目标。您不需要使用任何 JavaScript 和。我认为它非常易于管理的。如果你真的在维护你的样式表时遇到了困难,那么为什么不使用像 Sass/SCSSLess 这样的东西,因为你可以创建变量、mixin、函数等.,并显着减少您需要进行的更改次数。


也就是说,he's a really quick mockup of your solution,只使用纯 CSS 和 HTML。我使用的是 4 个固定的divs,并且可以进行简单的修改,以便“滚动内容”不固定,而只是使用边距来正确定位。那将有额外的好处,不必在 div 内滚动,但可以对着 body 滚动。

所有必需的 CSS:

div { position:fixed; }
#top {
    top:0;
    left:0;
    right:0;
    height:40px;
}

#menu {
    top:40px;
    height:40px;
    left:0;
    width:200px;
}

#long-list {
    top:80px;
    left:0;
    width:200px;
    bottom:0;
    overflow-y:auto;
}
#scrolling-content {
    top:40px;
    bottom:0;
    right:0;
    left:200px;
    overflow-y:auto;
}

很容易注意到40px200px 的重复作为菜单的高度和宽度。考虑到这一点,您可以简单地使用动态语言的变量并只定义一次(较少示例):

@leftwidth: 200px;

#scrolling-content {
    left:@leftwidth;
}
#menu, #longlist {
    width:@leftwidth;
}

争议 #1:框架不灵活或不易编辑

您提到很难轻松操作 CSS 框架,因为依赖于静态内容,他们必须决定要使用的列数(在 Bootstrap 和许多其他情况下,他们选择 12,因为它很容易被 1,2 整除,3,4,6)。 然而,在 Bootstrap 2 中,customise the number of columns 非常容易。预计当 Bootstrap 3 RC2 出现时,此功能也会存在。还有许多资源允许您使用Less with Bootstrap。也就是说,创建一个 Less 风格的灵活流体网格系统,see demo 将是相当常规的(免责声明:我没有使用 Less 的经验,this article helped me with looping):

/* The total number of columns you wish to use */
@columns: 15;
/* 
    We loop through and for each create class
   .dynamic-<index>-<columns> 
*/
 .looping (@index) when (@index > 0) {
    (~".dynamic-@{index}-@{columns}") {
        width: percentage(@index/@columns);
    }
    .looping(@index - 1);
}
/* Stop and do nothing at 0 */
.looping (0) {}
/* Call our function */
.looping (@columns);

然后你的 HTML 标记就变成了:

<div class="cf rows">
    <div class="dynamic-4-15">4/15th width</div>
    <div class="dynamic-7-15">7/15th width</div>
</div>

争议 #2:基于百分比的模态很难使用 CSS

在您提到的 cmets 中,您“希望布局相对于对话框宽度,而不是浏览器窗口宽度”。那么这当然也是可能的。其实很简单,and requires almost no change to our code

#some-modal {
   position:fixed;
   top:10%;
   bottom:10%;
   left:10%;
   right:10%;
}
/* Before this was simply div, and it was fixed, now it's absolute */
#some-modal div {
   position:absolute;
   padding:10px;
}

【讨论】:

  • 这个 CSS 的问题在于它非常不灵活。许多网格框架提供相对于整个屏幕的宽度(如 n/12 列)。另一个问题是在不同的屏幕上显示具有不同大小的模态对话框,并且在对话框中具有此布局。任何你不能使用精确像素大小的地方都会中断..
  • 另一个问题是希望菜单 div 足够大以容纳其内容。这意味着如果用户有不同的基本字体大小,例如,它会相应地增长或缩小。就像一个不固定的 div 会根据里面的内容改变它的高度。
  • 我不认为这些是 CSS 的问题,CSS 只是样式 HTML,你不能使用其他任何东西
  • 虽然我不太明白你的问题,但我认为 Ian 回答正确。
  • 嗯,伊恩,你的努力得了 A,这点毫无疑问。总体而言,flexbox 对我来说仍然是最好的解决方案。这是我们要去的地方,我愿意在我们到达那里之前进行 polyfill ;)
【解决方案2】:

我不知道为什么你的回答被否决了。每个人似乎都同意“不需要专门的框架”至少是一个好的答案的一部分。使用表格当然有缺点,但你似乎意识到了这一点,列出缺点在我看来是一个非常一致的答案。

尽管考虑了您的回答,我还是会使用 Flexbox 模型。它似乎更合适(@cimmanon 在另一个答案中很好地提出),语义甚至比表格更容易维护。此外,使用最新的技术可能会延长您的应用程序的生命周期。如果您担心向后兼容性,请查看这个库 - http://flexiejs.com/

您还可以使用其他元素和 css 表格模型来模拟表格的行为,例如:&lt;div style="display:table"&gt;。以这个小提琴为例 - http://jsfiddle.net/JWqVQ/

这里有更多关于不同渲染选项的信息 - https://developer.mozilla.org/en-US/docs/Web/CSS/display

【讨论】:

  • 我真的不想接受我自己的答案。我有一种感觉,没有人会“勇敢”地建议他们(毕竟这是有争议的),我愿意为了讨论而遭受反对票:)你的答案目前是我眼中最好的答案,谢谢。跨度>
【解决方案3】:

您可以使用直接、最少的 CSS 来做到这一点并且完全灵活(用户更改字体大小或您的内容长度未知?没问题)。

http://codepen.io/cimmanon/pen/vusmz

假设这个标记:

<header>Header</header>

<div class="container">
  <div class="sidebar">
    <aside>Menu (fixed)</aside>
    <nav>long list</nav>
  </div>
  <main>
    <p>...</p>
  </main>
</div>

CSS:

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

body {
  display: -ms-flexbox;
  display: -webkit-flex;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
}
@supports (flex-wrap: wrap) {
  body {
    display: flex;
  }
}

.container {
  display: -ms-flexbox;
  display: -webkit-flex;
  -webkit-flex-flow: column wrap;
  -ms-flex-flow: column wrap;
  flex-flow: column wrap;
  -webkit-flex: 1;
  -ms-flex: 1;
  flex: 1;
}
@supports (flex-wrap: wrap) {
  .container {
    display: flex;
  }
}

.sidebar {
  display: -ms-flexbox;
  display: -webkit-flex;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  -webkit-flex: 1 100%;
  -ms-flex: 1 100%;
  flex: 1 100%;
}
@supports (flex-wrap: wrap) {
  .sidebar {
    display: flex;
  }
}

header {
  background: yellow;
  height: 3em; /* optional */
}

aside {
  background: green;
  height: 4em; /* optional */
}

nav {
  background: orange;
  -webkit-flex: 1;
  -ms-flex: 1;
  flex: 1;
  overflow-y: scroll;
  height: 1px;
}

main {
  background: grey;
  -webkit-flex: 1;
  -ms-flex: 1;
  flex: 1;
  overflow-y: scroll;
  height: 1px;
}

由于需要flex-wrap: wrap 支持,浏览器支持受到限制(IE10 是唯一支持它的“部分支持”浏览器:http://caniuse.com/#feat=flexbox)。当前浏览器支持仅限于 Chrome、Opera、IE10 和 Blackberry 10。

请注意,滚动元素的高度非常小,这可能会导致缺乏完全 Flexbox 支持的浏览器出现问题(请参阅:Flexbox and vertical scroll in a full-height app using NEWER flexbox api 了解更多信息)。

【讨论】:

  • 我同意 flexbox 很好地解决了这个问题。不幸的是,我很确定我不能使用它,因为缺乏对 IE9 的支持以及在许多其他(FF、Safari)中的部分支持
【解决方案4】:

在一些项目中,我借助这样的代码(在 FF 上测试):

<style>
#topMenu {
    position: fixed;
    left: 0px;
    top: 0px;
    width: 100%;
    height: 100px;
}
#sidePanel {
    position: fixed;
    left: 0px;
    top: 100px;    
    width: 100px;
}
#sideMenu {
    width: 100%;
    height: 50px;
}
#sideList {
    border-width: 0px;
    width: 100%;
    padding: 0px;
    margin: 0px;
    background-color: #FFF0F0;
}
#content {
    border-width: 0px;
    padding: 0px;
    margin: 0px;
    background-color: #F0FFF0;
}
body {
    border-width: 0px;
    padding: 100px 0px 0px 100px;
    margin: 0px;
}
</style>

<div id="topMenu">Top menu</div>
<div id="sidePanel">
    <div id="sideMenu">Size menu</div>
    <iframe id="sideList"></iframe>
</div>    
<iframe id="content"></iframe>

<script>
function onResize() {

    var sizePanel = document.getElementById("sidePanel");
    sizePanel.style.height = (document.documentElement.clientHeight - 100) + "px";   
    document.getElementById("sideList").style.height = (sizePanel.clientHeight - 50) + "px";   

    var content = document.getElementById("content");
    content.style.width = (document.documentElement.clientWidth - 100 - 10) + "px";
    content.style.height = (document.documentElement.clientHeight - 100 - 10) + "px";
}

window.addEventListener("resize", onResize);
onResize();

</script>

【讨论】:

  • 谢谢,我有类似的东西,但这是我试图避免的。所有这些手动工作既费时又不灵活(一个小的更改需要完全重写)。我希望一些框架能在幕后为我处理所有这些(就像大多数网格框架一样)。
  • 另外,resize 事件在不同的浏览器中是非常有问题的。我已经看到人们使用定期计时器检查更改的窗口大小来解决这个问题 - 现在这真的很恶心:)
  • 是的,我同意这段代码可能过于粗糙,不适合作为稳定的跨浏览器解决方案。
【解决方案5】:

我认为您不需要使用框架,尤其是在您不熟悉它们并且遇到问题的情况下。如果您只是将不同的视图设置为溢出:滚动,您应该也可以创建您在该图像中描述的内容。您可以做的另一件事是为每个视图设置一个 iframe,就像 Javadocs 所做的那样。

【讨论】:

    【解决方案6】:

    作为记录,我认为 Ian 在这里给出了迄今为止最完整和最准确的答案,对于纯 CSS 答案,这将非常有效。但是,您还想知道您有哪些选择,我至少必须提供另一种选择,以便您知道它是可用的:

    我挑战你的前提,即 Javascript 不能做你想做的事。在我看来,JQuery 是一个真正革命性的 Javascript 库,并且极大地简化了它。根据维基百科,Jquery“被 10,000 个访问量最大的网站中的 65% 以上使用”。从个人经验来看,尝试在我的网站上使用纯 CSS 对我来说很失败。使用 JQuery 给了我更多的灵活性和对 CSS 的控制,不再强迫我使用相对值。我是个控制狂,所以这对我有用。

    JQuery 非常容易学习,并且允许使用 Javascript 处理程序和事件来补充 CSS 的浏览器事件。例如,如果您想在刷新时更改 CSS:

    $(document).ready(function() {
        $(window).resize(function() {
             var windowWidth = $(window).width();
             $('#div').css('width',windowWidth-100); //the # references id, like in CSS
        });
    });
    

    在我的 JSFiddle 上查看更详细的示例

    如果 JQuery 听起来是让您的 CSS 在任何场合都动态和灵活的正确途径,那么这里有几个教程。如果您了解 CSS 和 Javascript,用不了多久,它就会像魅力一样工作。即使你不懂 Javascript,你也可以用 JQuery 做很多事情。只需一点学习曲线,您肯定会找到什么。

    【讨论】:

      【解决方案7】:

      “有几十个网格/布局框架,其中大部分专注于 传统的文档网格布局。”

      你让它听起来像是一件坏事。我不明白你为什么不使用网格框架。如果您有任何意图使您的应用程序平板电脑和移动设备友好,这是相当标准的做法。它们中的大多数设置起来都非常快,几乎不需要额外的 CSS。

      kube 为例。它非常简约和灵活。 您基本上只需将预定义的类添加到您希望应用为大小的 div 标签。

      <div class="units-row">
          <div class="unit-30"></div>
          <div class="unit-70"></div>
      </div>
      

      这种类型的步骤不会与 modals 或 iframe 混淆。要修改所有你需要做的就是改变类..需要一个更大的左侧,只需改变 div 的类

      <div class="units-row">
          <div class="unit-80"></div>
          <div class="unit-20"></div>
      </div>
      

      这将在较小的分辨率下优雅地降级,同时保持您的编码风格,就像在任何其他应用程序中一样。

      如果你愿意,你可以从头开始写,但是.. 为什么?

      foundation 也非常好,是我用于项目的那个

      【讨论】:

        【解决方案8】:

        您可能想查看Cascade Framework 并使用this template 作为布局的起点。

        【讨论】:

          【解决方案9】:

          披露:我是 OP,我正在抛出一个想法以获得普遍的回应。

          不需要专门的框架,因为您可以使用 TABLES

          是的,我说的是&lt;table&gt;&lt;tr&gt;&lt;td&gt;这一广为人知的布局区域。众所周知,布局时应避免使用表格。我试图回顾一下这里提到的原因:Why not use tables for layout in HTML?

          在我看来,在这种情况下大多数原因都无效(SPA):

          内容与布局的分离 - 由于 SPA 并不是真正的内容(它只是一个带有 AJAX 填充数据的骨架),因此此论点不适用。这只是一个界面,我不希望谷歌索引它。

          表格不易维护 - 在这种情况下不是。使用 div 实现这一点所必须经历的 CSS 地狱可维护性要差得多。

          表格的渲染速度较慢 - 当然,但我们想要一个需要更多计算才能渲染的复杂布局。哎呀,我们通常用 JS 调整大小事件来补偿。浏览器在渲染引擎中本地执行此操作会非常有效。

          【讨论】:

          • 答案是为了答案。如果您需要提供更多信息,请更新您的问题。
          • @talkol 您可以编辑原始问题并添加此信息。请不要将为答案提供的空间用于答案以外的任何内容
          • 这实际上是我的一位同事提出的答案。我的第一反应是关闭它,因为表不不不,但我想不出很多反对它的事实原因。如果您不赞成,请解释
          • 建议避免使用我最初想要的框架,因为像 flexbox 或表格这样的原生布局机制已经足够好是一个有效的建议
          • 但这并没有回答这个问题,甚至没有尝试回答这个问题。它读起来是一个很长的评论,这不是答案的目的。表具有特定的语义含义。将其用于呈现表格数据以外的任何事情都是不正确的。
          猜你喜欢
          • 2021-05-19
          • 2013-03-27
          • 2013-08-30
          • 1970-01-01
          • 2011-12-24
          • 1970-01-01
          • 1970-01-01
          • 2015-07-28
          • 1970-01-01
          相关资源
          最近更新 更多