如何使用 Bootstrap 在 Jekyll 中换行文本而不是代码块?

How to wrap text, but not code blocks, in Jekyll using Bootstrap?

问题

我在 GitHub 页面上有一个博客:https://silvuss.github.io。它使用 Bootstrap 4.1 构建,使用 markdown 并使用 Jekyll 呈现(Github Pages 中的默认设置)。我将所有 Jekyll 选项保留为默认值。

问题是现在每个页面都可以在较宽的屏幕上正确显示,但在较窄的(移动)屏幕上则不是每个页面。唯一不能在较窄的屏幕(例如 375 x 667)上正确显示的页面是那些包含降价代码块(```)的页面。我注意到 Jekyll 将降价代码块呈现为 <pre><code></code></pre>.

我想换行文章的文字,而不是代码块中的代码。

到目前为止我做了什么

(1) 到目前为止,我尝试使用 CSS 来包装所有内容(文本和代码块)。使用下面的代码,文本被包裹了一半,代码块根本没有包裹:

<style>
    pre, code {
        white-space: pre-wrap;
    }
</style>

(2) 我还对 <pre><code>word-break 属性 的不同值进行了实验,但结果不会因任何值而改变。

(3) 由于 Jekyll 默认使用 Kramdown,我还尝试更改 _config.yml 文件中的 coderay_wrap 选项(目前在本地,而不是推送到 GitHub)。但是,none 的值似乎有效。我尝试了以下组合(都存在和不存在 markdown: kramdown 选项):

# One try, seems not to change anything
markdown: kramdown
kramdown:
  coderay_wrap: span

# Another try, seems not to change anything
markdown: kramdown
kramdown:
  coderay_wrap: div

# Another try, seems not to change anything
markdown: kramdown
kramdown:
  coderay_wrap: nil

更新: 抱歉,我更正了 CSS 代码,将 pre 更改为 pre, code


UPDATE2: 我忘了说我用什么浏览器来测试它。我现在不记得我在发布这个问题时使用的是什么浏览器,但现在我使用的是 Firefox 74.0.1。

现在,由于我收集了足够的信息,我想我可以回答我自己的问题了。


重要提示: 不要相信我的回答。我的调试和编码过程,正如您将在下面看到的,并不直接而且简单的。在许多情况下,我不得不 猜测 CSS(= 浏览器)的行为。这是因为 CSS 文档和规范中有很多地方我还不了解。 如果您遇到类似的问题,如果可能的话,请直接参考CSS和其他网络技术的文档和规范,而不是我的回答——以免混淆。


感谢用户@mb21:

  • 试图理解我的问题(有时我什至不太明白我过去的意思);
  • 提出一个确实对我有帮助的提示(在对我的问题的评论中)*。

注意:由于从我 post 提出问题之日起已经过去了一段时间,我博客的样式和布局发生了变化(正如我在对问题的评论)。幸运的是,因为我使用的是 VCS (Git),所以我能够获得我网站源代码的旧版本。接下来,这个答案包括两个部分,每个部分描述了针对网站不同状态的解决方案。如果您想验证我的解决方案是否真的有效,我将下面的 links 添加到我提出解决方案时所基于的提交中。

  1. 当有 Bootstrap 样式时,我用来表示网站状态的提交的 link 是:https://github.com/silvuss/silvuss.github.io/commit/c86a4123b09833758e70c222a7b45212feb0250b
  2. 我用来表示网站当前状态(纯 CSS 样式)的提交的 link 是:https://github.com/silvuss/silvuss.github.io/commit/1a9e11b4410abe9479b86e63d446895f440371d8

* 有关提示如何帮助我,请参阅此答案的 "The solution for the current, non-Bootstrap styles" 部分。

问题又来了

对我来说,问题描述的问题很清楚;但是,让我重新表述一下几点。

  1. 我用 Markdown 为我的博客写了所有文章。
  2. 在一些文章中,我在 Markdown 的代码块中有文本——也就是说,在 `````` 之间。
  3. 为了构建站点(以便在浏览器中向用户显示),Jekyll 将所有文章呈现为 HTML 页面(然后将这些页面放入 HTML模板,但这对我的问题并不重要)。
  4. 默认情况下,Markdown 的代码块由 Jekyll 呈现为四个 HTML 元素,一个放在另一个里面:<code> HTML 元素放在 <pre> 里面HTML 元素,放置在 <div> HTML 元素内,再次放置在 <div> HTML 元素内。它看起来像这样:<div><div><pre><code>Here some content</code></pre></div></div>(我在这里省略了属性)。为了简洁起见,在这个答案的后面,我将这段代码称为 "Jekyll's code block".
  5. 呈现所有站点后,就可以在浏览器中显示它了。
  6. 重要的部分来了:
    1. 对于包含至少一个 Jekyll 代码块且其宽度小于或等于浏览器当前视口*的页面,则没有问题。我正在写 "size of the rendered block",这是一个用 CSS 术语表达的非常模糊的陈述;但是,我希望人们能够直观地理解它,了解 CSS 是如何工作的。另外,我的意思是视口的宽度可能与 "desktop view" 一样大,也可能与 "mobile view".
    2. 一样小
    3. 对于包含至少一个 Jekyll 代码块且其宽度大于浏览器当前视口的页面,则存在问题.在这种情况下,页面上的所有 HTML 元素(不仅是 Jekyll 的代码块)宽度大于视口 "overflows" 水平 (通过默认情况下,浏览器会显示一个滚动条。
  7. 我想实现的是:
    1. 让 Jekyll 代码块的内容溢出(只是不要改变这种行为);
    2. 使所有其他元素的所有内容(即不在该块内的所有内容)不溢出。

我在问题中,甚至在问题标题中都写了关于 "wrapping"。我的意思是 "wrapping" 在 CSS white-space 属性 或 overflow-wrap 属性 的上下文中。不过后来发现问题和这样的"wrapping"关系不大。现在我认为这是一个错误。


* 我知道有两个,嗯,"kinds" 视口:布局视口和视觉视口。您可以阅读有关它们的信息 here。在这个答案中,我只写 "viewport" 因为我不太熟悉那两个 "kinds" 视口;所以,我不确定在什么情况下应该使用其中一种。我希望通用术语 "viewport" 在问题的上下文中是清楚的我的问题和我的回答地址。如果不是,请发表评论,也许建议我应该使用其他术语。

前者的解决方案,Bootstrap样式

注意: 我一直在努力寻找导致我 post 问题。但是,由于我在 post 编辑它的那天已经多次提交,所以我不能 100% 确定我找到的版本是否相同。

问题的根本原因

好吧,我仍然不确定问题的根本原因是什么 — 或者甚至不确定:是否存在一个问题。我的意思是,似乎有多个根本原因。但是,最有可能的是,Jekyll 代码块的内容使容器的大小变为 "stretching",实际上使它变为 "overflowing the viewport"。接下来,容器的所有内容(包括块内和块外)都超出了视口,这就是结果。

我是怎么查的?在一篇文章中,我放置了一段 Markdown 的预格式化文本,然后呈现为 ​​Jekyll 的代码块,确保它以使其成为视口 "overflowing" 的宽度呈现。然后,我将 display: none 应用于 <code> 元素。在那之后,页面内似乎没有"oveflowing"了。

解决方法

情况

原来我想达到的目的可以通过限制 Jekyll 代码块旁边的所有内容的范围来解决"stretch"。在 CSS 中可以通过几种方式实现这种行为(在 JavaScript 中甚至可以通过更多方式实现)。我想出的解决方案是使用 CSS 属性 widthmax-width(在不同的元素上)。

我需要指出的是,我仍然不知道 CSS 究竟是如何确定一个元素的宽度的(一般来说,不仅在我的网站内)。如果该元素是页面上的唯一元素,那么评估它很可能会非常简单。但是,就像我的情况一样,在从 <html> 元素到 Jekyll 代码块的路径上有几个嵌套元素,那就很难了。

下面是包含一篇文章的 HTML 页面结构的一部分。我展示了从 <html> 元素到 Jekyll 代码块的路径,为了清楚起见,我省略了属性。有些元素是我放的,有些是 Jekyll 渲染的。

<html>
    <body>
        <div>
            <main>
                <article>
                    Here some article's content outside the HTML generated by Jekyll
                    <div>
                        <div>
                            <pre>
                                <code>
                                    Here some content within the HTML generated by Jekyll
                                </code>
                            </pre>
                        </div>
                    </div>
                    Here some article's content outside the HTML generated by Jekyll
                </article>
            </main>
        </div>
    </body>
</html>

解决方案的第一部分

我在设计网站的时候,在<article>HTML元素中使用了Bootstrapclasscol-sm-10来限制宽度这个元素。 (现在我记得这个 class 使元素的宽度是某个元素宽度的 10/12……但我不记得这个 "some element" 是这个元素的直接容器,还是其他元素有一些特定的 Bootstrap class。如果你想确定,请参阅 documentation of Bootstrap 4.1.x grid system(我一直使用的版本是 4.1.3)。)

当时的情况是,在 <article> 元素的内容包括任何元素 一个 Jekyll 代码块的情况下,这种限制很有效。

因此,我尝试验证 Jekyll 代码块中的哪些元素导致了此问题。我意识到它有可能是几个元素的组合。但是,在这种情况下检查所有可能的组合似乎工作量太大。我只是假设它是由一个因素引起的;此外,我假设它是 "more inner" 一个而不是 "more outer".

所以,我在<article>元素的child中添加了一个随机内容很长的<code>元素。竟然没有"overflow"。接下来,我将其替换为具有相同内容的 <pre> 元素。现在有 "overflow"。所以我停止检查并假设它是导致 "overflow" 的 <pre> 元素。然后我读了documentation of this element。它似乎证实了这个假设,虽然我没有注意到任何解释明确告诉这个元素可能会导致任何 "overflow".

现在的问题是:既然内容是根据 col-sm-10 class 限制的,以防它不包含 Jekyll 的代码块,为什么不限制它以防万一包括在内吗? <article> 元素似乎 "considered" <pre> 元素的大小(=存在)比 col-sm-10 class 强加的大小更重要。 *

我在浏览器的开发人员工具中查找了 CSS 属性由 Bootstrap col-sm-10 class 定义的内容。结果是两个属性:flex,其值设置为 0 0 83.333333%,以及 max-width,其值设置为 83.333333%。这些声明的含义如下:

  • 声明flex: 0 0 83.333333%意味着:
    • flex-grow 属性 的值设置为 0。我不太了解 its documentation on MDN 它应该如何工作。尽管如此,<article> 元素的容器中没有其他元素,所以我假设 val这个 属性 的 e 无关紧要。在开发人员工具中更改它似乎没有改变任何东西,这证实了这个假设。
    • flex-shrink 属性 的值设置为 0。我不太了解 its documentation on MDN 它应该如何工作。尽管如此,<article> 元素的容器中没有其他元素,因此我假设此 属性 的值无关紧要。在开发人员工具中更改它似乎没有改变任何东西,这证实了这个假设。
    • flex-basis 属性 的值设置为 83.333333%。根据documentation of this property on MDN, it "sets the initial main size of a flex item". If given a percentage as its value, it is calculated as a percentage "of the parent flex container's main size property". The W3C documentation says (by an image) that the "main size" of a "row flex container" is just its width. When translating this statement into Bootstrap grid system, I didn't quite get from the Bootstrap documentation什么元素我应该算一个"parent flex container"。但是,开发人员工具报告 <article> 元素的第一个 parent 将 display 属性 设置为 flex,我认为这就足够了假设它是这个元素。综上所述,flex-basis 属性 告诉我们将 <article> 元素的宽度限制为 parent 容器的 83.333333% — 在本例中,<main> HTML 元素(如您在上面的清单中所见)。
  • 声明 max-width: 83.333333% 意味着 <article> 元素的宽度不能大于包含块宽度的 83.333333% — 我猜,根据 documentation<main> 元素。请注意,在提到的 MDN 文档中,使用了术语 "content box"。我找不到它是什么,但我发现有一个术语 "content-box"**(注意破折号而不是 space)。我不能说这些术语是等价的(严格来说;这就是我写 "I guess" 的原因)。该声明似乎还使 <pre> 元素(属于 Jekyll 的代码块)水平溢出其 parent 框(并具有滚动条);不过,我也不能确定这一点,因为我已经验证了这个假设,只在开发人员工具中启用和禁用 max-width 属性。

现在,我评估了有两种方法可以更进一步。第一个涉及确定为什么 <main> 元素是 "overflowing"——正如我检查过的那样——确实如此——并阻止它这样做。第二个涉及使 <article> 元素的宽度不依赖于其 parent 宽度。我选择了第二种方式,因为它看起来更简单。

现在,最简单的做法似乎就是用不会与 <article> 元素的 parent 容器关联的自定义声明覆盖 max-width: 83.333333% 声明。我选择了max-width: 83.333333vw(注意单位的变化)。我直接将它应用在 <article> 元素上。现在,<article> 元素不再是 "overflowing" 视口。


* 我知道这可能是 CSS 的默认行为。但我不知道有任何消息来源证实这一点。如果有人能找到证实或反驳这种行为的消息来源,我会很高兴。

** 有关第二个术语的内容,请参阅有关 box-sizing CSS 属性 的 MDN 文档中的示例 this section of the article on Wikipedia about the CSS box model (look up the word "content-box") or this article。 =254=]

解决方案的第二部分

剩下要做的,就是让 Jekyll 的代码块 "not respecting" 对其 parent 元素(<article> 元素)的宽度施加限制。经过一些试验,结果是 <pre> 元素的宽度超过了 <article> 元素的宽度。

所以,我开始尝试。我第一个想到的 属性 是 width 属性。开发人员工具报告没有涉及此 属性 的样式。因此,我假设它的实际值是它的初始值——即 auto 值。在开发人员工具中尝试使用不同的值后,我发现 min-contentmax-content 值都使 <pre> 元素适合其 parent 元素。我在 documentation of these values, but I didn't quite get the difference until I read this Stack Overflow answer 中查找。由于这两个值似乎同样有效,因此我选择了 max-content 值,因为在我的情况下更直观。

当前的解决方案,non-Bootstrap 样式

由于我的问题是关于我的网站自出现 Bootstrap 样式以来的状态,因此当前样式的解决方案作为此答案的一部分似乎不太重要。因此,我不会描述当前样式的解决方案所涉及的所有内容,而只描述结果。

解决方案包括两个步骤:

  1. 将 Jekyll 代码块容器的 max-width 属性 的值设置为:
    • calc(100vw - 10px - 20px) 如果视口更大(10px20px 代表填充大小),
    • inherit 如果视口较小;
  2. <pre> 元素的 width 属性 的值设置为 max-content.

第一步是 @mb21 用户的提示帮助了我。

注意: 如果您要在 GitHub 上检查我的代码,请注意本节中描述的更改尚未推送。我稍后再做,然后更新这个答案。


更新2020-04-22:我计划在我网站的 4.1 版本中推送对当前样式的修复。


更新 2020-04-23: 我发布了我网站的 4.1 版,其中包含对当前样式的修复。可以查看here.

我遇到了一个问题,代码围栏 (```) 中的长文本会在 Safari 中换行而不是滚动。它在 FireFox 和 Chrome 中运行良好(代码块将滚动而不是自动换行)。我通过在 syntax.css 文件中设置“word-wrap: normal”解决了这个问题。 (syntax.css 文件是包含 syntax highlighting 的 css)

示例:

.highlight code, .highlight pre { word-wrap: normal }

我的 Jekyll _config.yml 有以下设置:

highlighter: rouge
markdown: kramdown
kramdown: 
  input: GFM
  hard_wrap: false

我正在使用 Bootstrap v4.5.2 和 Jekyll v3.9.0 (GitHub pages Jekyll version)