我能翻译这个问题:在HTML5中是否可以设置制表位?

19

我想在HTML5中设置制表位,并能够像在Word中一样将文本对齐到它们上面。由于我的应用程序不能使用表格,因此是否有方法可以做到这一点?我是否必须使用Javascript?


你所说的“制表位(tab stops)”是什么意思?你是否期望基于制表符(ASCII 9)发生某些事情? - John Saunders
我的意思是在某个元素(例如div)内,我想说“制表位在1英寸、2英寸、4英寸等处”。然后我想有一种方式,可能不是制表符,而是文本流中的某些东西,来表示“在当前水平位置之后前进到下一个制表位”。这在文字处理中非常常见,MS Word从第一天起就有它。在关于如何在html中实现此操作的讨论中,我看到的只有“使用表格”,但这对我的情况不起作用。 - Wayne Christopher
HTML不是一个文字处理格式,而是一个演示格式。 - John Saunders
@WayneChristopher:你可以使用position: absolute来实现,但是溢出会带来很多麻烦。 - SLaks
2
2016年,主流浏览器确实支持在具有white-space:pre属性的元素中使用制表符。请参见fiddle。但是,对于tab-size属性的支持仍然不稳定。 - Mr Lister
显示剩余2条评论
7个回答

18

尽管其他帖子的作者声称相反,但有合理的原因想要做OP所问的事情,而且使用现代CSS有许多方法可以实现它(在我撰写本文时,还有更多草案规范正在进行中)。这里只列出一种方式。

<!DOCTYPE HTML>
<html>
 <head>
  <title>Tabs with css</title>
  <style>
  {body: font-family: arial;}
  div.row span{position: absolute;}
  div.row span:nth-child(1){left: 0px;}
  div.row span:nth-child(2){left: 250px;}
  div.row span:nth-child(3){left: 500px;}
  </style>
 </head>
 <body>
  <div class="row"><span>first row data before first tab</span><span>data left aligned with first tab</span><span>data aligned with second tab</span></div><br>
  <div class="row"><span>second row data before first tab</span><span>data left aligned with first tab</span><span>data aligned with second tab</span></div><br>
  <div class="row"><span>third row data before first tab</span><span>data left aligned with first tab</span><span>data aligned with second tab</span></div><br>
  <div class="row"><span>fourth row data before first tab</span><span>data left aligned with first tab</span><span>data aligned with second tab</span></div><br>
  <div class="row"><span>fifth row data before first tab</span><span>data left aligned with first tab</span><span>data aligned with second tab</span></div><br>
 </body>
</html>

查看样例结果: http://jsfiddle.net/Td285/

另一个例子,带有溢出裁剪: http://jsfiddle.net/KzhP8/


1
这种方法的困难在于容器不会垂直扩展以适应绝对定位的跨度。有没有解决方法? - hertzsprung
2
简短的回答是可以,但其他方法并不是“变通方法”。有很多方法可以做到OP所要求的事情。每种方法都有其优点和缺点。我想告诉读者的是,不要被那些说它无法完成的人吓到。它是可以实现的。我没有花时间记录每种可能的方法来完成它。当我三年前写下这句话时,已经有强大的工具可以按照草案规范所要求的方式进行操作。我相信这些工具现在已经出现在浏览器中了。每个人的需求将导致选择不同的解决方案。 - Ted Cohen
你能够fork我的fiddle,加载一个演示数据,以展示你想要克服的问题并告诉我目标环境吗?如果是企业内部网络,我们知道正在使用哪些浏览器。我可以选择更多的CSS工具,如果它将部署在内部网络上,并且您希望在追溯到netscape 1.0的每个浏览器中工作。我夸大其辞以阐明您想要做什么的额外澄清的需要。 - Ted Cohen
1
@tukusejssirs 我认为示例中使用内联样式标签是因为它们不在样式表(外部)中。如果您使用样式标签或样式表,该技术将起作用。也许您并不是在问样式标签,而是关于每个单独元素的样式属性?当然,您可以这样做,但这正是 OP 想避免的。如果您想要向每个元素添加样式,我建议您提出自己的问题,并记录您想要做什么以及可能的原因。避免这种情况正是这个问题所涉及的。 - Ted Cohen
这也适用于以百分比表示的度量,例如0%,33%,67%,而不是0px,250px,500px。 - Peter Swords
显示剩余2条评论

