如何保留HTML <pre> tags excluding the current indentation level of the <pre> tag in the document?</pre></pre>中包含的文本的空白缩进

时间:2011-01-08 00:48:57

标签: html whitespace indentation pre

我正在尝试在网站上显示我的代码,但我遇到了正确保留空白缩进的问题。

例如,给出以下代码段:

<html>
 <body>
   Here is my code:
   <pre>
     def some_funtion
       return 'Hello, World!'
     end
   </pre>
 <body>
</html>

这在浏览器中显示为:

Here is my code:

     def some_funtion
       return 'Hello, World!'
     end

当我希望它显示为:

Here is my code:

def some_funtion
 return 'Hello, World!'
end

不同之处在于HTML pre标记的当前缩进级别被添加到代码的缩进中。我使用nanoc作为静态网站生成器,我使用谷歌美化也添加语法高亮。

任何人都可以提供任何建议吗?

11 个答案:

答案 0 :(得分:22)

PRE旨在保留与其显示完全相同的空白(除非由CSS中的white-space更改,因为它没有足够的灵活性来支持格式化代码)。

<强>之前

保留格式,但PRE标记之外的缩进也是如此。使用标签位置作为起点进行空白保存会很好。

enter image description here

<强>后

内容仍然按声明格式化,但文档中PRE标记位置导致的无关前导空格将被删除。

enter image description here

我想出了以下插件来解决想要删除文档大纲缩进导致的多余空白的问题。此代码使用PRE标记内的第一行来确定它纯粹由于文档的缩进而缩进了多少。

此代码适用于IE7,IE8,IE9,Firefox和Chrome。我已使用Prettify库对其进行了简要测试,以将保留的格式与漂亮的打印相结合。确保PRE中的第一行实际上代表您要忽略的缩进的基线级别(或者,您可以修改插件以使其更加智能化)。

这是粗略的代码。如果您发现错误或无法正常工作,请修改/评论;不只是downvote。我写了这段代码来修复我遇到的问题,并且我正在积极地使用它,所以我希望它尽可能坚固!

/*!
*** prettyPre ***/

(function( $ ) {

    $.fn.prettyPre = function( method ) {

        var defaults = {
            ignoreExpression: /\s/ // what should be ignored?
        };

        var methods = {
            init: function( options ) {
                this.each( function() {
                    var context = $.extend( {}, defaults, options );
                    var $obj = $( this );
                    var usingInnerText = true;
                    var text = $obj.get( 0 ).innerText;

                    // some browsers support innerText...some don't...some ONLY work with innerText.
                    if ( typeof text == "undefined" ) {
                        text = $obj.html();
                        usingInnerText = false;
                    }

                    // use the first line as a baseline for how many unwanted leading whitespace characters are present
                    var superfluousSpaceCount = 0;
                    var currentChar = text.substring( 0, 1 );

                    while ( context.ignoreExpression.test( currentChar ) ) {
                        currentChar = text.substring( ++superfluousSpaceCount, superfluousSpaceCount + 1 );
                    }

                    // split
                    var parts = text.split( "\n" );
                    var reformattedText = "";

                    // reconstruct
                    var length = parts.length;
                    for ( var i = 0; i < length; i++ ) {
                        // cleanup, and don't append a trailing newline if we are on the last line
                        reformattedText += parts[i].substring( superfluousSpaceCount ) + ( i == length - 1 ? "" : "\n" );
                    }

                    // modify original
                    if ( usingInnerText ) {
                        $obj.get( 0 ).innerText = reformattedText;
                    }
                    else {
                        // This does not appear to execute code in any browser but the onus is on the developer to not 
                        // put raw input from a user anywhere on a page, even if it doesn't execute!
                        $obj.html( reformattedText );
                    }
                } );
            }
        }

        if ( methods[method] ) {
            return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
        }
        else if ( typeof method === "object" || !method ) {
            return methods.init.apply( this, arguments );
        }
        else {
            $.error( "Method " + method + " does not exist on jQuery.prettyPre." );
        }
    }
} )( jQuery );

然后可以使用标准的jQuery选择器应用此插件:

<script>
    $( function() { $("PRE").prettyPre(); } );
</script>

