更新 3(演示 3)
变化
我注意到most current OP code 中不再使用任何position: relative,这很好,但我相信这被遗忘了:
<span class='pagebreak spacer'contenteditable="false"></span>
我相信您最初使用 contenteditable="false" 是为了给您的 .pagebreaks 提供额外的功能并防止它们被删除,所以我重新添加了它们。
比较
Demo 3 将我的解决方案与OP code 并排比较行为。 Demo 3 还具有 2 个按钮(每个内容编辑器 1 个)突出显示每个 <span> 文本。以下是 OP 代码中的类列表(右侧的内容编辑器)和我的代码中等效的每个类的列表(左侧的内容编辑器)。
-
div.textframe.................................section.editor
-
p.textOutline.................article.content
-
span.flowbox.spacer......mark.vertRule
-
span.pagebreak.spacer ..mark.breaker
OP 关注两个要求:
点击<span>s周围的空白区域时,光标会跳到内容区域的一角。
每行字符数必须与OP码当前容量一致。
这个问题已经存在多年,但原因是星云,所以如果你将这种异常视为一种行为,你可以通过灌输不同的行为来解决它。
Demo2 和 Demo3 只需应用以下样式规则集即可满足这些标准:
演示 2
article p {display: table;...
演示 3
.content {display:table-cell;...
表格单元格的行为是严格且完善的,AFAIK 是唯一默认符合其内容并符合周围表格元素的非replaced element。作为奖励,带有display: table-cell(不是<td>)的元素不需要嵌套在<tr> 内,而<table> 内。
演示3
.content { display: table-cell;...
/* Begin Defaults */
* {
margin: 0;
padding: 0;
border: 0;
box-sizing: border-box;
}
html,
body {
background: white;
font: 400 16px/1.45 Arial;
height: 100%;
width: 100%;
}
/* End Defaults */
/* Begin Optional Layout */
#page01 {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
align-items: flex-start;
background: rgba(45, 99, 198, 0.6);
margin: 0 auto 20px;
height: fit-content;
min-width: 100%
}
/* End Optional Layout */
/* Begin Primary Styles */
.editor {
width: 350px;
height: 600px;
border: 1px solid black;
background: #fff;
}
.vertRule {
float: right;
clear: right;
width: 30px;
height: 600px;
}
.content {
display: table-cell;
word-break: break-word;
}
mark {
display: block;
pointer-events: none;
}
.break {
min-height: 80px;
}
/* End Primary Styles */
/* Begin Control */
/* https://jsfiddle.net/q4pu37dn/15 */
.textframe {
width: 350px;
height: 600px;
border: 1px solid black;
background: #fff;
}
.flowbox {
float: right;
clear: right;
width: 30px;
height: 600px;
}
.spacer {
background: yellow;
}
.pagebreak {
display: block;
min-height: 80px;
}
/* End Control */
/* Begin Demo Test */
.btn {
display: inline-block;
font: inherit;
margin: 5px 10px;
padding: 2px 5px;
border: 5px outset grey;
border-radius: 8px;
color: #000;
cursor: pointer;
}
[type='checkbox']:checked+label {
background: rgba(255, 12, 34, 0.75);
border: 5px inset grey;
color: #fff;
}
#outline1:checked+label+#outline2+label+hr+#page01>.editor>.content *,
#outline2:checked+label+hr+#page01>.textframe>#textOutline *:not(.spacer) {
color: #fff;
background: tomato;
outline: 2px solid red;
}
#outline1:checked+label+#outline2+label+hr+#page01>.editor>.content>.break,
#outline2:checked+label+hr+#page01>.textframe>#textOutline>.spacer {
background: yellow;
outline: none;
}
/* End Demo Test */
<!-- Begin Demo Test -->
<input id="outline1" type='checkbox' hidden>
<label for='outline1' class='btn'>Outline 1</label>
<input id="outline2" type='checkbox' hidden>
<label for='outline2' class='btn'>Outline 2</label>
<hr>
<!-- End Demo Test -->
<!-- Begin Optional Layout Part 1 -->
<main id='page01'>
<!-- End Optional Layout Part 1 -->
<!-- Begin Primary Markup -->
<section class="editor" contenteditable='true'>
<mark class="vertRule" contenteditable='false'></mark>
<article class='content'>
<span>
Clicking here is not a problem
</span>
<br>
<br>
<span>
Lorem ipsum
</span>
<mark class="break" contenteditable='false'></mark>
<span>
Clicking here (on empty space, not directly on text) will put the caret above the first .break element.
</span>
<br>
<br>
<span>
Lorem ipsum
</span>
<mark class="break" contenteditable='false'></mark>
<br>
<span>
Clicking here is not a problem
</span>
<br>
<br>
</article>
</section>
<!-- End Primary Markup -->
<!-- Begin Control -->
<div class="textframe" contenteditable>
<p id='textOutline'>
<span class="spacer flowbox"></span>
<span>
Clicking here is not a problem
</span>
<br>
<br>
<span>
Lorem ipsum
</span>
<span class="spacer pagebreak"></span>
<span>
Clicking here (on empty space, not directly on text) will put the caret above the first .pagebreak element.
</span>
<br>
<br>
<span>
Lorem ipsum
</span>
<span class="spacer pagebreak"></span>
<br>
<span>
Clicking here is not a problem
</span>
<br>
<br>
</p>
</div>
<!-- End Control -->
<!-- Begin Optional Layout Part 2 -->
</main>
<!-- End Optional Layout Part 2 -->
更新 2(演示 2)
关于演示 1 的操作:
“你为我设计的例子解决了这个问题,是的。不幸的是,无法在实际应用中的元素上设置这些值,那里的流程完全不合常理。” p>
参见Demo 2,它比Demo 1效果更好。由于它仅使用定位元素,因此流中没有冲突。为了使 Demo 2 适应您的应用程序,您只需将position:relative 添加到父元素即可。相关样式如下:
article p {display: table;...
必须将position:relative 分配给嵌套在.textframe 中的所有内容,否则static 元素将不会与定位的元素交互。表格和表格组件遵循的规则不仅适用于其内容,还适用于它们与相邻元素的交互方式。
演示 2
article p {display: table...
.container {
width: 400px;
float: left
}
.textframe {
width: 350px;
height: 650px;
outline: 2px dotted lightblue;
overflow: hidden;
margin: 0 15px 0 0;
/* Needed for long words */
word-break: break-word;
}
.textframe article {
position: relative;
height: 650px;
}
article p {
display: table;
margin: 0;
position:relative;
}
.flowbox {
width: 2px;
height: 650px;
float: right;
clear: right;
outline: 1px solid red;
}
.pagebreak {
display: block;
pointer-events:none;
position:relative;
}
<div class="container">
<h4>
article p {display: table; position: relative;}<br>
all children of .textframe have: position: relative;
</h4>
<div class="textframe a">
<div class="flowbox"></div>
<article contenteditable="true">
<p>
<span>
<span>Foo bar baz</span>
<br>
<mark class="pagebreak" contenteditable="false" style="min-height: 80px"></mark>
<span>Foo bar baz</span>
<br>
<span>Lorem ipsum dolor sit amet, consectetur adi piscing elit.</span>
<br>
<br>
<mark class="pagebreak" contenteditable="false" style="min-height: 80px"></mark>
<br>
<span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
</span>
</p>
<hr>
</article>
</div>
</div>
引用
MDN - Float
MDN - Position
CSS Tricks - Absolute Positioning Inside Relative Positioning
CSS Tricks - All About Floats
display: table/table-cell
word-break:break-word