2

您可以使用CSS属性p {text-indent:50px;}

您可以为每个缩进使用CSS类,如

h1 { text-indent: 10px; }
h2 { text-indent: 14px; }
h3 { text-indent: 18px; }
p { text-indent: 20px; }
p.notice { text-indent: 24px; }

并且按照以下方式编写HTML

<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<p>Text 1</p>
<p class="notice">Text 2</p>

由于使用此属性只能缩进一行,因此支持多行缩进还有另一种方法:
h1 { padding-left: 10px; }
h2 { padding-left: 14px; }
h3 { padding-left: 18px; }
p { padding-left: 20px; }
p.notice { padding-left: 24px; }

最后一个是fiddle


2
谢谢,但您描述的是缩进而不是制表位。请参见http://www.youtube.com/watch?v=vvZxO93MApE。 - Wayne Christopher
HTML中不存在制表位。您必须使用表格(这很糟糕)或使用简单的CSS。如果您愿意,还可以使用英寸来声明“制表位”大小 p { padding-left: 2in; } - Pixelmonster
或者,这只是一个玩笑,你可以像Word一样做。当你使用制表位并将页面导出为html时,它会创建大量的空白来显示类似于制表位的东西。`<p class=MsoNormal>普通</p><p class=MsoNormal>                                                                                                     缩进</p> 你必须接受HTML不像Word那样是一个程序,它没有像Word那样的功能。如果你写文本,标记它并点击加粗,Word会为你做一些像<b>你的文本</b>`的事情。它只是以粗体文本的形式显示,就像在html中的结果一样。 - Pixelmonster
使用空格来模拟制表符的问题在于你需要准确地知道页面上的水平位置,而在生成HTML时,你没有必要的字体度量信息来做到这一点。也许Word有这些信息,所以它可以输出适当数量的nbsp字符...我认为唯一的方法是使用JavaScript在渲染时确定span元素的精确宽度... - Wayne Christopher

1

您可以使用具有相同固定宽度的类将数据分成 <div>。这样,列就会对齐。

<style>
  div.col-1 {
    width: 200px
  }
  div.col-2 {
    width: 500px
  }
</style>

First row is:
<div class="col-1">Some text here </div><div class="col-2">And here </div>
...
Second row is:
<div class="col-1">And here </div><div class="col-2">And here </div>

1
其实,我曾经遇到过类似的情况,而我很简单地解决了它。 在 <p> 属性内使用 <span>,并适当地浮动它。

CSS:

p.main-text { /* these properties don't matter much */    
    margin: 0;    
    text-indent: 0;    
    font-size: 1em;    
    line-height: 1.2;    
    text-align:justify;    
}    
span.column-width { /*this defines the width of the first column */    
    width: 33%;    
    float: left;    
}

HTML:

<p class="main-text"><span class="column-width">Diary Date: 2016 April 01 &mdash;</span>This is the text of the diary entry. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fringilla pharetra metus id blandit. Integer molestie sed mauris eget gravida. Fusce aliquam diam eu arcu imperdiet vehicula. Fusce fermentum molestie aliquet. Phasellus sodales, mauris sed ornare accumsan, dolor ligula vehicula magna, vel pulvinar sapien lorem condimentum purus. Etiam vulputate commodo mattis. Etiam non tincidunt leo, eget ultricies mauris. Fusce rhoncus ultrices purus. Nunc id scelerisque nisi, quis congue turpis.</p>

代码片段: http://jsfiddle.net/Q3ruh/44/


