计算保证金百分比差异与宽度

时间:2016-09-29 13:42:45

标签: javascript html css

我已经就百分比如何影响保证金这一主题进行了大量研究(including this question),但我还没有计算出正确的算法来计算额外的高度/宽度增加到保证金。

As taken from w3c:

  

百分比是根据生成的框的包含块的宽度计算的。请注意,对于“margin-top”和“margin-bottom”也是如此。如果包含块的宽度取决于此元素,则在CSS 2.1中未定义结果布局。

因此,如果这是真的,则以下算法应该起作用:

width of container = w_c
decided margin = m
x = ((w_c/100)*m) +- unknown

Take the given codepen example.

左边两个div的高度为42.5%,边缘底部为5%。因此理论上它应该等于90%并且与右div匹配相同的高度。但事实并非如此。

我确信这可以计算,因为following codepen worksmargin-bottom: 5vh;而不是5%。我希望这与%而不是vh一起使用。

所以我的问题是,算法是什么算法的margin-bottom来计算精确的余量,使得两个div的左边,边距底部,加起来为90%并且匹配右边的div?

2 个答案:

答案 0 :(得分:2)

我一直在与作者交谈,并且在学习(并确信)css margin-top和margin-bottom确实不是基于div的高度时,我发现自己对这个事实感到恼火,并决定写点什么。我希望它可以帮助任何有类似问题的人!

基本上,它在文档中搜索属性“vertMargin”设置为true的元素标记。如果找到一个,它会创建一个函数原型,其中包含3个变量的范围...两个用于初始内联边距设置,另一个用作回调,然后将此原型添加到数组中。调整窗口大小后,它会遍历此数组以运行存储的回调,并适当调整div的边距。

无论如何,我的解决方案。

使用以下代码制作脚本文件。

var addMarginBottom = function(target){
    var parentDiv = target.parentNode;
    var parentRect = parentDiv.getBoundingClientRect();
    var parentHeight = parentRect.bottom - parentRect.top;
    var height_1Pc = parentHeight/100;
    target.style.marginBottom = height_1Pc*target.bottom_pc+"px";
};

var addMarginTop = function(target){
    var parentDiv = target.parentNode;
    var parentRect = parentDiv.getBoundingClientRect();
    var parentHeight = parentRect.bottom - parentRect.top;
    var height_1Pc = parentHeight/100;
    target.style.marginTop = height_1Pc*target.top_pc+"px";
};

var NODE_REF = [];

var nodeRef = function(){
    var update;
    var top_pc;
    var bottom_pc;
}

var realHeightMarginInit = function(target){
    var children = target.childNodes;
    for(var x = 0; x < children.length; x++){
        var child = children[x];
        if(child.nodeType == 1){ //is an elemental node..
            if(child.hasAttribute("rel-margin")){
                var nodeRef = child;
                var nodeStyle = window.getComputedStyle(nodeRef);
                var parentStyle = window.getComputedStyle(target);
                var num = parseFloat(nodeStyle.marginTop);
                var dom = parseFloat(parentStyle.width);
                nodeRef.top_pc = (num/dom)*100;
                num = parseFloat(nodeStyle.marginBottom);
                nodeRef.bottom_pc = (num/dom)*100;
                nodeRef.update = function(){
                    addMarginTop(nodeRef)
                    addMarginBottom(nodeRef);
                };
                NODE_REF.push(nodeRef);
            }
            realHeightMarginInit(child);
        }   
    }
}

在HTML文件中,将这些内容添加到一些脚本标记中......

window.addEventListener("resize", function(){
    for(var x = 0; x < NODE_REF.length; x++){
        NODE_REF[x].update();
    }
});

window.addEventListener("load", function(){
    realHeightMarginInit(document);
    for(var x = 0; x < NODE_REF.length; x++){
        NODE_REF[x].update();
    }
});

现在,您可以为margin-top和margin-bottom添加内联样式以实现您正在寻找的行为:)只需添加属性vertMargin =“true”,它将按预期工作。

<div rel-margin id="your-top-left-div">
    Hello!
</div>

然而,这可能不是你最好的选择(它也是一团糟)!您可以使用大量工具和技术来避免此问题,例如使用像bootstrap这样的CSS框架,并且90%的时候,重构CSS和HTML可能是最简单,最容易实现的。当然,有时基于js的解决方案可能就是您所需要的。

编辑:更新了代码,以便样式现在可以成为样式表的一部分而不是内联。

(已更新)Example of usage with OP's code.

答案 1 :(得分:1)

虽然保证金确实取决于宽度而可以计算,但在很多地方设置了百分比高度--- html,{{ 1}},body#Left ....

在这种情况下,百分比边距不会总是加起来,因为百分比高度包含在内。即使这样,在窗口调整大小时也会失败

这意味着,虽然

#Right

看似添加到42.5% + 42.5% + 5% 它不会。只是因为90%基于宽度---而其他两个是高度值。包含块越宽,5%的值越大。

据我所知,在这种情况下只有CSS才有可能。虽然可能更好地使用 5% 单位,但请记住它在其他地方(html,正文,列)设置viewport cos的cos值。如果要更改分配给其中一个的高度属性,则还必须更改边距。并且计算这不像height: 100%那么容易。

通过JavaScript的一种方法是使用列之间的高度差和窗口调整大小事件来计算像素值中所需的间隔。请记住获取实际浮动值以最好地避免子像素问题。我的JS有点生疏,但希望可以按照合适的方式重新设计。

https://jsfiddle.net/j0565smf/

5vh
function setMargin() {
  // get them all
  var look = document.getElementsByClassName('Look'),
  // 42.5% + 42.5%
  leftHeight = look[0].getBoundingClientRect().height * 2,
  // height of red div
  rightHeight = look[2].getBoundingClientRect().height,
 
  // separation needed
  separation = rightHeight - leftHeight;

  // set this on the first blue box
  look[0].style.marginBottom = separation + "px";
}
setMargin();
window.addEventListener('resize', function(){
 setMargin()
}, true);
*,html,body {height: 100%;padding: 0; margin: 0;}
#Ticket     {width: 100%;height: 100%;float: left;}
#Left       {width: 40%;height: 100%;float: left;}
#Right      {width: 60%;height: 100%;float: left;}

.Look       {float: left;width: 100%;height: 100%;}
.test1      {background-color: blue;height: 42.5%;}
.test2      {background-color: red;height: 90%;}