1

我在布局具有非常严格的布局要求的电子商务页面时遇到了问题。我们希望在产品描述旁边显示产品图片,并在图片下方显示一些关于产品的可选额外信息。宽度受我们整个页面布局的限制,而高度可以是可变的。答案似乎是“你不能用纯 CSS 做到这一点”。

这是一个模拟: 设计模型

标记的宽度为 372+12+178=562,边框留出 8px。图片和描述区域有2px的边框,总共有8px的水平像素,562+8=570。

我已经对图像的垂直居中进行了大部分排序,破坏设计的是可选的“额外信息”面板。该站点是由 PHP 生成的,<div>如果数据可用于产品,PHP 可以选择性地包含该额外信息。如果它有助于解决设计问题,我很乐意始终包含“额外信息”元素并将其设置为不可见,如果它为空的话。

要求:

  • 产品图像可以是任何纵横比。有的又瘦又高,有的又宽又短,有的方形。
  • 产品图像应水平填充其区域,并按其纵横比自然垂直调整大小。
  • 产品图像应在其区域(蓝色)中垂直居中。当额外信息不可见时,图像将在描述区域旁边垂直居中。当额外信息可见时,图像应在剩余空间中垂直居中。
  • 额外信息可以是任意数量的文本,并与产品图像区域的底部对齐。所以,不能有固定的高度。
  • 产品描述可以是任意数量的文本。
  • “图像和额外信息”列应垂直匹配“描述”列的大小,反之亦然。
  • 描述和额外信息框使用 CSS 渐变背景和边框。所有这些 div 都必须相应地调整自己的大小,我无法摆脱这里描述的“人造列” http://www.alistapart.com/articles/fauxcolumns/
  • 不想使用 Javascript 来对齐元素。是的,我确信我们都是 jQuery 大师,它是一个很棒的工具,但这种布局不应该是必需的。

到目前为止,我的设计使用纯 CSS 并且没有表格,使用表格单元格样式来居中图像,但是当使用不同大小的图像时,最小高度会中断。一个jsfiddle:http: //jsfiddle.net/GJVbX/

通过将产品描述文本内容增加三倍或添加“宽度:370 像素;高度:400 像素;”很容易破坏该小提琴。所以它不是一个很好的高度。

我设计的一个很好的例子:

现场运行良好的屏幕截图

但是,不难找到破坏它的图像大小:

现场破解截图

请注意高大的产品图像如何使图像 div 垂直扩展并且描述列无法跟上。

我一直在 Freenode 上的#css IRC 频道上,并被告知使用纯 CSS 可以实现这一点,使用表格来完成此布局任务表明我不了解 CSS 布局,应该聘请专业人士,以实现垂直居中我应该使用“显示:表格单元格”。然而,尽管他们非常有帮助,但讨论过于复杂,无法在 IRC 上继续。我知道这<table>会带来各种可怕的布局机制,这些机制只是为了准确的页面布局而被破坏,但是,我想不出更好的解决方案,主要是因为我要求保持列的高度相同。

希望有建设性的批评,替代解决方案,甚至只是确认我的困境:)

编辑- 这是上面给出的 jsfiddle 中的 HTML 和 CSS 内容,适合那些喜欢包含在 stackoverflow 问题中的内容的人。这是从实时站点中提取的,稍微清理一下缩进,带有虚拟产品图像(由实时站点中使用的缩略图脚本生成)和虚拟文本。

HTML:

<div class="productInfo">
  <div class="productTopWrapper">
    <div class="productImgWrapper"><div class="wraptocenter"><span></span><img src="http://nickfenwick.com/hood.jpg"></div></div><div class="extraInfoWrapper gradientBackground"><div class="extraInfoInner">Extra info goes here.</div>
      </div>
      <div class="productDescription gradientBackground"><div class="productDescriptionInner">
          Product Description goes here.<br/>
          Product Description goes here.<br/>
          Product Description goes here.<br/>
          Product Description goes here.<br/>
          Product Description goes here.<br/>
          Yet the gradient ends too soon because this div doesn't fill its space vertically!
          </div>
      </div>
    </div>
</div>

CSS:

DIV.productInfo {
    max-width: 570px;
    font-family: Verdana,Geneva,'DejaVu Sans',sans-serif;
    font-size: 12px; /* Just for this fiddle */
}
.productInfo .productTopWrapper {
    overflow: hidden;
    margin-bottom: 12px;
    position: relative;
}
.productInfo .productImgWrapper {
    width: 372px;
    min-height: 353px;
    float: left;
    border: 2px solid #cbcbcb;
    text-align: center;
}