1
简要想到最近可能需要类似的东西,所以基于当前被接受的答案,制作了以下内容。原始答案看起来对于小文本值(例如对齐值列表)可能很好,但是如果您重新调整大小和/或将在行内块区域内换行,则较长的文本不会重新流动。
<html>
    <head>
        <style type="text/css">
            /* decorative styles for demo only */
            html, body { 
                margin: 0;
                padding: 0;
            }
            p { 
                background-color: lightyellow; 
            }
            div#ruler {
                border-bottom: 1px solid gray;
                overflow: hidden;
                white-space: nowrap;
            }
            div#ruler>span {
                display: inline-block;
                text-align: right;
                font-size: xx-small;
                color: gray;
                border-right: 1px solid gray;
                overflow: hidden;
                box-sizing: border-box;
            }
            span.tabbed, br.tab {
                background-color: lightcyan;
            }

            /* seems to be needed if text-indent used for spacing; no harm for padding/margin... */
            span.tabbed::before {
                display: inline-block;
                content: '';
            }
            /* doesn't work universally, was hoping to use for better semantics -- maybe revisit... */
            br.tab {
                content: '';
                display: inline;
            }
        </style>
        <script type="text/javascript">
            // for rate-limiting resize/scroll event firing
            function debounce(func, wait, immediate) {
                // ref: https://davidwalsh.name/javascript-debounce-function
                var timeout;
                return function() {
                    var context = this, args = arguments;
                    var later = function() {
                        timeout = null;
                        if (!immediate) func.apply(context, args);
                    };
                    var callNow = immediate && !timeout;
                    clearTimeout(timeout);
                    timeout = setTimeout(later, wait);
                    if (callNow) func.apply(context, args);
                };
            };

            // decorative; used for drawing a ruler at the top of the page only
            function applyTabRuler(pid, tabstops) {
                var parent = document.getElementById(pid);
                if (!parent) {
                    parent = document.createElement('div');
                    document.body.insertBefore(parent, document.body.firstChild);
                }
                for (var s = 1, slen = tabstops.length; s < slen; s++) {
                    var width = tabstops[s] - tabstops[s - 1];
                    var tab = document.createElement('span');                        
                    tab.appendChild(document.createTextNode(s));
                    tab.style.width = tab.style.maxWidth = tab.style.minWidth = '' + width + 'px';
                    parent.appendChild(tab);
                }
            }

            // call this to align elements matching className to pixel-posiitoned tabstops
            // tabstops should be an array of monotonically-increasing pixel positions
            function applyTabStops(className, tabstops) {
                // try also paddingLeft or textIndent (may need a ::before{display:inline-block})
                var styleProp = 'marginLeft';
                
                var tabbed = document.getElementsByClassName(className);
                var bodyRect = document.body.getBoundingClientRect();
                var inlineMarker = document.createElement('span');
                
                for (var t = 0, tlen = tabbed.length; t < tlen; t++) {
                    tabbed[t].style[styleProp] = '0px';
                    tabbed[t].insertBefore(inlineMarker, tabbed[t].firstChild);
                    var tabRect = inlineMarker.getBoundingClientRect();

                    var tabstop = 0;
                    for (var s = 0, slen = tabstops.length - 1; s < slen; s++) {
                        if (tabRect.left >= tabstops[s] && tabRect.left < tabstops[s + 1]) {
                            tabstop = tabstops[s + 1];
                            break;
                        }
                    }
                    if (tabstop > 0) {
                        var width = tabstop - tabRect.left + bodyRect.left;
                        tabbed[t].style[styleProp] = '' + width + 'px';
                    }
                }
                
                if (inlineMarker && inlineMarker.parentNode) {
                    inlineMarker.parentNode.removeChild(inlineMarker);
                }
            }
        </script>
    </head>
    <body>
        <div>
            <div id="ruler"></div>
            <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc cursus congue purus vel blandit. 
                <span class="tabbed">Cras non justo vitae orci vehicula tincidunt. Aliquam convallis cursus nisi, 
                eu varius odio rutrum ut. Morbi id accumsan velit. Proin commodo consequat urna aliquam 
                imperdiet.</span> Curabitur laoreet est ut venenatis suscipit. Sed id vulputate enim.
                <span class="tabbed">Etiam libero massa, suscipit eget interdum non, vulputate nec eros. In hac 
                habitasse platea dictumst.</span>
                Ut vestibulum venenatis ante, at vestibulum ex varius eu. Nam lorem 
                turpis, euismod a aliquam vel, placerat iaculis mauris. Integer et eros turpis. Ut quis volutpat 
                urna, eu fermentum magna. Phasellus nunc turpis, accumsan nec velit eget, pretium semper urna.
            </p>
            <p>
                <span class="tabbed">Suspendisse nibh nibh, ultrices vitae odio aliquam, facilisis euismod dui.</span>
                Quisque dignissim felis in luctus faucibus. Sed at finibus leo. Suspendisse potenti. Nullam 
                commodo eleifend porttitor. Nam id dolor pretium felis rutrum posuere. Vivamus maximus lorem 
                mauris, sit amet pulvinar diam luctus nec. Praesent ac euismod lectus. 
                <span class="tabbed">Fusce tempor metus eget posuere vehicula.</span>
                Vestibulum porttitor vitae magna non consectetur. Ut nibh massa, molestie in 
                est nec, pellentesque rutrum purus. Nam sagittis felis gravida odio blandit, in tincidunt velit 
                ornare. Etiam congue tellus eros, at molestie risus luctus iaculis. Nulla et vehicula enim. 
                Integer pellentesque nunc augue, in scelerisque magna eleifend id. Etiam ut dapibus nulla, in 
                tincidunt justo. 
            </p>
            <p>Sed iaculis enim fermentum arcu gravida tempus. 
                <span class="tabbed">Sed ipsum ante, scelerisque eget tellus eget, sagittis pellentesque odio.</span></p>
            <p>Curabitur vestibulum felis non arcu cursus vehicula.
                <span class="tabbed">Nunc blandit neque et imperdiet efficitur.</span></p>
            <p>
                Quisque malesuada cursus porttitor.
                <span class="tabbed">Vestibulum porttitor libero massa, quis lacinia elit tempus vel.</span>
                <br/>
                Suspendisse laoreet sapien nec nulla placerat, vel dapibus nulla auctor.
                <span class="tabbed">Phasellus ut dictum dolor, sit amet feugiat tellus.</span>
            </p>
        </div>
        <script type="text/javascript">
            // random tabstops, for testing...
            var trun = 0;
            var tabstops = [];
            for (var t = 0, tlen = 50; t < tlen; t++) {
                tabstops[t] = trun; 
                trun += ((200 * Math.random()) + 20); 
            }
            
            // fixed tabstops...
            //var tabstops = [0, 200, 300, 450, 500, 600, 700, 800, 900, 1000];
            
            console.log(tabstops);

            applyTabRuler("ruler", tabstops);
            applyTabStops("tabbed", tabstops);
            
            var reapplyTabStops = debounce(function() { applyTabStops("tabbed", tabstops); }, 100);
            window.addEventListener('resize', reapplyTabStops);
            window.addEventListener('scroll', reapplyTabStops);
        </script>
    </body>