答案 1 :(得分:14)

缩进评论

由于浏览器会忽略评论,因此您可以使用它们缩进pre代码内容。

解决方案

&#13;
&#13;
<html>
  <body>
    <main>
      Here is my code with hack:
      <pre>
<!-- -->def some_function
<!-- -->  return 'Hello, World!'
<!-- -->end
      </pre>
      Here is my code without hack:
      <pre>
        def some_function
          return 'Hello, World!'
        end
      </pre>
    </main>
  <body>
</html>
&#13;
&#13;
&#13;

注意:添加了一个主包装,为评论提供了足够的空间。

优点

  • 无需JavaScript
  • 可以静态添加
  • 缩小不会影响缩进并缩小文件大小

缺点

  • 要求评论的最小空间
  • 除非使用构建工具,否则不是很优雅

使用节点

删除缩进

更好的解决方案是使用构建过程或后端渲染过程删除前导空白区域。如果您使用的是node.js,那么您可以使用我编写的名为predentation的流。您可以使用任何您想要构建类似工具的语言。

<html>
 <body>
   Here is my code:
   <pre>
     def some_function
       return 'Hello, World!'
     end
   </pre>
 </body>
</html>

<html>
 <body>
   Here is my code:
   <pre>
def some_function
  return 'Hello, World!'
end
   </pre>
 </body>
</html>

优点

  • 撰写pre代码的无缝方式
  • 较小的输出文件大小

缺点

  • 需要在工作流程中构建步骤
  • 不处理CSS添加pre的非white-space: pre元素

使用JavaScript删除缩进

See this answer to remove indentation with JavaScript

优点

  • 可以使用white-space: pre
  • 定位元素

缺点

  • 可以禁用JavaScript
  • 空格会增加文件大小

答案 2 :(得分:5)

使用JavaScript进行管理。它适用于Internet Explorer 9和Chrome 15,我还没有测试旧版本。当添加对outerHTML的支持时,它应该在Firefox 11中工作(请参阅here),同时网上还有一些自定义实现。读者的练习是摆脱尾随缩进(直到我抽出时间完成它并更新这个答案)。

我还将此标记为社区维基,以便于编辑。

请注意,您必须重新格式化示例以使用制表符作为缩进,或更改正则表达式以使用空格。

<!DOCTYPE html>
<html>
    <head>
        <title>Hello, World!</title>
    </head>
    <body>
        <pre>
            &lt;html&gt;
                &lt;head&gt;
                    &lt;title&gt;Hello World Example&lt;/title&gt;
                &lt;/head&gt;
                &lt;body&gt;
                    Hello, World!
                &lt;/body&gt;
            &lt;/html&gt;
        </pre>
        <pre>
            class HelloWorld
            {
                public static int Main(String[] args)
                {
                    Console.WriteLine(&amp;quot;Hello, World!&amp;quot;);
                    return 0;
                }
            }
        </pre>
        <script language="javascript">
            var pre_elements = document.getElementsByTagName('pre');

            for (var i = 0; i < pre_elements.length; i++)
            {
                var content = pre_elements[i].innerHTML;

                var tabs_to_remove = '';
                while (content.indexOf('\t') == '0')
                {
                  tabs_to_remove += '\t';
                  content = content.substring(1);
                }

                var re = new RegExp('\n' + tabs_to_remove, 'g');
                content = content.replace(re, '\n');
                pre_elements[i].outerHTML = '<pre>' + content + '</pre>';
            }
        </script>
    </body>
</html>

答案 3 :(得分:3)

This can be done in four lines of JavaScript:

var pre= document.querySelector('pre');

//insert a span in front of the first letter.  (the span will automatically close.)
pre.innerHTML= pre.textContent.replace(/(\w)/, '<span>$1');

//get the new span's left offset:
var left= pre.querySelector('span').getClientRects()[0].left;

//move the code to the left, taking into account the body's margin:
pre.style.marginLeft= (-left + pre.getClientRects()[0].left)+'px';
 <body>
   Here is my code:
   <pre>
     def some_funtion
       return 'Hello, World!'
     end
   </pre>
 <body>

答案 4 :(得分:2)

