diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/css/css_box_model | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/zh-cn/web/css/css_box_model')
4 files changed, 3225 insertions, 0 deletions
diff --git a/files/zh-cn/web/css/css_box_model/box-shadow_generator/index.html b/files/zh-cn/web/css/css_box_model/box-shadow_generator/index.html new file mode 100644 index 0000000000..3fb264bc40 --- /dev/null +++ b/files/zh-cn/web/css/css_box_model/box-shadow_generator/index.html @@ -0,0 +1,2880 @@ +--- +title: Box-shadow generator +slug: Web/CSS/CSS_Box_Model/Box-shadow_generator +translation_of: Web/CSS/CSS_Background_and_Borders/Box-shadow_generator +--- +<p>这个可视化工具可以帮助你生成一个元素的CSS{{cssxref("box-shadow")}}相关代码,添加box shadow效果到你的CSS对象上。</p> + +<div style="display: none;"> +<h2 id="box-shadow_generator" name="box-shadow_generator">box-shadow generator</h2> + +<h3 id="HTML_Content">HTML Content</h3> + +<pre class="brush: html"><div id="container"> + <div class="group section"> + <div id="layer_manager"> + <div class="group section"> + <div class="button" data-type="add"> </div> + <div class="button" data-type="move-up"> </div> + <div class="button" data-type="move-down"> </div> + </div> + <div id="stack_container"></div> + </div> + + <div id="preview_zone"> + <div id="layer_menu" class="col span_12"> + <div class="button" id="element" data-type="subject" data-title="element"> element </div> + <div class="button" id="before" data-type="subject" data-title=":before"> + :before + <span class="delete" data-type="disable"></span> + </div> + <div class="button" id="after" data-type="subject" data-title=":after"> + :after + <span class="delete" data-type="disable"></span> + </div> + <div class="ui-checkbox" data-topic='before' data-label=":before"></div> + <div class="ui-checkbox" data-topic='after' data-label=":after"></div> + </div> + + <div id="preview"> + <div id="obj-element"> + <div class="content"> </div> + <div id="obj-before"> </div> + <div id="obj-after"> </div> + </div> + </div> + </div> + </div> + + <div id="controls" class="group section"> + <div class="wrap-left"> + <div class="colorpicker category"> + <div class="title"> </div> + <div id="colorpicker" class="group"> + <div id="gradient" class="gradient"> + <div id="gradient_picker"> </div> + </div> + <div id="hue" data-topic="hue" class="hue"> + <div id="hue_selector"> </div> + </div> + <div class="info"> + <div class="input" data-topic="hue" data-title='H:' data-action="HSV"></div> + <div class="input" data-topic="saturation" data-title='S:' data-action="HSV"></div> + <div class="input" data-topic="value" data-title='V:' data-action="HSV"></div> + </div> + <div class="alpha"> + <div id="alpha" data-topic="alpha"> + <div id="alpha_selector"> </div> + </div> + </div> + <div class="info"> + <div class="input" data-topic="r" data-title='R:' data-action="RGB"></div> + <div class="input" data-topic="g" data-title='G:' data-action="RGB"></div> + <div class="input" data-topic="b" data-title='B:' data-action="RGB"></div> + </div> + <div class="preview block"> + <div id="output_color"> </div> + </div> + <div class="block info"> + <div class="input" data-topic="a" data-title='alpha:' data-action="alpha"></div> + <div class="input" data-topic="hexa" data-title='' data-action="hexa"></div> + </div> + </div> + </div> + </div> + + <div class="wrap-right"> + + <div id="shadow_properties" class="category"> + <div class="title"> Shadow properties </div> + <div class="group"> + <div class="group property"> + <div class="ui-slider-name"> inset </div> + <div class="ui-checkbox" data-topic='inset'></div> + </div> + <div class="slidergroup"> + <div class="ui-slider-name"> Position x </div> + <div class="ui-slider-btn-set" data-topic="posX" data-type="sub"></div> + <div class="ui-slider" data-topic="posX" + data-min="-500" data-max="500" data-step="1"> </div> + <div class="ui-slider-btn-set" data-topic="posX" data-type="add"></div> + <div class="ui-slider-input" data-topic="posX" data-unit="px"></div> + </div> + <div class="slidergroup"> + <div class="ui-slider-name"> Position y </div> + <div class="ui-slider-btn-set" data-topic="posY" data-type="sub"></div> + <div class="ui-slider" data-topic="posY" + data-min="-500" data-max="500" data-step="1"> </div> + <div class="ui-slider-btn-set" data-topic="posY" data-type="add"></div> + <div class="ui-slider-input" data-topic="posY" data-unit="px"></div> + </div> + <div class="slidergroup"> + <div class="ui-slider-name"> Blur </div> + <div class="ui-slider-btn-set" data-topic="blur" data-type="sub"></div> + <div class="ui-slider" data-topic="blur" + data-min="0" data-max="200" data-step="1"> </div> + <div class="ui-slider-btn-set" data-topic="blur" data-type="add"></div> + <div class="ui-slider-input" data-topic="blur" data-unit="px"></div> + </div> + <div class="slidergroup"> + <div class="ui-slider-name"> Spread </div> + <div class="ui-slider-btn-set" data-topic="spread" data-type="sub"></div> + <div class="ui-slider" data-topic="spread" + data-min="-100" data-max="100" data-step="1" data-value="50"> + </div> + <div class="ui-slider-btn-set" data-topic="spread" data-type="add"></div> + <div class="ui-slider-input" data-topic="spread" data-unit="px"></div> + </div> + </div> + </div> + + <div id="element_properties" class="category"> + <div class="title"> Class element properties </div> + <div class="group"> + <div class="group property"> + <div class="ui-slider-name"> border </div> + <div class="ui-checkbox" data-topic='border-state' data-state="true"></div> + </div> + <div id="z-index" class="slidergroup"> + <div class="ui-slider-name"> z-index </div> + <div class="ui-slider-btn-set" data-topic="z-index" data-type="sub"></div> + <div class="ui-slider" data-topic="z-index" + data-min="-10" data-max="10" data-step="1"></div> + <div class="ui-slider-btn-set" data-topic="z-index" data-type="add"></div> + <div class="ui-slider-input" data-topic="z-index"></div> + </div> + <div class="slidergroup"> + <div class="ui-slider-name"> top </div> + <div class="ui-slider-btn-set" data-topic="top" data-type="sub"></div> + <div class="ui-slider" data-topic="top" + data-min="-500" data-max="500" data-step="1"> </div> + <div class="ui-slider-btn-set" data-topic="top" data-type="add"></div> + <div class="ui-slider-input" data-topic="top" data-unit="px"></div> + </div> + <div class="slidergroup"> + <div class="ui-slider-name"> left </div> + <div class="ui-slider-btn-set" data-topic="left" data-type="sub"></div> + <div class="ui-slider" data-topic="left" + data-min="-300" data-max="700" data-step="1"> </div> + <div class="ui-slider-btn-set" data-topic="left" data-type="add"></div> + <div class="ui-slider-input" data-topic="left" data-unit="px"></div> + </div> + <div id="transform_rotate" class="slidergroup"> + <div class="ui-slider-name"> Rotate </div> + <div class="ui-slider-btn-set" data-topic="rotate" data-type="sub"></div> + <div class="ui-slider" data-topic="rotate" + data-min="-360" data-max="360" data-step="1" data-value="0"> + </div> + <div class="ui-slider-btn-set" data-topic="rotate" data-type="add"></div> + <div class="ui-slider-input" data-topic="rotate" data-unit="deg"></div> + </div> + <div class="slidergroup"> + <div class="ui-slider-name"> Width </div> + <div class="ui-slider-btn-set" data-topic="width" data-type="sub"></div> + <div class="ui-slider" data-topic="width" + data-min="0" data-max="1000" data-step="1" data-value="200"> + </div> + <div class="ui-slider-btn-set" data-topic="width" data-type="add"></div> + <div class="ui-slider-input" data-topic="width" data-unit="px"></div> + </div> + <div class="slidergroup"> + <div class="ui-slider-name"> Height </div> + <div class="ui-slider-btn-set" data-topic="height" data-type="sub"></div> + <div class="ui-slider" data-topic="height" + data-min="0" data-max="400" data-step="1" data-value="200"> + </div> + <div class="ui-slider-btn-set" data-topic="height" data-type="add"></div> + <div class="ui-slider-input" data-topic="height" data-unit="px"></div> + </div> + </div> + </div> + + <div id="output" class="category"> + <div id="menu" class="menu"></div> + <div class="title"> CSS Code </div> + <div class="group" style="border-top-left-radius: 0;"> + <div class="output" data-topic="element" data-name="element" + data-prop="width height background-color position=[relative] box-shadow"> + </div> + <div class="output" data-topic="before" data-name="element:before" + data-prop="content=[&quot;&quot;] position=[absolute] width height top left z-index background-color box-shadow transform -webkit-transform -ms-transform"> + </div> + <div class="output" data-topic="after" data-name="element:after" + data-prop="content=[&quot;&quot;] position=[absolute] width height top left z-index background-color box-shadow transform -webkit-transform -ms-transform"> + </div> + </div> + </div> + </div> + </div> +</div> +</pre> + +<h3 id="CSS_Content">CSS Content</h3> + +<pre class="brush: css">/* GRID OF TWELVE + * ========================================================================== */ + +.span_12 { + width: 100%; +} + +.span_11 { + width: 91.46%; +} + +.span_10 { + width: 83%; +} + +.span_9 { + width: 74.54%; +} + +.span_8 { + width: 66.08%; +} + +.span_7 { + width: 57.62%; +} + +.span_6 { + width: 49.16%; +} + +.span_5 { + width: 40.7%; +} + +.span_4 { + width: 32.24%; +} + +.span_3 { + width: 23.78%; +} + +.span_2 { + width: 15.32%; +} + +.span_1 { + width: 6.86%; +} + + +/* SECTIONS + * ========================================================================== */ + +.section { + clear: both; + padding: 0px; + margin: 0px; +} + +/* GROUPING + * ========================================================================== */ + + +.group:before, .group:after { + content: ""; + display: table; +} + +.group:after { + clear:both; +} + +.group { + zoom: 1; /* For IE 6/7 (trigger hasLayout) */ +} + +/* GRID COLUMN SETUP + * ========================================================================== */ + +.col { + display: block; + float:left; + margin: 1% 0 1% 1.6%; +} + +.col:first-child { + margin-left: 0; +} /* all browsers except IE6 and lower */ + +/* + * UI Slider + */ + +.slidergroup { + height: 20px; + margin: 10px 0; + font-family: "Segoe UI", Arial, Helvetica, sans-serif; + -moz-user-select: none; + user-select: none; +} + +.slidergroup * { + float: left; + height: 100%; + line-height: 100%; +} + +/* Slider */ + +.ui-slider { + height: 10px; + width: 200px; + margin: 4px 10px; + display: block; + border: 1px solid #999; + border-radius: 3px; + background: #EEE; +} + +.ui-slider:hover { + cursor: pointer; +} + +.ui-slider-name { + width: 90px; + padding: 0 10px 0 0; + text-align: right; + text-transform: lowercase; +} + +.ui-slider-pointer { + width: 13px; + height: 13px; + background-color: #EEE; + border: 1px solid #2C9FC9; + border-radius: 3px; + position: relative; + top: -3px; + left: 0%; +} + +.ui-slider-btn-set { + width: 25px; + background-color: #2C9FC9; + border-radius: 3px; + color: #FFF; + font-weight: bold; + text-align: center; +} + +.ui-slider-btn-set:hover { + background-color: #379B4A; + cursor: pointer; +} + +.ui-slider-input > input { + margin: 0 10px; + padding: 0; + width: 50px; + text-align: center; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +/* + * UI Button + */ + +/* Checkbox */ + +.ui-checkbox { + text-align: center; + font-size: 16px; + font-family: "Segoe UI", Arial, Helvetica, sans-serif; + line-height: 1.5em; + color: #FFF; + + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.ui-checkbox > input { + display: none; +} + +.ui-checkbox > label { + font-size: 12px; + padding: 0.333em 1.666em 0.5em; + height: 1em; + line-height: 1em; + + background-color: #888; + background-image: url("https://mdn.mozillademos.org/files/5683/disabled.png"); + background-position: center center; + background-repeat: no-repeat; + + color: #FFF; + border-radius: 3px; + font-weight: bold; + float: left; +} + +.ui-checkbox .text { + padding-left: 34px; + background-position: center left 10px; +} + +.ui-checkbox .left { + padding-right: 34px; + padding-left: 1.666em; + background-position: center right 10px; +} + +.ui-checkbox > label:hover { + cursor: pointer; +} + +.ui-checkbox > input:checked + label { + background-image: url("https://mdn.mozillademos.org/files/5681/checked.png"); + background-color: #379B4A; +} + +/* + * BOX SHADOW GENERATOR TOOL + */ + +body { + max-width: 1000px; + height: 800px; + margin: 20px auto 0; + + font-family: "Segoe UI", Arial, Helvetica, sans-serif; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; +} + +#container { + width: 100%; + padding: 2px; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + + +/* container with shadows stacks */ +#stack_container { + height: 400px; + overflow: hidden; + position: relative; + border: 1px solid #CCC; + border-radius: 3px; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +#stack_container .container { + height: 100%; + width: 100%; + position: absolute; + left: 100%; + transition-property: left; + transition-duration: 0.5s; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + + +#stack_container .title { + text-align: center; + font-weight: bold; + line-height: 2em; + border-bottom: 1px solid #43A6E1; + color: #666; +} + + +/* + * Stack of Layers for shadow + */ + +#layer_manager { + width: 17%; + background-color: #FEFEFE; + margin: 0 1% 0 0; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + float: left; +} + + +#layer_manager .button { + width: 30%; + height: 25px; + margin:0 0 10px; + color: #333; + background-color: #EEE; + text-align: center; + font-size: 0.75em; + line-height: 1.5em; + border: 1px solid #CCC; + border-radius: 3px; + + display: block; + background-position: center center; + background-repeat: no-repeat; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + float: left; +} + +#layer_manager .button:hover { + background-color: #3380C4; + border: 1px solid #3380C4; + cursor: pointer; +} + +#layer_manager [data-type='add'] { + background-image: url("https://mdn.mozillademos.org/files/5685/add-black.png"); +} + +#layer_manager [data-type='add']:hover { + background-image: url("https://mdn.mozillademos.org/files/5687/add-white.png"); +} + +#layer_manager [data-type='move-up'] { + background-image: url("https://mdn.mozillademos.org/files/5697/up-black.png"); + margin-left: 5%; + margin-right: 5%; +} + +#layer_manager [data-type='move-up']:hover { + background-image: url("https://mdn.mozillademos.org/files/5709/up-white.png"); +} + +#layer_manager [data-type='move-down'] { + background-image: url("https://mdn.mozillademos.org/files/5693/down-black.png"); +} + +#layer_manager [data-type='move-down']:hover { + background-image: url("https://mdn.mozillademos.org/files/5695/down-white.png"); +} + +/* shadows classes */ + +#layer_manager .node { + width: 100%; + margin: 5px 0; + padding: 5px; + text-align: center; + background-color: #EEE; + border: 1px solid #DDD; + font-size: 0.75em; + line-height: 1.5em; + color: #333; + border-radius: 3px; + + position: relative; + display: block; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +#layer_manager .node:hover { + color: #FFF; + background-color: #3380C4; + cursor: pointer; +} + +/* active element styling */ + +#layer_manager [data-active='layer'] { + color: #FFF; + border: none; + background-color: #379B4A; +} + +#layer_manager [data-active='subject'] { + color: #FFF; + background-color: #467FC9; +} + +/* delete button */ + +#layer_manager .delete { + width: 1.5em; + height: 100%; + float: right; + border-radius: 3px; + background-image: url("https://mdn.mozillademos.org/files/5689/delete-white.png"); + background-position: center center; + background-repeat: no-repeat; + position: absolute; + top: 0; + right: 10px; + display: none; +} + +#layer_manager .delete:hover { + background-image: url("https://mdn.mozillademos.org/files/5691/delete-yellow.png"); +} + +#layer_manager .node:hover .delete { + display: block; +} + + +#layer_manager .stack { + padding: 0 5px; + max-height: 90%; + overflow: auto; + overflow-x: hidden; +} + + +/* + * Layer Menu + */ + +#layer_menu { + margin: 0 0 10px 0; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +#layer_menu .button { + width: 100px; + margin: 0 5px 0 0; + padding: 2.5px; + color: #333; + background-color: #EEE; + border: 1px solid #CCC; + border-radius: 3px; + text-align: center; + font-size: 0.75em; + line-height: 1.5em; + + position: relative; + display: block; + float: left; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +#layer_menu .button:hover { + color: #FFF; + background-color: #3380C4; + border: 1px solid #3380C4; + cursor: pointer; +} + +#layer_menu .delete { + width: 1.5em; + height: 100%; + float: right; + border-radius: 3px; + background-image: url("https://mdn.mozillademos.org/files/5689/delete-white.png"); + background-position: center center; + background-repeat: no-repeat; + position: absolute; + top: 0; + right: 5px; + display: none; +} + +#layer_menu .delete:hover { + background-image: url("https://mdn.mozillademos.org/files/5691/delete-yellow.png"); +} + +#layer_menu .button:hover .delete { + display: block; +} + + +/* + * active element styling + */ + +#layer_menu [data-active='subject'] { + color: #FFF; + background-color: #379B4A; + border: 1px solid #379B4A; +} + + +/* Checkbox */ + +#layer_menu .ui-checkbox > label { + height: 15px; + line-height: 17px; + font-weight: normal; + width: 46px; + margin: 0 5px 0 0; +} + +#layer_menu .ui-checkbox > input:checked + label { + display: none; +} + + +/******************************************************************************/ +/******************************************************************************/ +/* + * Preview Area + */ + +#preview_zone { + width: 82%; + float: left; + +} + + +#preview { + width: 100%; + height: 400px; + border: 1px solid #CCC; + border-radius: 3px; + text-align: center; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + cursor: move; + float: left; +} + +#preview .content { + width: 100%; + height: 100%; + display: block; +} + +#obj-element { + width: 300px; + height: 100px; + border: 1px solid #CCC; + background: #FFF; + position: relative; +} + + +#obj-before { + height: 100%; + width: 100%; + background: #999; + border: 1px solid #CCC; + text-align: left; + display : block; + position: absolute; + z-index: -1; +} + +#obj-after { + height: 100%; + width: 100%; + background: #DDD; + border: 1px solid #CCC; + text-align: right; + display : block; + position: absolute; + z-index: -1; +} + + +/******************************************************************************/ +/******************************************************************************/ + +/** + * Controls + */ + +.wrap-left { + float: left; + overflow: hidden; +} + +.wrap-right { + float: right; + overflow: hidden; +} + +.wrap-left > * { + float: left; +} + +.wrap-right > * { + float: right; +} + +@media (min-width: 960px) { + + .wrap-left { + width: 45%; + } + + .wrap-right { + width: 55%; + } +} + + +@media (max-width: 959px) { + + .wrap-left { + width: 30%; + } + + .wrap-right { + width: 70%; + } +} + + +#controls { + color: #444; + margin: 10px 0 0 0; +} + + +#controls .category { + width: 500px; + margin: 0 auto 20px; + padding: 0; + +} + +#controls .category .title { + width: 100%; + height: 1.5em; + line-height: 1.5em; + color: #AAA; + text-align: right; +} + +#controls .category > .group { + border: 1px solid #CCC; + border-radius: 3px; +} + + +/** + * Color Picker + */ + +@media (min-width: 960px) { + #controls .colorpicker { + width: 420px; + } +} + +@media (max-width: 959px) { + #controls .colorpicker { + width: 210px; + } +} + +#colorpicker { + width: 100%; + margin: 0 auto; +} + +#colorpicker .gradient { + width: 200px; + height: 200px; + margin: 5px; + background: url("https://mdn.mozillademos.org/files/5707/picker_mask_200.png"); + background: -moz-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%), + -moz-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%); + background: -webkit-linear-gradient(bottom, #000 0%, rgba(0, 0, 0, 0) 100%), + -webkit-linear-gradient(left, #FFF 0%, rgba(255, 255, 255, 0) 100%); + background-color: #F00; + float: left; +} + +#colorpicker .hue { + width: 200px; + height: 30px; + margin: 5px; + background: url("https://mdn.mozillademos.org/files/5701/hue.png"); + background: -moz-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%, + #00F 66.66%, #F0F 83.33%, #F00 100%); + background: -webkit-linear-gradient(left, #F00 0%, #FF0 16.66%, #0F0 33.33%, #0FF 50%, + #00F 66.66%, #F0F 83.33%, #F00 100%); + float: left; +} + +#colorpicker .alpha { + width: 200px; + height: 30px; + margin: 5px; + border: 1px solid #CCC; + float: left; + background: url("https://mdn.mozillademos.org/files/5705/alpha.png"); + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +#colorpicker #alpha { + width: 100%; + height: 100%; + background: url("https://mdn.mozillademos.org/files/5703/alpha_mask.png"); + background: -moz-linear-gradient(left, rgba(255, 0, 0, 0) 0%, rgba(255, 0, 0, 1) 100%); +} + +#colorpicker #gradient_picker { + width: 0.5em; + height: 0.5em; + border-radius: 0.4em; + border: 2px solid #CCC; + position: relative; + top: 20%; + left: 20%; +} + +#colorpicker #hue_selector, +#colorpicker #alpha_selector { + width: 3px; + height: 100%; + border: 1px solid #777; + background-color: #FFF; + position: relative; + top: -1px; + left: 0%; +} + +/* input HSV and RGB */ +#colorpicker .info { + width: 200px; + margin: 5px; + float: left; +} + +#colorpicker .info * { + float: left; +} + +#colorpicker .info input { + margin: 0; + text-align: center; + width: 30px; + -moz-user-select: text; + -webkit-user-select: text; + -ms-user-select: text; +} + +#colorpicker .info span { + height: 20px; + width: 30px; + text-align: center; + line-height: 20px; + display: block; +} + +/* Preview color */ +#colorpicker .block { + width: 95px; + height: 54px; + float: left; + position: relative; +} + +#colorpicker .preview { + margin: 5px; + border: 1px solid #CCC; + background-image: url("https://mdn.mozillademos.org/files/5705/alpha.png"); + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +#colorpicker .preview:before { + height: 100%; + width: 50%; + left: 50%; + content: ""; + background: #FFF; + position: absolute; + z-index: 1; +} + +#colorpicker .preview > * { + width: 50%; + height: 100%; +} + +#colorpicker #output_color { + width: 100%; + height: 100%; + position: absolute; + z-index: 2; +} + +#colorpicker .block .input { + float: right; +} + +#colorpicker [data-topic="a"] > span { + width: 50px; +} + +#colorpicker [data-topic="hexa"] { + float: right; + margin: 10px 0 0 0; +} + +#colorpicker [data-topic="hexa"] > span { + display: none; +} + +#colorpicker [data-topic="hexa"] > input { + width: 85px; + padding: 2px 0; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + + +/* + * UI Components + */ + +/* Property */ + +.property { + height: 20px; + margin: 10px 0; +} + +.property * { + float: left; + height: 100%; + line-height: 100%; +} + +/* Slider */ + +#controls .ui-slider-name { + margin: 0 10px 0 0; +} + +/* + * Output code styling + */ + +#output { + position: relative; +} + +#output .menu { + max-width: 70%; + height: 20px; + position: absolute; + top: 2px; +} + +#output .button { + width: 90px; + height: 22px; + margin: 0 5px 0 0; + text-align: center; + line-height: 20px; + font-size: 14px; + color: #FFF; + background-color: #999; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + bottom: -5px; + float:left; +} + +#output .button:hover { + color: #FFF; + background-color: #666; + cursor: pointer; +} + +#output .menu [data-active="true"] { + color: #777; + background-color: #FFF; + border: 1px solid #CCC; + border-bottom: none; +} + +#output .menu [data-topic="before"] { + left: 100px; +} + +#output .menu [data-topic="after"] { + left: 200px; +} + +#output .output { + width: 480px; + margin: 10px; + padding: 10px; + overflow: hidden; + color: #555; + font-size: 14px; + border: 1px dashed #CCC; + border-radius: 3px; + display: none; + + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + + -moz-user-select: text; + -webkit-user-select: text; + -ms-user-select: text; +} + +#output .css-property { + width: 100%; + float: left; + white-space: pre; +} + +#output .name { + width: 35%; + float: left; +} + +#output .value { + width: 65%; + float: left; +} + +</pre> + +<h3 id="JavaScript_Content">JavaScript Content</h3> + +<pre class="brush: js"><code class="language-js"> + +'use strict'; + +/** + * UI-SlidersManager + */ + +var SliderManager = (function SliderManager() { + + var subscribers = {}; + var sliders = []; + + var Slider = function(node) { + var min = node.getAttribute('data-min') | 0; + var max = node.getAttribute('data-max') | 0; + var step = node.getAttribute('data-step') | 0; + var value = node.getAttribute('data-value') | 0; + var snap = node.getAttribute('data-snap'); + var topic = node.getAttribute('data-topic'); + + this.min = min; + this.max = max > 0 ? max : 100; + this.step = step === 0 ? 1 : step; + this.value = value <= max && value >= min ? value : (min + max) / 2 | 0; + this.snap = snap === "true" ? true : false; + this.topic = topic; + this.node = node; + + var pointer = document.createElement('div'); + pointer.className = 'ui-slider-pointer'; + node.appendChild(pointer); + this.pointer = pointer; + + setMouseTracking(node, updateSlider.bind(this)); + + sliders[topic] = this; + setValue(topic, this.value); + } + + var setButtonComponent = function setButtonComponent(node) { + var type = node.getAttribute('data-type'); + var topic = node.getAttribute('data-topic'); + if (type === "sub") { + node.textContent = '-'; + node.addEventListener("click", function() { + decrement(topic); + }); + } + if (type === "add") { + node.textContent = '+'; + node.addEventListener("click", function() { + increment(topic); + }); + } + } + + var setInputComponent = function setInputComponent(node) { + var topic = node.getAttribute('data-topic'); + var unit_type = node.getAttribute('data-unit'); + + var input = document.createElement('input'); + var unit = document.createElement('span'); + unit.textContent = unit_type; + + input.setAttribute('type', 'text'); + node.appendChild(input); + node.appendChild(unit); + + input.addEventListener('click', function(e) { + this.select(); + }); + + input.addEventListener('change', function(e) { + setValue(topic, e.target.value | 0); + }); + + subscribe(topic, function(value) { + node.children[0].value = value; + }); + } + + var increment = function increment(topic) { + var slider = sliders[topic]; + if (slider === null || slider === undefined) + return; + + if (slider.value + slider.step <= slider.max) { + slider.value += slider.step; + setValue(slider.topic, slider.value) + notify.call(slider); + } + }; + + var decrement = function decrement(topic) { + var slider = sliders[topic]; + if (slider === null || slider === undefined) + return; + + if (slider.value - slider.step >= slider.min) { + slider.value -= slider.step; + setValue(topic, slider.value) + notify.call(slider); + } + } + + // this = Slider object + var updateSlider = function updateSlider(e) { + var node = this.node; + var pos = e.pageX - node.offsetLeft; + var width = node.clientWidth; + var delta = this.max - this.min; + var offset = this.pointer.clientWidth + 4; // border width * 2 + + if (pos < 0) pos = 0; + if (pos > width) pos = width; + + var value = pos * delta / width | 0; + var precision = value % this.step; + value = value - precision + this.min; + if (precision > this.step / 2) + value = value + this.step; + + if (this.snap) + pos = (value - this.min) * width / delta; + + this.pointer.style.left = pos - offset/2 + "px"; + this.value = value; + node.setAttribute('data-value', value); + notify.call(this); + } + + var setValue = function setValue(topic, value) { + var slider = sliders[topic]; + + if (value > slider.max || value < slider.min) + return; + + var delta = slider.max - slider.min; + var width = slider.node.clientWidth; + var offset = slider.pointer.clientWidth; + var pos = (value - slider.min) * width / delta; + slider.value = value; + slider.pointer.style.left = pos - offset / 2 + "px"; + slider.node.setAttribute('data-value', value); + notify.call(slider); + } + + var setMouseTracking = function setMouseTracking(elem, callback) { + elem.addEventListener("mousedown", function(e) { + callback(e); + document.addEventListener("mousemove", callback); + }); + + document.addEventListener("mouseup", function(e) { + document.removeEventListener("mousemove", callback); + }); + } + + var subscribe = function subscribe(topic, callback) { + if (subscribers[topic] === undefined) + subscribers[topic] = []; + subscribers[topic].push(callback); + } + + var unsubscribe = function unsubscribe(topic, callback) { + subscribers[topic].indexOf(callback); + subscribers[topic].splice(index, 1); + } + + var notify = function notify() { + if (subscribers[this.topic] === undefined) + return; + + for (var i in subscribers[this.topic]) { + subscribers[this.topic][i](this.value); + } + } + + var init = function init() { + var elem, size; + + elem = document.querySelectorAll('.ui-slider-btn-set'); + size = elem.length; + for (var i = 0; i < size; i++) + setButtonComponent(elem[i]); + + elem = document.querySelectorAll('.ui-slider-input'); + size = elem.length; + for (var i = 0; i < size; i++) + setInputComponent(elem[i]); + + elem = document.querySelectorAll('.ui-slider'); + size = elem.length; + for (var i = 0; i < size; i++) + new Slider(elem[i]); + } + + return { + init : init, + setValue : setValue, + subscribe : subscribe, + unsubscribe : unsubscribe + } + +})(); + +/** + * UI-ButtonManager + */ + +var ButtonManager = (function CheckBoxManager() { + + var subscribers = []; + var buttons = []; + + var CheckBox = function CheckBox(node) { + var topic = node.getAttribute('data-topic'); + var state = node.getAttribute('data-state'); + var name = node.getAttribute('data-label'); + var align = node.getAttribute('data-text-on'); + + state = (state === "true"); + + var checkbox = document.createElement("input"); + var label = document.createElement("label"); + + var id = 'checkbox-' + topic; + checkbox.id = id; + checkbox.setAttribute('type', 'checkbox'); + checkbox.checked = state; + + label.setAttribute('for', id); + if (name) { + label.className = 'text'; + if (align) + label.className += ' ' + align; + label.textContent = name; + } + + node.appendChild(checkbox); + node.appendChild(label); + + this.node = node; + this.topic = topic; + this.checkbox = checkbox; + + checkbox.addEventListener('change', function(e) { + notify.call(this); + }.bind(this)); + + buttons[topic] = this; + } + + var getNode = function getNode(topic) { + return buttons[topic].node; + } + + var setValue = function setValue(topic, value) { + try { + buttons[topic].checkbox.checked = value; + notify.call(buttons[topic]); + } + catch(error) { + console.log(error, topic, value); + } + } + + var subscribe = function subscribe(topic, callback) { + if (subscribers[topic] === undefined) + subscribers[topic] = []; + + subscribers[topic].push(callback); + } + + var unsubscribe = function unsubscribe(topic, callback) { + subscribers[topic].indexOf(callback); + subscribers[topic].splice(index, 1); + } + + var notify = function notify() { + if (subscribers[this.topic] === undefined) + return; + for (var i = 0; i < subscribers[this.topic].length; i++) + subscribers[this.topic][i](this.checkbox.checked); + } + + var init = function init() { + var elem = document.querySelectorAll('.ui-checkbox'); + var size = elem.length; + for (var i = 0; i < size; i++) + new CheckBox(elem[i]); + } + + return { + init : init, + setValue : setValue, + subscribe : subscribe, + unsubscribe : unsubscribe + } + +})(); + + +window.addEventListener("load", function(){ + BoxShadow.init(); +}); + +var BoxShadow = (function BoxShadow() { + + function getElemById(id) { + return document.getElementById(id); + } + + /** + * RGBA Color class + */ + + function Color() { + this.r = 0; + this.g = 0; + this.b = 0; + this.a = 1; + this.hue = 0; + this.saturation = 0; + this.value = 0; + } + + Color.prototype.copy = function copy(obj) { + if(obj instanceof Color !== true) { + console.log("Typeof instance not Color"); + return; + } + + this.r = obj.r; + this.g = obj.g; + this.b = obj.b; + this.a = obj.a; + this.hue = obj.hue; + this.saturation = obj.saturation; + this.value = obj.value; + } + + Color.prototype.setRGBA = function setRGBA(red, green, blue, alpha) { + if (red != undefined) + this.r = red | 0; + if (green != undefined) + this.g = green | 0; + if (blue != undefined) + this.b = blue | 0; + if (alpha != undefined) + this.a = alpha | 0; + } + + /** + * HSV/HSB (hue, saturation, value / brightness) + * @param hue 0-360 + * @param saturation 0-100 + * @param value 0-100 + */ + Color.prototype.setHSV = function setHSV(hue, saturation, value) { + this.hue = hue; + this.saturation = saturation; + this.value = value; + this.updateRGB(); + } + + Color.prototype.updateRGB = function updateRGB() { + var sat = this.saturation / 100; + var value = this.value / 100; + var C = sat * value; + var H = this.hue / 60; + var X = C * (1 - Math.abs(H % 2 - 1)); + var m = value - C; + var precision = 255; + + C = (C + m) * precision; + X = (X + m) * precision; + m = m * precision; + + if (H >= 0 && H < 1) { this.setRGBA(C, X, m); return; } + if (H >= 1 && H < 2) { this.setRGBA(X, C, m); return; } + if (H >= 2 && H < 3) { this.setRGBA(m, C, X); return; } + if (H >= 3 && H < 4) { this.setRGBA(m, X, C); return; } + if (H >= 4 && H < 5) { this.setRGBA(X, m, C); return; } + if (H >= 5 && H < 6) { this.setRGBA(C, m, X); return; } + } + + Color.prototype.updateHSV = function updateHSV() { + var red = this.r / 255; + var green = this.g / 255; + var blue = this.b / 255; + + var cmax = Math.max(red, green, blue); + var cmin = Math.min(red, green, blue); + var delta = cmax - cmin; + var hue = 0; + var saturation = 0; + + if (delta) { + if (cmax === red ) { hue = ((green - blue) / delta); } + if (cmax === green ) { hue = 2 + (blue - red) / delta; } + if (cmax === blue ) { hue = 4 + (red - green) / delta; } + if (cmax) saturation = delta / cmax; + } + + this.hue = 60 * hue | 0; + if (this.hue < 0) this.hue += 360; + this.saturation = (saturation * 100) | 0; + this.value = (cmax * 100) | 0; + } + + Color.prototype.setHexa = function setHexa(value) { + var valid = /(^#{0,1}[0-9A-F]{6}$)|(^#{0,1}[0-9A-F]{3}$)/i.test(value) + if (valid !== true) + return; + + if (value[0] === '#') + value = value.slice(1, value.length); + + if (value.length === 3) + value = value.replace(/([0-9A-F])([0-9A-F])([0-9A-F])/i,"$1$1$2$2$3$3"); + + this.r = parseInt(value.substr(0, 2), 16); + this.g = parseInt(value.substr(2, 2), 16); + this.b = parseInt(value.substr(4, 2), 16); + + this.alpha = 1; + } + + Color.prototype.getHexa = function getHexa() { + var r = this.r.toString(16); + var g = this.g.toString(16); + var b = this.b.toString(16); + if (this.r < 16) r = '0' + r; + if (this.g < 16) g = '0' + g; + if (this.b < 16) b = '0' + b; + var value = '#' + r + g + b; + return value.toUpperCase(); + } + + Color.prototype.getRGBA = function getRGBA() { + + var rgb = "(" + this.r + ", " + this.g + ", " + this.b; + var a = ''; + var v = ''; + if (this.a !== 1) { + a = 'a'; + v = ', ' + this.a; + } + + var value = "rgb" + a + rgb + v + ")"; + return value; + } + + Color.prototype.getColor = function getColor() { + if (this.a | 0 === 1) + return this.getHexa(); + return this.getRGBA(); + } + + /** + * Shadow Object + */ + function Shadow() { + this.inset = false; + this.posX = 5; + this.posY = -5; + this.blur = 5; + this.spread = 0; + this.color = new Color(); + + var hue = (Math.random() * 360) | 0; + var saturation = (Math.random() * 75) | 0; + var value = (Math.random() * 50 + 50) | 0; + this.color.setHSV(hue, saturation, value, 1); + } + + Shadow.prototype.computeCSS = function computeCSS() { + var value = ""; + if (this.inset === true) + value += "inset "; + value += this.posX + "px "; + value += this.posY + "px "; + value += this.blur + "px "; + value += this.spread + "px "; + value += this.color.getColor(); + + return value; + } + + Shadow.prototype.toggleInset = function toggleInset(value) { + if (value !== undefined || typeof value === "boolean") + this.inset = value; + else + this.inset = this.inset === true ? false : true; + } + + Shadow.prototype.copy = function copy(obj) { + if(obj instanceof Shadow !== true) { + console.log("Typeof instance not Shadow"); + return; + } + + this.inset = obj.inset; + this.posX = obj.posX; + this.posY = obj.posY; + this.blur = obj.blur; + this.spread = obj.spread; + this.color.copy(obj.color); + } + + /** + * Color Picker + */ + var ColoPicker = (function ColoPicker() { + + var colorpicker; + var hue_area; + var gradient_area; + var alpha_area; + var gradient_picker; + var hue_selector; + var alpha_selector; + var pick_object; + var info_rgb; + var info_hsv; + var info_hexa; + var output_color; + var color = new Color(); + var subscribers = []; + + var updateColor = function updateColor(e) { + var x = e.pageX - gradient_area.offsetLeft; + var y = e.pageY - gradient_area.offsetTop; + + // width and height should be the same + var size = gradient_area.clientWidth; + + if (x > size) + x = size; + if (y > size) + y = size; + + if (x < 0) x = 0; + if (y < 0) y = 0; + + var value = 100 - (y * 100 / size) | 0; + var saturation = x * 100 / size | 0; + + color.setHSV(color.hue, saturation, value); + // should update just + // color pointer location + updateUI(); + notify("color", color); + } + + var updateHue = function updateHue(e) { + var x = e.pageX - hue_area.offsetLeft; + var width = hue_area.clientWidth; + + if (x < 0) x = 0; + if (x > width) x = width; + + var hue = ((360 * x) / width) | 0; + if (hue === 360) hue = 359; + + color.setHSV(hue, color.saturation, color.value); + + // should update just + // hue pointer location + // picker area background + // alpha area background + updateUI(); + notify("color", color); + } + + var updateAlpha = function updateAlpha(e) { + var x = e.pageX - alpha_area.offsetLeft; + var width = alpha_area.clientWidth; + + if (x < 0) x = 0; + if (x > width) x = width; + + color.a = (x / width).toFixed(2); + + // should update just + // alpha pointer location + updateUI(); + notify("color", color); + } + + var setHueGfx = function setHueGfx(hue) { + var sat = color.saturation; + var val = color.value; + var alpha = color.a; + + color.setHSV(hue, 100, 100); + gradient_area.style.backgroundColor = color.getHexa(); + + color.a = 0; + var start = color.getRGBA(); + color.a = 1; + var end = color.getRGBA(); + color.a = alpha; + + var gradient = '-moz-linear-gradient(left, ' + start + '0%, ' + end + ' 100%)'; + alpha_area.style.background = gradient; + } + + var updateUI = function updateUI() { + var x, y; // coordinates + var size; // size of the area + var offset; // pointer graphic selector offset + + // Set color pointer location + size = gradient_area.clientWidth; + offset = gradient_picker.clientWidth / 2 + 2; + + x = (color.saturation * size / 100) | 0; + y = size - (color.value * size / 100) | 0; + + gradient_picker.style.left = x - offset + "px"; + gradient_picker.style.top = y - offset + "px"; + + // Set hue pointer location + size = hue_area.clientWidth; + offset = hue_selector.clientWidth/2; + x = (color.hue * size / 360 ) | 0; + hue_selector.style.left = x - offset + "px"; + + // Set alpha pointer location + size = alpha_area.clientWidth; + offset = alpha_selector.clientWidth/2; + x = (color.a * size) | 0; + alpha_selector.style.left = x - offset + "px"; + + // Set picker area background + var nc = new Color(); + nc.copy(color); + if (nc.hue === 360) nc.hue = 0; + nc.setHSV(nc.hue, 100, 100); + gradient_area.style.backgroundColor = nc.getHexa(); + + // Set alpha area background + nc.copy(color); + nc.a = 0; + var start = nc.getRGBA(); + nc.a = 1; + var end = nc.getRGBA(); + var gradient = '-moz-linear-gradient(left, ' + start + '0%, ' + end + ' 100%)'; + alpha_area.style.background = gradient; + + // Update color info + notify("color", color); + notify("hue", color.hue); + notify("saturation", color.saturation); + notify("value", color.value); + notify("r", color.r); + notify("g", color.g); + notify("b", color.b); + notify("a", color.a); + notify("hexa", color.getHexa()); + output_color.style.backgroundColor = color.getRGBA(); + } + + var setInputComponent = function setInputComponent(node) { + var topic = node.getAttribute('data-topic'); + var title = node.getAttribute('data-title'); + var action = node.getAttribute('data-action'); + title = title === null ? '' : title; + + var input = document.createElement('input'); + var info = document.createElement('span'); + info.textContent = title; + + input.setAttribute('type', 'text'); + input.setAttribute('data-action', 'set-' + action + '-' + topic); + node.appendChild(info); + node.appendChild(input); + + input.addEventListener('click', function(e) { + this.select(); + }); + + input.addEventListener('change', function(e) { + if (action === 'HSV') + inputChangeHSV(topic); + if (action === 'RGB') + inputChangeRGB(topic); + if (action === 'alpha') + inputChangeAlpha(topic); + if (action === 'hexa') + inputChangeHexa(topic); + }); + + subscribe(topic, function(value) { + node.children[1].value = value; + }); + } + + var inputChangeHSV = function actionHSV(topic) { + var selector = "[data-action='set-HSV-" + topic + "']"; + var node = document.querySelector("#colorpicker " + selector); + var value = parseInt(node.value); + + if (typeof value === 'number' && isNaN(value) === false && + value >= 0 && value < 360) + color[topic] = value; + + color.updateRGB(); + updateUI(); + } + + var inputChangeRGB = function inputChangeRGB(topic) { + var selector = "[data-action='set-RGB-" + topic + "']"; + var node = document.querySelector("#colorpicker " + selector); + var value = parseInt(node.value); + + if (typeof value === 'number' && isNaN(value) === false && + value >= 0 && value <= 255) + color[topic] = value; + + color.updateHSV(); + updateUI(); + } + + var inputChangeAlpha = function inputChangeAlpha(topic) { + var selector = "[data-action='set-alpha-" + topic + "']"; + var node = document.querySelector("#colorpicker " + selector); + var value = parseFloat(node.value); + + if (typeof value === 'number' && isNaN(value) === false && + value >= 0 && value <= 1) + color.a = value.toFixed(2); + + updateUI(); + } + + var inputChangeHexa = function inputChangeHexa(topic) { + var selector = "[data-action='set-hexa-" + topic + "']"; + var node = document.querySelector("#colorpicker " + selector); + var value = node.value; + color.setHexa(value); + color.updateHSV(); + updateUI(); + } + + var setMouseTracking = function setMouseTracking(elem, callback) { + + elem.addEventListener("mousedown", function(e) { + callback(e); + document.addEventListener("mousemove", callback); + }); + + document.addEventListener("mouseup", function(e) { + document.removeEventListener("mousemove", callback); + }); + } + + /* + * Observer + */ + var setColor = function setColor(obj) { + if(obj instanceof Color !== true) { + console.log("Typeof instance not Color"); + return; + } + color.copy(obj); + updateUI(); + } + + var subscribe = function subscribe(topic, callback) { + if (subscribers[topic] === undefined) + subscribers[topic] = []; + + subscribers[topic].push(callback); + } + + var unsubscribe = function unsubscribe(callback) { + subscribers.indexOf(callback); + subscribers.splice(index, 1); + } + + var notify = function notify(topic, value) { + for (var i in subscribers[topic]) + subscribers[topic][i](value); + } + + var init = function init() { + colorpicker = getElemById("colorpicker"); + hue_area = getElemById("hue"); + gradient_area = getElemById("gradient"); + alpha_area = getElemById("alpha"); + gradient_picker = getElemById("gradient_picker"); + hue_selector = getElemById("hue_selector"); + alpha_selector = getElemById("alpha_selector"); + output_color = getElemById("output_color"); + + var elem = document.querySelectorAll('#colorpicker .input'); + var size = elem.length; + for (var i = 0; i < size; i++) + setInputComponent(elem[i]); + + setMouseTracking(gradient_area, updateColor); + setMouseTracking(hue_area, updateHue); + setMouseTracking(alpha_area, updateAlpha); + + } + + return { + init : init, + setColor : setColor, + subscribe : subscribe, + unsubscribe : unsubscribe + } + + })(); + + /** + * Shadow dragging + */ + var PreviewMouseTracking = (function Drag() { + var active = false; + var lastX = 0; + var lastY = 0; + var subscribers = []; + + var init = function init(id) { + var elem = getElemById(id); + elem.addEventListener('mousedown', dragStart, false); + document.addEventListener('mouseup', dragEnd, false); + } + + var dragStart = function dragStart(e) { + if (e.button !== 0) + return; + + active = true; + lastX = e.clientX; + lastY = e.clientY; + document.addEventListener('mousemove', mouseDrag, false); + } + + var dragEnd = function dragEnd(e) { + if (e.button !== 0) + return; + + if (active === true) { + active = false; + document.removeEventListener('mousemove', mouseDrag, false); + } + } + + var mouseDrag = function mouseDrag(e) { + notify(e.clientX - lastX, e.clientY - lastY); + lastX = e.clientX; + lastY = e.clientY; + } + + var subscribe = function subscribe(callback) { + subscribers.push(callback); + } + + var unsubscribe = function unsubscribe(callback) { + var index = subscribers.indexOf(callback); + subscribers.splice(index, 1); + } + + var notify = function notify(deltaX, deltaY) { + for (var i in subscribers) + subscribers[i](deltaX, deltaY); + } + + return { + init : init, + subscribe : subscribe, + unsubscribe : unsubscribe + } + + })(); + + /* + * Element Class + */ + var CssClass = function CssClass(id) { + this.left = 0; + this.top = 0; + this.rotate = 0; + this.width = 300; + this.height = 100; + this.display = true; + this.border = true; + this.zIndex = -1; + this.bgcolor = new Color(); + this.id = id; + this.node = getElemById('obj-' + id); + this.object = getElemById(id); + this.shadowID = null; + this.shadows = [] + this.render = []; + this.init(); + } + + CssClass.prototype.init = function init() { + this.left = ((this.node.parentNode.clientWidth - this.node.clientWidth) / 2) | 0; + this.top = ((this.node.parentNode.clientHeight - this.node.clientHeight) / 2) | 0; + + this.setTop(this.top); + this.setLeft(this.left); + this.setHeight(this.height); + this.setWidth(this.width); + this.bgcolor.setHSV(0, 0, 100); + this.updateBgColor(this.bgcolor); + } + + CssClass.prototype.updatePos = function updatePos(deltaX, deltaY) { + this.left += deltaX; + this.top += deltaY; + this.node.style.top = this.top + "px"; + this.node.style.left = this.left + "px"; + SliderManager.setValue("left", this.left); + SliderManager.setValue("top", this.top); + } + + CssClass.prototype.setLeft = function setLeft(value) { + this.left = value; + this.node.style.left = this.left + "px"; + OutputManager.updateProperty(this.id, 'left', this.left + 'px'); + } + + CssClass.prototype.setTop = function setTop(value) { + this.top = value; + this.node.style.top = this.top + 'px'; + OutputManager.updateProperty(this.id, 'top', this.top + 'px'); + } + + CssClass.prototype.setWidth = function setWidth(value) { + this.width = value; + this.node.style.width = this.width + 'px'; + OutputManager.updateProperty(this.id, 'width', this.width + 'px'); + } + + CssClass.prototype.setHeight = function setHeight(value) { + this.height = value; + this.node.style.height = this.height + 'px'; + OutputManager.updateProperty(this.id, 'height', this.height + 'px'); + } + + // Browser support + CssClass.prototype.setRotate = function setRotate(value) { + var cssvalue = 'rotate(' + value +'deg)'; + + this.node.style.transform = cssvalue; + this.node.style.webkitTransform = cssvalue; + this.node.style.msTransform = cssvalue; + + if (value !== 0) { + if (this.rotate === 0) { + OutputManager.toggleProperty(this.id, 'transform', true); + OutputManager.toggleProperty(this.id, '-webkit-transform', true); + OutputManager.toggleProperty(this.id, '-ms-transform', true); + } + } + else { + OutputManager.toggleProperty(this.id, 'transform', false); + OutputManager.toggleProperty(this.id, '-webkit-transform', false); + OutputManager.toggleProperty(this.id, '-ms-transform', false); + } + + OutputManager.updateProperty(this.id, 'transform', cssvalue); + OutputManager.updateProperty(this.id, '-webkit-transform', cssvalue); + OutputManager.updateProperty(this.id, '-ms-transform', cssvalue); + this.rotate = value; + } + + CssClass.prototype.setzIndex = function setzIndex(value) { + this.node.style.zIndex = value; + OutputManager.updateProperty(this.id, 'z-index', value); + this.zIndex = value; + } + + CssClass.prototype.toggleDisplay = function toggleDisplay(value) { + if (typeof value !== "boolean" || this.display === value) + return; + + this.display = value; + var display = this.display === true ? "block" : "none"; + this.node.style.display = display; + this.object.style.display = display; + } + + CssClass.prototype.toggleBorder = function toggleBorder(value) { + if (typeof value !== "boolean" || this.border === value) + return; + + this.border = value; + var border = this.border === true ? "1px solid #CCC" : "none"; + this.node.style.border = border; + } + + CssClass.prototype.updateBgColor = function updateBgColor(color) { + this.bgcolor.copy(color); + this.node.style.backgroundColor = color.getColor(); + OutputManager.updateProperty(this.id, 'background-color', color.getColor()); + } + + CssClass.prototype.updateShadows = function updateShadows() { + if (this.render.length === 0) + OutputManager.toggleProperty(this.id, 'box-shadow', false); + if (this.render.length === 1) + OutputManager.toggleProperty(this.id, 'box-shadow', true); + + this.node.style.boxShadow = this.render.join(", "); + OutputManager.updateProperty(this.id, 'box-shadow', this.render.join(", \n")); + + } + + + /** + * Tool Manager + */ + var Tool = (function Tool() { + + var preview; + var classes = []; + var active = null; + var animate = false; + + /* + * Toll actions + */ + var addCssClass = function addCssClass(id) { + classes[id] = new CssClass(id); + } + + var setActiveClass = function setActiveClass(id) { + active = classes[id]; + active.shadowID = null; + ColoPicker.setColor(classes[id].bgcolor); + SliderManager.setValue("top", active.top); + SliderManager.setValue("left", active.left); + SliderManager.setValue("rotate", active.rotate); + SliderManager.setValue("z-index", active.zIndex); + SliderManager.setValue("width", active.width); + SliderManager.setValue("height", active.height); + ButtonManager.setValue("border-state", active.border); + active.updateShadows(); + } + + var disableClass = function disableClass(topic) { + classes[topic].toggleDisplay(false); + ButtonManager.setValue(topic, false); + } + + var addShadow = function addShadow(position) { + if (animate === true) + return -1; + + active.shadows.splice(position, 0, new Shadow()); + active.render.splice(position, 0, null); + } + + var swapShadow = function swapShadow(id1, id2) { + var x = active.shadows[id1]; + active.shadows[id1] = active.shadows[id2]; + active.shadows[id2] = x; + updateShadowCSS(id1); + updateShadowCSS(id2); + } + + var deleteShadow = function deleteShadow(position) { + active.shadows.splice(position, 1); + active.render.splice(position, 1); + active.updateShadows(); + } + + var setActiveShadow = function setActiveShadow(id, glow) { + active.shadowID = id; + ColoPicker.setColor(active.shadows[id].color); + ButtonManager.setValue("inset", active.shadows[id].inset); + SliderManager.setValue("blur", active.shadows[id].blur); + SliderManager.setValue("spread", active.shadows[id].spread); + SliderManager.setValue("posX", active.shadows[id].posX); + SliderManager.setValue("posY", active.shadows[id].posY); + if (glow === true) + addGlowEffect(id); + } + + var addGlowEffect = function addGlowEffect(id) { + if (animate === true) + return; + + animate = true; + var store = new Shadow(); + var shadow = active.shadows[id]; + + store.copy(shadow); + shadow.color.setRGBA(40, 125, 200, 1); + shadow.blur = 10; + shadow.spread = 10; + + active.node.style.transition = "box-shadow 0.2s"; + updateShadowCSS(id); + + setTimeout(function() { + shadow.copy(store); + updateShadowCSS(id); + setTimeout(function() { + active.node.style.removeProperty("transition"); + animate = false; + }, 100); + }, 200); + } + + var updateActivePos = function updateActivePos(deltaX, deltaY) { + if (active.shadowID === null) + active.updatePos(deltaX, deltaY); + else + updateShadowPos(deltaX, deltaY); + } + + /* + * Shadow properties + */ + var updateShadowCSS = function updateShadowCSS(id) { + active.render[id] = active.shadows[id].computeCSS(); + active.updateShadows(); + } + + var toggleShadowInset = function toggleShadowInset(value) { + if (active.shadowID === null) + return; + active.shadows[active.shadowID].toggleInset(value); + updateShadowCSS(active.shadowID); + } + + var updateShadowPos = function updateShadowPos(deltaX, deltaY) { + var shadow = active.shadows[active.shadowID]; + shadow.posX += deltaX; + shadow.posY += deltaY; + SliderManager.setValue("posX", shadow.posX); + SliderManager.setValue("posY", shadow.posY); + updateShadowCSS(active.shadowID); + } + + var setShadowPosX = function setShadowPosX(value) { + if (active.shadowID === null) + return; + active.shadows[active.shadowID].posX = value; + updateShadowCSS(active.shadowID); + } + + var setShadowPosY = function setShadowPosY(value) { + if (active.shadowID === null) + return; + active.shadows[active.shadowID].posY = value; + updateShadowCSS(active.shadowID); + } + + var setShadowBlur = function setShadowBlur(value) { + if (active.shadowID === null) + return; + active.shadows[active.shadowID].blur = value; + updateShadowCSS(active.shadowID); + } + + var setShadowSpread = function setShadowSpread(value) { + if (active.shadowID === null) + return; + active.shadows[active.shadowID].spread = value; + updateShadowCSS(active.shadowID); + } + + var updateShadowColor = function updateShadowColor(color) { + active.shadows[active.shadowID].color.copy(color); + updateShadowCSS(active.shadowID); + } + + /* + * Element Properties + */ + var updateColor = function updateColor(color) { + if (active.shadowID === null) + active.updateBgColor(color); + else + updateShadowColor(color); + } + + var init = function init() { + preview = getElemById("preview"); + + ColoPicker.subscribe("color", updateColor); + PreviewMouseTracking.subscribe(updateActivePos); + + // Affects shadows + ButtonManager.subscribe("inset", toggleShadowInset); + SliderManager.subscribe("posX", setShadowPosX); + SliderManager.subscribe("posY", setShadowPosY); + SliderManager.subscribe("blur", setShadowBlur); + SliderManager.subscribe("spread", setShadowSpread); + + // Affects element + SliderManager.subscribe("top", function(value){ + active.setTop(value); + }); + SliderManager.subscribe("left", function(value){ + active.setLeft(value); + }); + SliderManager.subscribe("rotate", function(value) { + if (active == classes["element"]) + return; + active.setRotate(value); + }); + + SliderManager.subscribe("z-index", function(value) { + if (active == classes["element"]) + return; + active.setzIndex(value); + }); + + SliderManager.subscribe("width", function(value) { + active.setWidth(value) + }); + + SliderManager.subscribe("height", function(value) { + active.setHeight(value) + }); + + // Actions + classes['before'].top = -30; + classes['before'].left = -30; + classes['after'].top = 30; + classes['after'].left = 30; + classes['before'].toggleDisplay(false); + classes['after'].toggleDisplay(false); + ButtonManager.setValue('before', false); + ButtonManager.setValue('after', false); + + ButtonManager.subscribe("before", classes['before'].toggleDisplay.bind(classes['before'])); + ButtonManager.subscribe("after", classes['after'].toggleDisplay.bind(classes['after'])); + + ButtonManager.subscribe("border-state", function(value) { + active.toggleBorder(value); + }); + + } + + return { + init : init, + addShadow : addShadow, + swapShadow : swapShadow, + addCssClass : addCssClass, + disableClass : disableClass, + deleteShadow : deleteShadow, + setActiveClass : setActiveClass, + setActiveShadow : setActiveShadow + } + + })(); + + /** + * Layer Manager + */ + var LayerManager = (function LayerManager() { + var stacks = []; + var active = { + node : null, + stack : null + } + var elements = {}; + + var mouseEvents = function mouseEvents(e) { + var node = e.target; + var type = node.getAttribute('data-type'); + + if (type === 'subject') + setActiveStack(stacks[node.id]); + + if (type === 'disable') { + Tool.disableClass(node.parentNode.id); + setActiveStack(stacks['element']); + } + + if (type === 'add') + active.stack.addLayer(); + + if (type === 'layer') + active.stack.setActiveLayer(node); + + if (type === 'delete') + active.stack.deleteLayer(node.parentNode); + + if (type === 'move-up') + active.stack.moveLayer(1); + + if (type === 'move-down') + active.stack.moveLayer(-1); + } + + var setActiveStack = function setActiveStack(stackObj) { + active.stack.hide(); + active.stack = stackObj; + active.stack.show(); + } + + /* + * Stack object + */ + var Stack = function Stack(subject) { + var S = document.createElement('div'); + var title = document.createElement('div'); + var stack = document.createElement('div'); + + S.className = 'container'; + stack.className = 'stack'; + title.className = 'title'; + title.textContent = subject.getAttribute('data-title'); + S.appendChild(title); + S.appendChild(stack); + + this.id = subject.id; + this.container = S; + this.stack = stack; + this.subject = subject; + this.order = []; + this.uid = 0; + this.count = 0; + this.layer = null; + this.layerID = 0; + } + + Stack.prototype.addLayer = function addLayer() { + if (Tool.addShadow(this.layerID) == -1) + return; + + var uid = this.getUID(); + var layer = this.createLayer(uid); + + if (this.layer === null && this.stack.children.length >= 1) + this.layer = this.stack.children[0]; + + this.stack.insertBefore(layer, this.layer); + this.order.splice(this.layerID, 0, uid); + this.count++; + this.setActiveLayer(layer); + } + + Stack.prototype.createLayer = function createLayer(uid) { + var layer = document.createElement('div'); + var del = document.createElement('span'); + + layer.className = 'node'; + layer.setAttribute('data-shid', uid); + layer.setAttribute('data-type', 'layer'); + layer.textContent = 'shadow ' + uid; + + del.className = 'delete'; + del.setAttribute('data-type', 'delete'); + + layer.appendChild(del); + return layer; + } + + Stack.prototype.getUID = function getUID() { + return this.uid++; + } + + // SOLVE IE BUG + Stack.prototype.moveLayer = function moveLayer(direction) { + if (this.count <= 1 || this.layer === null) + return; + if (direction === -1 && this.layerID === (this.count - 1) ) + return; + if (direction === 1 && this.layerID === 0 ) + return; + + if (direction === -1) { + var before = null; + Tool.swapShadow(this.layerID, this.layerID + 1); + this.swapOrder(this.layerID, this.layerID + 1); + this.layerID += 1; + + if (this.layerID + 1 !== this.count) + before = this.stack.children[this.layerID + 1]; + + this.stack.insertBefore(this.layer, before); + Tool.setActiveShadow(this.layerID, false); + } + + if (direction === 1) { + Tool.swapShadow(this.layerID, this.layerID - 1); + this.swapOrder(this.layerID, this.layerID - 1); + this.layerID -= 1; + this.stack.insertBefore(this.layer, this.stack.children[this.layerID]); + Tool.setActiveShadow(this.layerID, false); + } + } + + Stack.prototype.swapOrder = function swapOrder(pos1, pos2) { + var x = this.order[pos1]; + this.order[pos1] = this.order[pos2]; + this.order[pos2] = x; + } + + Stack.prototype.deleteLayer = function deleteLayer(node) { + var shadowID = node.getAttribute('data-shid') | 0; + var index = this.order.indexOf(shadowID); + this.stack.removeChild(this.stack.children[index]); + this.order.splice(index, 1); + this.count--; + + Tool.deleteShadow(index); + + if (index > this.layerID) + return; + + if (index == this.layerID) { + if (this.count >= 1) { + this.layerID = 0; + this.setActiveLayer(this.stack.children[0], true); + } + else { + this.layer = null; + this.show(); + } + } + + if (index < this.layerID) { + this.layerID--; + Tool.setActiveShadow(this.layerID, true); + } + + } + + Stack.prototype.setActiveLayer = function setActiveLayer(node) { + elements.shadow_properties.style.display = 'block'; + elements.element_properties.style.display = 'none'; + + if (this.layer) + this.layer.removeAttribute('data-active'); + + this.layer = node; + this.layer.setAttribute('data-active', 'layer'); + + var shadowID = node.getAttribute('data-shid') | 0; + this.layerID = this.order.indexOf(shadowID); + Tool.setActiveShadow(this.layerID, true); + } + + Stack.prototype.unsetActiveLayer = function unsetActiveLayer() { + if (this.layer) + this.layer.removeAttribute('data-active'); + + this.layer = null; + this.layerID = 0; + } + + Stack.prototype.hide = function hide() { + this.unsetActiveLayer(); + this.subject.removeAttribute('data-active'); + var style = this.container.style; + style.left = '100%'; + style.zIndex = '0'; + } + + Stack.prototype.show = function show() { + elements.shadow_properties.style.display = 'none'; + elements.element_properties.style.display = 'block'; + + if (this.id === 'element') { + elements.zIndex.style.display = 'none'; + elements.transform_rotate.style.display = 'none'; + } + else { + elements.zIndex.style.display = 'block'; + elements.transform_rotate.style.display = 'block'; + } + + this.subject.setAttribute('data-active', 'subject'); + var style = this.container.style; + style.left = '0'; + style.zIndex = '10'; + Tool.setActiveClass(this.id); + } + + function init() { + + var elem, size; + var layerManager = getElemById("layer_manager"); + var layerMenu = getElemById("layer_menu"); + var container = getElemById("stack_container"); + + elements.shadow_properties = getElemById('shadow_properties'); + elements.element_properties = getElemById('element_properties'); + elements.transform_rotate = getElemById('transform_rotate'); + elements.zIndex = getElemById('z-index'); + + elem = document.querySelectorAll('#layer_menu [data-type="subject"]'); + size = elem.length; + + for (var i = 0; i < size; i++) { + var S = new Stack(elem[i]); + stacks[elem[i].id] = S; + container.appendChild(S.container); + Tool.addCssClass(elem[i].id); + } + + active.stack = stacks['element']; + stacks['element'].show(); + + layerManager.addEventListener("click", mouseEvents); + layerMenu.addEventListener("click", mouseEvents); + + ButtonManager.subscribe("before", function(value) { + if (value === false && active.stack === stacks['before']) + setActiveStack(stacks['element']) + if (value === true && active.stack !== stacks['before']) + setActiveStack(stacks['before']) + }); + + ButtonManager.subscribe("after", function(value) { + if (value === false && active.stack === stacks['after']) + setActiveStack(stacks['element']) + if (value === true && active.stack !== stacks['after']) + setActiveStack(stacks['after']) + }); + } + + return { + init : init + } + })(); + + /* + * OutputManager + */ + var OutputManager = (function OutputManager() { + var classes = []; + var buttons = []; + var active = null; + var menu = null; + var button_offset = 0; + + var crateOutputNode = function(topic, property) { + + var prop = document.createElement('div'); + var name = document.createElement('span'); + var value = document.createElement('span'); + + var pmatch = property.match(/(^([a-z0-9\-]*)=\[([a-z0-9\-\"]*)\])|^([a-z0-9\-]*)/i); + + name.textContent = '\t' + pmatch[4]; + + if (pmatch[3] !== undefined) { + name.textContent = '\t' + pmatch[2]; + value.textContent = pmatch[3] + ';'; + } + + name.textContent += ': '; + prop.className = 'css-property'; + name.className = 'name'; + value.className = 'value'; + prop.appendChild(name); + prop.appendChild(value); + + classes[topic].node.appendChild(prop); + classes[topic].line[property] = prop; + classes[topic].prop[property] = value; + } + + var OutputClass = function OutputClass(node) { + var topic = node.getAttribute('data-topic'); + var prop = node.getAttribute('data-prop'); + var name = node.getAttribute('data-name'); + var properties = prop.split(' '); + + classes[topic] = {}; + classes[topic].node = node; + classes[topic].prop = []; + classes[topic].line = []; + classes[topic].button = new Button(topic); + + var open_decl = document.createElement('div'); + var end_decl = document.createElement('div'); + + open_decl.textContent = name + ' {'; + end_decl.textContent = '}'; + node.appendChild(open_decl); + + for (var i in properties) + crateOutputNode(topic, properties[i]); + + node.appendChild(end_decl); + } + + var Button = function Button(topic) { + var button = document.createElement('div'); + + button.className = 'button'; + button.textContent = topic; + button.style.left = button_offset + 'px'; + button_offset += 100; + + button.addEventListener("click", function() { + toggleDisplay(topic); + }) + + menu.appendChild(button); + return button; + } + + var toggleDisplay = function toggleDisplay(topic) { + active.button.removeAttribute('data-active'); + active.node.style.display = 'none'; + active = classes[topic]; + active.node.style.display = 'block'; + active.button.setAttribute('data-active', 'true'); + } + + var toggleButton = function toggleButton(topic, value) { + var display = (value === true) ? 'block' : 'none'; + classes[topic].button.style.display = display; + + if (value === true) + toggleDisplay(topic); + else + toggleDisplay('element'); + } + + var updateProperty = function updateProperty(topic, property, data) { + try { + classes[topic].prop[property].textContent = data + ';'; + } + catch(error) { + // console.log("ERROR undefined : ", topic, property, data); + } + } + + var toggleProperty = function toggleProperty(topic, property, value) { + var display = (value === true) ? 'block' : 'none'; + try { + classes[topic].line[property].style.display = display; + } + catch(error) { + // console.log("ERROR undefined : ",classes, topic, property, value); + } + } + + var init = function init() { + + menu = getElemById('menu'); + + var elem = document.querySelectorAll('#output .output'); + var size = elem.length; + for (var i = 0; i < size; i++) + OutputClass(elem[i]); + + active = classes['element']; + toggleDisplay('element'); + + ButtonManager.subscribe("before", function(value) { + toggleButton('before', value); + }); + + ButtonManager.subscribe("after", function(value) { + toggleButton('after', value); + }); + } + + return { + init : init, + updateProperty : updateProperty, + toggleProperty : toggleProperty + } + + })(); + + + /** + * Init Tool + */ + var init = function init() { + ButtonManager.init(); + OutputManager.init(); + ColoPicker.init(); + SliderManager.init(); + LayerManager.init(); + PreviewMouseTracking.init("preview"); + Tool.init(); + } + + return { + init : init + } + +})(); + + +</code></pre> +</div> + +<div>{{ EmbedLiveSample('box-shadow_generator', '100%', '1100px', '') }}</div> + +<p><strong>Related Tool: </strong><a href="https://cssgenerator.org/box-shadow-css-generator.html">Box Shadow CSS Generator</a></p> diff --git a/files/zh-cn/web/css/css_box_model/index.html b/files/zh-cn/web/css/css_box_model/index.html new file mode 100644 index 0000000000..8d0de27817 --- /dev/null +++ b/files/zh-cn/web/css/css_box_model/index.html @@ -0,0 +1,112 @@ +--- +title: CSS 基础框盒模型 +slug: Web/CSS/CSS_Box_Model +tags: + - CSS +translation_of: Web/CSS/CSS_Box_Model +--- +<p>{{CSSRef}}</p> + +<p><strong>CSS 基础框盒模型</strong>是 CSS 规范的一个模块,它定义了一种长方形的盒子——包括它们各自的内边距(padding)与外边距(margin ),并根据<a href="/zh-CN/docs/Web/CSS/Visual_formatting_model">视觉格式化模型</a>来生成元素,对其进行布置、编排、布局(lay out)。常被直译为盒子模型、盒模型或框模型。</p> + +<p>CSS 基础框盒模型一般仅针对单个元素及其边距、内容进行布局,而非对多个元素进行综合的排版,即使<a href="/zh-CN/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing">外边距合并</a>等特性涉及二个或二个以上元素之间部分属性的交互反馈。</p> + +<h2 id="参考">参考</h2> + +<h3 id="属性">属性</h3> + +<h4 id="控制框盒中内容流的属性">控制框盒中内容流的属性</h4> + +<div class="index"> +<ul> + <li>{{CSSxRef("overflow")}}</li> + <li>{{CSSxRef("overflow-x")}}</li> + <li>{{CSSxRef("overflow-y")}}</li> +</ul> +</div> + +<h4 id="控制框盒大小的属性">控制框盒大小的属性</h4> + +<div class="index"> +<ul> + <li>{{CSSxRef("height")}}</li> + <li>{{CSSxRef("width")}}</li> + <li>{{CSSxRef("max-height")}}</li> + <li>{{CSSxRef("max-width")}}</li> + <li>{{CSSxRef("min-height")}}</li> + <li>{{CSSxRef("min-width")}}</li> +</ul> +</div> + +<h4 id="控制外边距_Margin_的属性">控制外边距 Margin 的属性</h4> + +<div class="index"> +<ul> + <li>{{CSSxRef("margin")}}</li> + <li>{{CSSxRef("margin-bottom")}}</li> + <li>{{CSSxRef("margin-left")}}</li> + <li>{{CSSxRef("margin-right")}}</li> + <li>{{CSSxRef("margin-top")}}</li> + <li>{{CSSxRef("margin-trim")}} {{Experimental_Inline}}</li> +</ul> +</div> + +<h4 id="控制内边距_Padding_的属性">控制内边距 Padding 的属性</h4> + +<div class="index"> +<ul> + <li>{{CSSxRef("padding")}}</li> + <li>{{CSSxRef("padding-bottom")}}</li> + <li>{{CSSxRef("padding-left")}}</li> + <li>{{CSSxRef("padding-right")}}</li> + <li>{{CSSxRef("padding-top")}}</li> +</ul> +</div> + +<h4 id="其他属性">其他属性</h4> + +<div class="index"> +<ul> + <li>{{CSSxRef("visibility")}}</li> +</ul> +</div> + +<h2 id="指南">指南</h2> + +<dl> + <dt><a href="/zh-CN/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model">CSS 基础框盒模型介绍</a></dt> + <dd>解释了 CSS 的根本概念之一:框盒模型。该模型定义了 CSS 如何对元素的各个组成进行布局(lays out),这些组成包括他们的内容 Content、内边距 Padding、边框 Border,和外边距 Margin。</dd> + <dt><a href="/zh-CN/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing">掌握外边距合并</a></dt> + <dd>有时,两个相邻的外边距会折叠合并成一个。本文介绍了控制此特性的规则,比如合并何时发生、为何发生;以及应当如何控制它。</dd> + <dt><a href="/zh-CN/docs/Web/CSS/Visual_formatting_model">视觉格式化模型</a></dt> + <dd>解释了视觉格式化模型(visual formatting model)是什么,以及它的作用。</dd> +</dl> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName("CSS3 Box")}}</td> + <td>{{Spec2("CSS3 Box")}}</td> + <td>Added <code>margin-trim</code></td> + </tr> + <tr> + <td>{{SpecName("CSS2.1", "box.html")}}</td> + <td>{{Spec2("CSS2.1")}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName("CSS1")}}</td> + <td>{{Spec2("CSS1")}}</td> + <td>Initial definition.</td> + </tr> + </tbody> +</table> diff --git a/files/zh-cn/web/css/css_box_model/introduction_to_the_css_box_model/index.html b/files/zh-cn/web/css/css_box_model/introduction_to_the_css_box_model/index.html new file mode 100644 index 0000000000..90e9c23798 --- /dev/null +++ b/files/zh-cn/web/css/css_box_model/introduction_to_the_css_box_model/index.html @@ -0,0 +1,82 @@ +--- +title: CSS 基础框盒模型介绍 +slug: Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model +tags: + - CSS Box Model + - 定位 + - 布局 + - 指南 +translation_of: Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model +--- +<p>{{CSSRef}}</p> + +<div class="syntaxbox"> +<p>当对一个文档进行布局(lay out)的时候,浏览器的渲染引擎会根据标准之一的 <strong>CSS 基础框盒模型</strong>(<strong>CSS basic box model</strong>),将所有元素表示为一个个矩形的盒子(box)。CSS 决定这些盒子的大小、位置以及属性(例如颜色、背景、边框尺寸…)。</p> + +<p>每个盒子由四个部分(或称<em>区域</em>)组成,其效用由它们各自的边界(Edge)所定义(原文:defined by their respective edges,可能意指容纳、包含、限制等)。如图,与盒子的四个组成区域相对应,每个盒子有四个边界:<em>内容边界</em> <em>Content edge</em>、<em>内边距边界</em> <em>Padding Edge</em>、<em>边框边界</em> <em>Border Edge</em>、<em>外边框边界</em> <em>Margin Edge</em>。</p> + +<p><img alt="CSS Box model" src="https://mdn.mozillademos.org/files/8685/boxmodel-(3).png" style="height: 384px; width: 548px;"></p> + +<p><strong>内容区域 content area</strong> ,由内容边界限制,容纳着元素的“真实”内容,例如文本、图像,或是一个视频播放器。它的尺寸为内容宽度(或称 <em>content-box 宽度</em>)和内容高度(或称 <em>content-box 高度</em>)。它通常含有一个背景颜色(默认颜色为透明)或背景图像。</p> + +<p>如果 {{cssxref("box-sizing")}} 为 <code>content-box</code>(默认),则内容区域的大小可明确地通过 {{cssxref("width")}}、{{cssxref("min-width")}}、{{cssxref("max-width")}}、{{cssxref("height")}}、{{cssxref("min-height")}},和 {{cssxref("max-height")}} 控制。</p> + +<p><strong>内边距区域 padding area</strong> 由内边距边界限制,扩展自内容区域,负责延伸内容区域的背景,填充元素中内容与边框的间距。它的尺寸是 <em>padding-box 宽度</em> 和 <em>padding-box 高度</em>。</p> + +<p>内边距的粗细可以由 {{cssxref("padding-top")}}、{{cssxref("padding-right")}}、{{cssxref("padding-bottom")}}、{{cssxref("padding-left")}},和简写属性 {{cssxref("padding")}} 控制。</p> + +<p><strong>边框区域 border area</strong> 由边框边界限制,扩展自内边距区域,是容纳边框的区域。其尺寸为 <em>border-box 宽度</em> 和 <em>border-box 高度</em>。</p> + +<p>边框的粗细由 {{cssxref("border-width")}} 和简写的 {{cssxref("border")}} 属性控制。如果 {{cssxref("box-sizing")}} 属性被设为 <code>border-box</code>,那么边框区域的大小可明确地通过 {{cssxref("width")}}、{{cssxref("min-width")}}, {{cssxref("max-width")}}、{{ cssxref("height") }}、{{cssxref("min-height")}},和 {{cssxref("max-height")}} 属性控制。假如框盒上设有背景({{cssxref("background-color")}} 或 {{cssxref("background-image")}}),背景将会一直延伸至边框的外沿(默认为在边框下层延伸,边框会盖在背景上)。此默认表现可通过 CSS 属性 {{cssxref("background-clip")}} 来改变。</p> + +<p><strong>外边距区域 margin area</strong> 由外边距边界限制,用空白区域扩展边框区域,以分开相邻的元素。它的尺寸为 <em>margin-box 宽度 </em>和 <em>margin-box 高度</em>。</p> + +<p>外边距区域的大小由 {{cssxref("margin-top")}}、{{cssxref("margin-right")}}、{{cssxref("margin-bottom")}}、{{cssxref("margin-left")}},和简写属性 {{cssxref("margin")}} 控制。在发生<a href="/en/CSS/margin_collapsing" title="en/CSS/margin_collapsing">外边距合并</a>的情况下,由于盒之间共享外边距,外边距不容易弄清楚。</p> + +<p>最后,请注意,除<a href="/zh-CN/docs/Web/CSS/Replaced_element">可替换元素</a>外,对于行内元素来说,尽管内容周围存在内边距与边框,但其占用空间(每一行文字的高度)则由 {{cssxref('line-height')}} 属性决定,即使边框和内边距仍会显示在内容周围。</p> +</div> + +<h2 id="参见">参见</h2> + +<ul> + <li><a href="/zh-CN/docs/Web/CSS/Containing_block">布局与包含块</a></li> + <li><a href="/zh-CN/docs/Web/CSS/Cascade">CSS 层叠介绍</a></li> + <li><a href="/zh-CN/docs/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance">层叠和继承</a></li> +</ul> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">注释</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('CSS3 Box', '#intro')}}</td> + <td>{{Spec2('CSS3 Box')}}</td> + <td> </td> + </tr> + <tr> + <td>{{ SpecName("CSS2.1","box.html#box-dimensions")}}</td> + <td>{{ Spec2('CSS2.1') }}</td> + <td>Though more precisely worded, there is no practical change.<br> + 尽管有了更详尽的描述,但没有实际上的变化。</td> + </tr> + <tr> + <td>{{SpecName("CSS1","#formatting-model")}}</td> + <td>{{Spec2('CSS1')}}</td> + <td>Initial definition.<br> + 最初的定义。</td> + </tr> + </tbody> +</table> + +<h2 id="参见_2">参见</h2> + +<ul> + <li>{{css_key_concepts}}</li> +</ul> diff --git a/files/zh-cn/web/css/css_box_model/mastering_margin_collapsing/index.html b/files/zh-cn/web/css/css_box_model/mastering_margin_collapsing/index.html new file mode 100644 index 0000000000..d1b40704cf --- /dev/null +++ b/files/zh-cn/web/css/css_box_model/mastering_margin_collapsing/index.html @@ -0,0 +1,151 @@ +--- +title: 外边距重叠 +slug: Web/CSS/CSS_Box_Model/Mastering_margin_collapsing +tags: + - CSS + - CSS 盒模型 + - 参考 + - 指南 +translation_of: Web/CSS/CSS_Box_Model/Mastering_margin_collapsing +--- +<div>{{CSSRef}}</div> + +<p>块的<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-top">上外边距(margin-top)</a>和<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-bottom">下外边距(margin-bottom)</a>有时合并(折叠)为单个边距,其大小为单个边距的最大值(或如果它们相等,则仅为其中一个),这种行为称为<strong>边距折叠</strong>。</p> + +<div class="blockIndicator note"> +<p>注意有设定<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/float">float</a>和<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/position#absolute">position=absolute</a>的元素不会产生外边距重叠行为。</p> +</div> + +<div></div> + +<p>有三种情况会形成外边距重叠:</p> + +<dl> + <dt>同一层相邻元素之间</dt> + <dd>相邻的两个元素之间的外边距重叠,除非后一个元素加上<a href="/zh-CN/docs/Web/CSS/clear">clear-fix清除浮动</a>。</dd> +</dl> + +<pre class="brush: html notranslate"><style> +p:nth-child(1){ + margin-bottom: 13px; +} +p:nth-child(2){ + margin-top: 87px; +} +</style> + +<p>下边界范围会...</p> +<p>...会跟这个元素的上边界范围重叠。</p></pre> + +<p>这个例子如果以为边界会合并的话,理所当然会猜测上下2个元素会合并一个100px的边界范围,但其实会发生边界折叠,只会挑选最大边界范围留下,所以这个例子的边界范围其实是87px。</p> + +<dl> + <dt>没有内容将父元素和后代元素分开</dt> + <dd> 如果没有边框{{cssxref("border")}},内边距{{cssxref("padding")}},行内内容,也没有创建<a href="https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context">块级格式上下文</a>或<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/clear">清除浮动</a>来分开一个块级元素的上边界{{cssxref("margin-top")}} 与其内一个或多个后代块级元素的上边界{{cssxref("margin-top")}};或没有边框,内边距,行内内容,高度{{cssxref("height")}},最小高度{{cssxref("min-height")}}或 最大高度{{cssxref("max-height")}} 来分开一个块级元素的下边界{{cssxref("margin-bottom")}}与其内的一个或多个后代后代块元素的下边界{{cssxref("margin-bottom")}},则就会出现父块元素和其内后代块元素外边界重叠,重叠部分最终会溢出到父级块元素外面。</dd> +</dl> + +<pre class="brush: html notranslate"><style type="text/css"> + section { + margin-top: 13px; + margin-bottom: 87px; + } + + header { + margin-top: 87px; + } + + footer { + margin-bottom: 13px; + } +</style> + +<section> + <header>上边界重叠 87</header> + <main></main> + <footer>下边界重叠 87 不能再高了</footer> +</section></pre> + +<dl> + <dt>空的块级元素</dt> + <dd>当一个块元素上边界{{cssxref("margin-top")}} 直接贴到元素下边界{{cssxref("margin-bottom")}}时也会发生边界折叠。这种情况会发生在一个块元素完全没有设定边框{{cssxref("border")}}、内边距{{cssxref("paddng")}}、高度{{cssxref("height")}}、最小高度{{cssxref("min-height")}} 、最大高度{{cssxref("max-height")}} 、内容设定为inline或是加上<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/clear">clear-fix</a>的时候。</dd> +</dl> + +<pre class="brush: html notranslate"><style> +p { + margin: 0; +} +div { + margin-top: 13px; + margin-bottom: 87px; +} +</style> + +<p>上边界范围是 87 ...</p> +<div></div> +<p>... 上边界范围是 87</p></pre> + +<p>一些需要注意的地方:</p> + +<ul> + <li>上述情况的组合会产生更复杂的外边距折叠。</li> + <li>即使某一外边距为0,这些规则仍然适用。因此就算父元素的外边距是0,第一个或最后一个子元素的外边距仍然会“溢出”到父元素的外面。</li> + <li>如果参与折叠的外边距中包含负值,折叠后的外边距的值为最大的正边距与最小的负边距(即绝对值最大的负边距)的和,;也就是说如果有-13px 8px 100px叠在一起,边界范围的技术就是 100px -13px的87px。</li> + <li>如果所有参与折叠的外边距都为负,折叠后的外边距的值为最小的负边距的值。这一规则适用于相邻元素和嵌套元素。</li> +</ul> + +<p>以上这些内容都是发生在Block-Level的元素,设定floating和absolutely positioned的元素完全不用担心边界重叠的问题。</p> + +<h2 id="示例">示例</h2> + +<h3 id="HTML">HTML</h3> + +<pre class="brush: html notranslate"><p>The bottom margin of this paragraph is collapsed …</p> +<p>… with the top margin of this paragraph, yielding a margin of <code>1.2rem</code> in between.</p> + +<div>This parent element contains two paragraphs! + <p>This paragraph has a <code>.4rem</code> margin between it and the text above.</p> + <p>My bottom margin collapses with my parent, yielding a bottom margin of <code>2rem</code>.</p> +</div> + +<p>I am <code>2rem</code> below the element above.</p></pre> + +<h3 id="CSS">CSS</h3> + +<pre class="brush: css notranslate">div { + margin: 2rem 0; + background: lavender; +} + +p { + margin: .4rem 0 1.2rem 0; + background: yellow; +}</pre> + +<h3 id="结果">结果</h3> + +<p>{{EmbedLiveSample('示例', 'auto', 350)}}</p> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName("CSS2.1", "box.html#collapsing-margins", "margin collapsing")}}</td> + <td>{{Spec2("CSS2.1")}}</td> + <td>初始定义</td> + </tr> + </tbody> +</table> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{css_key_concepts}}</li> +</ul> |