</html>

在FF94、Edge95和IE11中进行了烟雾测试。

最终成功摆脱了需求(毕竟在表格中呈现表格数据是可以的),但我想在这里提供它,以帮助其他人。

它并不完美:

  • 有几个地方不完全对齐(可能是边距/填充问题)
  • 调整大小时重新布局效果不佳
  • 没有为从右到左的语言做出任何努力(margin-inline可能足够)
  • 我更喜欢将选项卡定义为换行符(即<br>),而不是包含选项卡内容的<span>
  • 只能左对齐:无法将其与MS Word的制表位的“制表停靠点”对齐到右侧、居中或小数点

...但也许对于其他人来说已经足够了...

Example render


0

解决方案似乎是使用Javascript。这里有一个简单的例子:http://jsfiddle.net/A6z5D/1

<p>Hello bla bla bla<span id="tab1"></span>world</p>
<script>
function do_tab(id, tabstops)
{
    var tab1 = document.getElementById(id);
    var rect = tab1.getBoundingClientRect();
    console.log(rect.top, rect.right, rect.bottom, rect.left);
    var tabstop = 0;
    for (var i = 0; i < tabstops.length - 1; ++i)
    {
        if (rect.left >= tabstops[i] && rect.left < tabstops[i+1]) 
        {
            tabstop = tabstops[i+1];
        }
    }
    if (tabstop > 0)
    {
        var width = tabstop - rect.left;
        tab1.style.display = "inline-block";
        tab1.style.width = width + "px";
    }
}
do_tab("tab1", new Array(0, 100, 200, 300, 400));
</script>

0

我知道问题中说不要使用表格,之前的JS答案也不受欢迎,但是有人应该会觉得这个有用。它不能做到真正的制表符,但即使使用CSS也不可能。

如果你不想手动添加大量的或标签,这个JS会在页面加载时自动将所有class为“tabs”的元素转换为表格,使用制表符作为指南。

JS Fiddle: https://jsfiddle.net/s7m6zggp/7/

编辑:仔细想想,也许不是最好的方法。正则表达式让我感到困惑。但是我会保留Fiddle,以防有人想使用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接