<script>
    $("pre[name='pre']").each(function () {
        var html = $(this).html()
        var blankLen = (html.split('\n')[0].match(/^\s+/)[0]).length
        $(this).html($.trim(html.replace(eval("/^ {" + blankLen + "}/gm"), "")))
    })
</script>
<div>
	<pre name="pre">
		1
			2
				3
	</pre>
</div>

答案 5 :(得分:2)

如果您可以更改元素的innerHTML,则可以:

给出:

<pre>
  <code id="the-code">
    def some_funtion
      return 'Hello, World!'
    end
  </code
</pre>

哪个呈现为:


    def some_funtion
      return 'Hello, World!'
    end

以下香草JS:

// get block however you want.
var block = document.getElementById("the-code");

// remove leading and trailing white space.
var code = block.innerHTML
                .split('\n')
                .filter(l => l.trim().length > 0)
                .join('\n');

// find the first non-empty line and use its
// leading whitespace as the amount that needs to be removed
var firstNonEmptyLine = block.textContent
                             .split('\n')
                             .filter(l => l.trim().length > 0)[0];

// using regex get the first capture group
var leadingWhiteSpace = firstNonEmptyLine.match(/^([ ]*)/);

// if the capture group exists, then use that to
// replace all subsequent lines.
if(leadingWhiteSpace && leadingWhiteSpace[0]) {
  var whiteSpace = leadingWhiteSpace[0];
  code = code.split('\n')
             .map(l => l.replace(new RegExp('^' + whiteSpace + ''), ''))
             .join('\n');
}

// update the inner HTML with the edited code
block.innerHTML = code;

将导致:

<pre>
  <code id="the-code">def some_funtion
  return 'Hello, World!'
end</code>
</pre>

并将呈现为:

def some_funtion
  return 'Hello, World!'
end

答案 6 :(得分:1)

我还发现如果你使用haml,你可以使用preserve方法。例如:

preserve yield

这将保留生成的yield中的空格,该空格通常是包含代码块的markdown。

答案 7 :(得分:1)

我决定提出一些比改变precode工作方式更具体的方法。所以我做了一些正则表达式来获取第一个换行符\n(前面有可能的空格 - \s*用于清除一行代码末尾和换行符之前的额外空格(我注意到你的))并找到它后面的标签或空白字符[\t\s]*(这意味着制表符,空格字符(0或更多)并将该值设置为变量。然后该变量用于正则表达式替换函数查找它的所有实例并将其替换为\n(换行符)。由于第二行(pattern设置的地方)没有全局标记(g之后正则表达式,它将找到\n换行符的第一个实例并将pattern变量设置为该值。因此,对于换行符,后跟2个制表符,{的值从技术上讲,{1}}将pattern替换,在\n\t\t元素中找到每个\n字符(因为它贯穿每个函数)并替换与pre code

&#13;
&#13;
\n
&#13;
$("pre code").each(function(){
    var html = $(this).html();
    var pattern = html.match(/\s*\n[\t\s]*/);
    $(this).html(html.replace(new RegExp(pattern, "g"),'\n'));
});
&#13;
&#13;
&#13;

答案 8 :(得分:0)

这很麻烦,但如果代码折叠对您很重要,它就可以使用:

        <pre>def some_funtion</pre>
        <pre>    return 'Hello, World!'</pre>
        <pre>end</pre>

在你的CSS中,

    pre { margin:0 }

在vim中,正常编写代码然后执行:

    :s/\t\t\([^\n]\+\)/<pre>\1<\/pre>/
每行的

都可以。

答案 9 :(得分:0)

如果您在代码块上使用它,例如:

<pre>
  <code>
    ...
  </code>
</pre>

你可以使用这样的css来抵消前面那么大的空白区域。

pre code {
  position: relative;
  left: -95px; // or whatever you want
}

答案 10 :(得分:-1)

pre标签会保留您在体内书写时使用的所有空白区域。通常情况下如果你不使用pre它会正常显示文本...(HTML将使浏览器忽略那些空格)这里尝试这个我使用了段落标记。 输出: -

这是我的代码:

def some_function

  return 'Hello, World!'

<html> <body> Here is my code: <p> def some_function<br> <pre> return 'Hello, World!'<br></pre> end </p> </body> </html>