/* BEGIN css wrap from http://www.brunildo.org/test/img_center.html */
.wraptocenter {
    display: table-cell;
    text-align: center;
    vertical-align: middle;
    width: 372px;
    height: 309px;
}
.wraptocenter * {
    vertical-align: middle;
}
/*\*//*/
.wraptocenter {
    display: block;
}
.wraptocenter span {
    display: inline-block;
    height: 100%;
    width: 1px;
}
/**/
*:first-child+html {} * html .wraptocenter span {
    display: inline-block;
    height: 100%;
}

/* END css wrap */

.productInfo .extraInfoWrapper {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 376px;
}
.productInfo .extraInfoInner {
    padding: 5px;
    border: 2px solid #cbcbcb;
    text-align: center;
}

.productInfo .gradientBackground {
    background: #999; /* for non-css3 browsers */

    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d0d1d3', endColorstr='#fefefe'); /* for IE */
    background: -webkit-gradient(linear, left top, left bottom, from(#d0d1d3), to(#fefefe)); /* for webkit browsers */
    background: -moz-linear-gradient(top, #d0d1d3,  #fefefe); /* for firefox 3.6+ */
    background: -ms-repeating-linear-gradient(top, #d0d1d3,  #fefefe);
    background: repeating-linear-gradient(top, #d0d1d3,  #fefefe);
}.productInfo .productDescription {
    width: 178px;
    min-height: 353px;
    margin-left: 388px;

    border: 2px solid #cbcbcb;
}
.productInfo .productDescriptionInner {
    padding: 5px;
    font-size: 1.2em;
    line-height: 1.2em;
}
4

3 回答 3

1

您可以使用带负边距的高高度来执行此操作。(您的高度减去您的 div 的最小高度,在这种情况下为 353px)唯一的问题是边框底部将消失在父级的溢出中(应该保持隐藏)。不确定边界对您有多重要,或者即使那是您正在寻找的东西,但也许它可能会为您指明正确的方向?

.productInfo .productDescription {
    width: 178px;
    min-height: 353px;
    margin-left: 388px;
    border: 2px solid #cbcbcb;
    height: 1000px;
    margin-bottom: -647px;
}
于 2012-09-13T00:01:39.897 回答
1

不幸的是,您需要支持哪些版本的 IE 不仅仅影响 CSS3。display: table-cell,例如,在 IE7 中不可用。其他浏览器中存在的无数其他东西在 IE7 和 IE8 中丢失或存在错误。然而,IE9 是一个相当大的改进。

老实说,即使您将自己限制在所有浏览器的最新版本中,这种布局在纯 CSS 中仍然很困难,无论 IRC 上的人可能会说什么。当新的布局管理器(如灵活框和网格布局)无处不在时,这将很容易,但恐怕我们还需要几年的时间。

无论如何,这是我对您所需布局的尝试:

http://jsfiddle.net/amtiskaw/tNywn/

它需要 IE8 及更高版本,因为它用于display: table-cell垂直居中产品图像。它还有一个怪癖,即额外信息框的内容永远不会与产品信息框的内容垂直重叠,尽管它们的边框看起来是正确的。

拉伸的边框和渐变是通过使用附加元素来实现的,这些元素的大小使用绝对定位垂直填充产品容器元素,然后使用负 z-index 放置在内容后面。

就个人而言,在这种情况下,我更倾向于使用表格或一些 jQuery 来获得正确的大小,而不是这种 CSS hackery。如果您使用表格,您可以给它一个属性role="presentation",以向屏幕阅读器和其他语义工具指示它正在用于布局目的,而不是表达表格数据。这种模式得到了 W3C 的认可

于 2012-09-13T02:26:32.330 回答
0

我记得前段时间遇到过这个问题,最后求助于 JS 来解决它。不幸的是,您的限制使得很难用纯 CSS 提出一个工作示例。我看到的问题是,一旦图像大小增加,包含的 div 不再具有特定的宽度或高度,并且仅使用 CSS 就无法进行将描述 div 扩展到正确高度所需的计算。如果大小发生变化的元素不是直接父元素,浏览器不会自动执行此操作,从而将父元素的子元素留在高度/宽度更改前的高度。

是的,表格将解决固定行高的问题,但正如你所说,它们的价格是我尽量避免的。

我假设您已经考虑使用 JS / Jquery 来解决这个问题。

jQuery 示例

$(function()
{
    var height = $('.productImgWrapper').innerHeight();

    $('.productDescription').css('height', height);
});

请注意,这.innerHeight()包括填充,但不包括边框或边距。包括边框使用.outerHeight()

我知道这并不理想,但我看不出有任何其他方法可以解决您的问题。也许有比我更强大的 CSS 能力的人想出一个解决方案。

于 2012-09-12T07:31:43.590 回答