Can I set up tab stops in html5?

You can use the CSS property p { text-indent:50px; }

You can use css classes for each indent like

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

and do the HTML like this

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

Because you can only indent one line with this property there's another way to support multiline-indent:

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

And finally a fiddle.


Despite the assertions of the other posters to the contrary, there are valid reasons to want to do what the OP asked and many ways to do it using modern CSS (and more in the draft specification process as I write this). Here is just one way.

<!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>

See sample results here: http://jsfiddle.net/Td285/

Another example, with overflow clipped: http://jsfiddle.net/KzhP8/


Briefly thought I might need something similar recently, so mocked up the following, using the current accepted answer as a basis. Original answer looked like it might be fine for small text values (e.g. aligning a list of values), but longer text didn't reflow if you resized and/or would wrap inside the inline block area.

<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>

(Smoke-tested in FF94, Edge95, IE11)

Managed to get the requirement to go away in the end (it is OK to present tabular data in tables, after all), but I thought I'd offer it up here in case it helps anyone else.

It's not perfect:

  • there are a couple of places where it doesn't line up exactly (I guess possible margin/padding issues)
  • reflow isn't great on resizing
  • no effort done for right-to-left languages (margin-inline may be enough)
  • I'd prefer to define tabs as breaks (i.e. <br>) rather than <span> containing the tabbed content
  • only left-aligned: couldn't align right, centred or decimal-point to the "tabstop", which is a significant feature of MS Word's tabstops

...but maybe it is enough for someone else to get it over the line...

Example render


Actually, I had a similar situation, and I did it quite simply. Use the <span> within the <p> property, and float it appropriately.

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>

fiddle: http://jsfiddle.net/Q3ruh/44/

Tags:

Html