diff options
Diffstat (limited to 'files/ru/learn')
216 files changed, 59112 insertions, 0 deletions
diff --git a/files/ru/learn/common_questions/available_text_editors/index.html b/files/ru/learn/common_questions/available_text_editors/index.html new file mode 100644 index 0000000000..37f18bfe7b --- /dev/null +++ b/files/ru/learn/common_questions/available_text_editors/index.html @@ -0,0 +1,309 @@ +--- +title: Как выбрать текстовый редактор? +slug: Learn/Common_questions/Available_text_editors +translation_of: Learn/Common_questions/Available_text_editors +--- +<div>{{IncludeSubnav("/en-US/Learn")}}</div> + +<div class="summary"> +<p>In this article we highlight some things to think about when installing a text editor for web development.</p> +</div> + +<table class="learn-box nostripe standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Вы уже должны знать о <a href="/en-US/Learn/What_software_do_I_need">различных программах, необходимых для создания веб-сайта.</a></p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Узнать, как выбрать текстовый редактор, который наилучшим образом соответствует вашим потребностям в качестве веб-разработчика.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Summary">Summary</h2> + +<p>Веб-сайт состоит в основном из текстовых файлов, поэтому для веселого и приятного процесса разработки вы должны выбрать свой текстовый редактор с умом.</p> + +<p>Огромное количество вариантов немного ошеломляет, так как текстовый редактор настолько важен для компьютерных наук (да, веб-разработка - это компьютерная наука). В идеале вы должны попробовать столько редакторов, сколько сможете, и почувствовать, что соответствует вашему рабочему процессу. Но мы дадим вам несколько советов для начала.</p> + +<p>Вот основные вопросы, на которые вы должны ответить:</p> + +<ul> + <li>С какой ОС (операционной системой) я хочу работать?</li> + <li>Какие технологии я хочу использовать?</li> + <li>Какие основные функции я ожидаю от моего текстового редактора?</li> + <li>Хочу ли я добавить дополнительные функции в мой текстовый редактор?</li> + <li>Нужна ли мне поддержка / помощь при использовании моего текстового редактора?</li> + <li>Имеет ли смысл мой текстовый редактор для меня?</li> +</ul> + +<p>Обратите внимание, что мы не упомянули цену. Очевидно, что это тоже важно, но стоимость продукта мало связана с его качеством или возможностями. Существует большая вероятность, что вы найдете подходящий текстовый редактор бесплатно.</p> + +<p>Here are some popular editors:</p> + +<table class="standard-table" style="height: 522px; width: 917px;"> + <thead> + <tr> + <th scope="col">Редактор</th> + <th scope="col">Лицензия</th> + <th scope="col">Цена</th> + <th scope="col">ОС</th> + <th scope="col">Поддержка</th> + <th scope="col">Док.</th> + <th scope="col">Расширяемый</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="https://atom.io/">Atom</a></td> + <td>MIT/BSD</td> + <td style="text-align: center;">Free</td> + <td>Windows, Mac, Linux</td> + <td><a href="https://discuss.atom.io/categories" rel="external">Forum</a></td> + <td><a href="https://atom.io/docs/latest/">Online Manual</a></td> + <td style="text-align: center;"><a href="https://atom.io/packages">Yes</a></td> + </tr> + <tr> + <td><a href="http://brackets.io/" rel="external">Brackets</a></td> + <td>MIT/BSD</td> + <td style="text-align: center;">Free</td> + <td>Windows, Mac, Linux</td> + <td><a href="https://groups.google.com/forum/#!forum/brackets-dev" rel="external">Forum</a>, <a href="http://webchat.freenode.net/?channels=brackets" rel="external">IRC</a></td> + <td><a href="https://github.com/adobe/brackets/wiki" rel="external">GitHub Wiki</a></td> + <td style="text-align: center;"><a href="https://ingorichter.github.io/BracketsExtensionTweetBot/" rel="external">Yes</a></td> + </tr> + <tr> + <td><a href="https://panic.com/coda/" rel="external">Coda</a></td> + <td>Closed source</td> + <td style="text-align: center;">$99</td> + <td>Mac</td> + <td><a href="https://twitter.com/panic">Twitter</a>, <a href="https://panic.com/qa" rel="external">Forum</a>, <a href="mailto:coda@panic.com">E-mail</a></td> + <td><a href="https://panic.com/coda/#book">eBook</a></td> + <td style="text-align: center;"><a href="https://panic.com/coda/plugins.php">Yes</a></td> + </tr> + <tr> + <td><a href="http://www.codelobster.com">CodeLobster</a></td> + <td>Closed source</td> + <td style="text-align: center;">Free</td> + <td>Windows, Mac, Linux</td> + <td><a href="http://www.codelobster.com/forum/index.php" rel="external">Forum</a>, <a href="mailto:support@codelobster.com">E-mail</a></td> + <td>No end user doc</td> + <td style="text-align: center;">Yes</td> + </tr> + <tr> + <td><a href="http://www.gnu.org/software/emacs/" rel="external">Emacs</a></td> + <td>GPL 3</td> + <td style="text-align: center;">Free</td> + <td>Windows, Mac, Linux</td> + <td><a href="http://www.gnu.org/software/emacs/manual/efaq.html" rel="external">FAQ</a>, <a href="http://mail.gnu.org/mailman/listinfo/help-gnu-emacs" rel="external">Mailing list</a>, <a href="news://gnu.emacs.help" rel="external">News Group</a></td> + <td><a href="http://www.gnu.org/software/emacs/manual/html_node/emacs/index.html">Online Manual</a></td> + <td style="text-align: center;">Yes</td> + </tr> + <tr> + <td><a href="http://www.macrabbit.com/espresso/">Espresso</a></td> + <td>Closed source</td> + <td style="text-align: center;">$75</td> + <td>Mac</td> + <td><a href="http://www.macrabbit.com/support/" rel="external">FAQ</a>, <a href="mailto:support@macrabbit.com">E-mail</a></td> + <td>No end user doc,<br> + but <a href="http://wiki.macrabbit.com/">plug-in doc</a></td> + <td style="text-align: center;">Yes</td> + </tr> + <tr> + <td><a href="https://wiki.gnome.org/Apps/Gedit">Gedit</a></td> + <td>GPL</td> + <td style="text-align: center;">Free</td> + <td>Windows, Mac, Linux</td> + <td><a href="http://mail.gnome.org/mailman/listinfo/gedit-list" rel="external">Mailing list</a>, <a href="irc://irc.gnome.org/%23gedit">IRC</a></td> + <td><a href="https://help.gnome.org/users/gedit/stable/">Online Manual</a></td> + <td style="text-align: center;"><a href="https://wiki.gnome.org/Apps/Gedit/PluginsLists">Yes</a></td> + </tr> + <tr> + <td><a href="http://komodoide.com/komodo-edit/" rel="external">Komodo Edit</a></td> + <td>MPL</td> + <td style="text-align: center;">Free</td> + <td>Windows, Mac, Linux</td> + <td><a href="http://forum.komodoide.com/" rel="external">Forum</a></td> + <td><a href="http://docs.activestate.com/komodo/8.5/" rel="external">Online Manual</a></td> + <td style="text-align: center;"><a href="http://komodoide.com/resources/addons/">Yes</a></td> + </tr> + <tr> + <td><a href="http://www.notepad-plus-plus.org/" rel="external">Notepad++</a></td> + <td>GPL</td> + <td style="text-align: center;">Free</td> + <td>Windows</td> + <td><a href="http://sourceforge.net/p/notepad-plus/discussion/">Forum</a></td> + <td><a href="http://npp-wiki.tuxfamily.org/index.php?title=Main_Page" rel="external">Wiki</a></td> + <td style="text-align: center;"><a href="http://npp-wiki.tuxfamily.org/index.php?title=Plugin_Central" rel="external">Yes</a></td> + </tr> + <tr> + <td><a href="http://www.pspad.com/">PSPad</a></td> + <td>Closed source</td> + <td style="text-align: center;">Free</td> + <td>Windows</td> + <td><a href="http://gogogadgetscott.info/pspad/dotazy.htm">FAQ</a>, <a href="http://forum.pspad.com/" rel="external">Forum</a></td> + <td><a href="http://gogogadgetscott.info/pspad/">Online Help</a></td> + <td style="text-align: center;"><a href="http://www.pspad.com/en/pspad-extensions.php">Yes</a></td> + </tr> + <tr> + <td><a href="http://www.sublimetext.com/" rel="external">Sublime Text</a></td> + <td>Closed source</td> + <td style="text-align: center;">$70</td> + <td>Windows, Mac, Linux</td> + <td><a href="http://www.sublimetext.com/forum/viewforum.php?f=3" rel="external">Forum</a></td> + <td><a href="http://www.sublimetext.com/docs/3/">Official</a>,<a href="http://docs.sublimetext.info/en/latest/index.html"> Unofficial</a></td> + <td style="text-align: center;"><a href="https://sublime.wbond.net/">Yes</a></td> + </tr> + <tr> + <td><a href="http://macromates.com/" rel="external">TextMate</a></td> + <td>Closed source</td> + <td style="text-align: center;">$50</td> + <td>Mac</td> + <td><a href="https://twitter.com/macromates">Twitter</a>, <a href="http://webchat.freenode.net/?channels=textmate">IRC</a>, <a href="http://lists.macromates.com/listinfo/textmate" rel="external">Mailing list</a>, <a href="mailto:tm-support@macromates.com">E-mail</a></td> + <td><a href="http://manual.macromates.com/en/">Online Manual</a>, <a href="http://wiki.macromates.com/Main/HomePage" rel="external">Wiki</a></td> + <td style="text-align: center;"><a href="http://wiki.macromates.com/Main/Plugins" rel="external">Yes</a></td> + </tr> + <tr> + <td><a href="http://www.barebones.com/products/textwrangler/" rel="external">TextWrangler</a></td> + <td>Closed source</td> + <td style="text-align: center;">Free</td> + <td>Mac</td> + <td><a href="http://www.barebones.com/support/textwrangler/faqs.html" rel="external">FAQ</a>, <a href="https://groups.google.com/forum/#!forum/textwrangler">Forum</a></td> + <td><a href="http://ash.barebones.com/TextWrangler_User_Manual.pdf" rel="external">PDF Manual</a></td> + <td style="text-align: center;">No</td> + </tr> + <tr> + <td><a href="http://www.vim.org/" rel="external">Vim</a></td> + <td><a href="http://vimdoc.sourceforge.net/htmldoc/uganda.html#license" rel="external">Specific open license</a></td> + <td style="text-align: center;">Free</td> + <td>Windows, Mac, Linux</td> + <td><a href="http://www.vim.org/maillist.php#vim" rel="external">Mailing list</a></td> + <td><a href="http://vimdoc.sourceforge.net/">Online Manual</a></td> + <td style="text-align: center;"><a href="http://www.vim.org/scripts/script_search_results.php?order_by=creation_date&direction=descending" rel="external">Yes</a></td> + </tr> + <tr> + <td><a href="https://code.visualstudio.com/download">Visual Studio Code</a></td> + <td><a href="https://github.com/microsoft/vscode">Open Source</a> under MIT licence/ Specific licence for product</td> + <td style="text-align: center;">Free</td> + <td>Windows, Mac, Linux</td> + <td><a href="https://code.visualstudio.com/docs/supporting/faq">FAQ</a> </td> + <td><a href="https://code.visualstudio.com/docs">Documentation</a></td> + <td style="text-align: center;"><a href="https://marketplace.visualstudio.com/VSCode">Yes</a></td> + </tr> + </tbody> +</table> + +<h2 id="Активное_изучение">Активное изучение</h2> + +<p><em>Активное изучение пока не доступно. <a href="https://developer.mozilla.org/en-US/docs/MDN/Getting_started">Пожалуйста, рассмотрите возможность внести свой вклад</a>.</em></p> + +<h2 id="Копай_глебже">Копай глебже</h2> + +<h3 id="Критерии_выбора">Критерии выбора</h3> + +<p>Итак, более подробно, о чем вы должны думать, когда выбираете текстовый редактор?</p> + +<h4 id="С_какой_ОС_операционной_системой_я_хочу_работать">С какой ОС (операционной системой) я хочу работать?</h4> + +<p>Конечно, это Ваш выбор. Однако некоторые редакторы доступны только для определенных ОС, поэтому, если Вам нравится переключаться вперед и назад, это сузит возможности. Любой текстовый редактор может выполнить работу, если он работает в вашей системе, но кроссплатформенный редактор облегчает переход с ОС на ОС.</p> + +<p>So first find out which OS you're using, and then check if a given editor supports your OS. Most editors specify on their website whether they support Windows or Mac, though some editors only support certain versions (say, only Windows 7 or later and not Vista). If you're running Ubuntu, your best bet is to search within the Ubuntu Software Center. In general, of course, the Linux/UNIX world is a pretty diverse place where different distros work with different, incompatible packaging systems. That means, if you've set your heart on an obscure text editor, you may have to compile it from source yourself (not for the faint-hearted).</p> + +<h4 id="What_kind_of_technologies_do_I_want_to_manipulate">What kind of technologies do I want to manipulate?</h4> + +<p>Generally speaking, any text editor can open any text file. That works great for writing notes to yourself, but when you're doing web development and writing in {{Glossary("HTML")}}, {{Glossary("CSS")}}, and {{Glossary("JavaScript")}}, you can produce some pretty large, complex files. Make it easier on yourself by choosing a text editor that understands the technologies you're working with. Many text editors help you out with features like</p> + +<ul> + <li><strong>Code coloring. </strong>Make your file more legible by color-coding keywords based on the technology you're using.</li> + <li><strong>Code completion. </strong>Save you time by auto-completing recurring structures (for example, automatically close HTML tags, or suggesting valid values for a given CSS property).</li> + <li><strong>Code snippets. </strong>As you saw when starting a new HTML document, many technologies use the same document structure over and over. Save yourself the hassle of retyping all this by using a code snippet to pre-fill your document.</li> +</ul> + +<p>Most text editors now support code coloring, but not necessarily the other two features. Make sure in particular that your text editor color-codes {{Glossary("HTML")}}, {{Glossary("CSS")}}, and {{Glossary("JavaScript")}}.</p> + +<h4 id="What_kind_of_basic_features_do_I_expect_from_my_text_editor">What kind of basic features do I expect from my text editor?</h4> + +<p>It depends on your needs and plans. These functionalities are often helpful:</p> + +<ul> + <li>Search-and-replace, in one or multiple documents, based on {{Glossary("Regular Expression", "regular expressions")}} or other patterns as needed</li> + <li>Quickly jump to a given line</li> + <li>View two parts of a large document separately</li> + <li>View HTML as it will look in the browser</li> + <li>Select text in multiple places at once</li> + <li>View your project's files and directories</li> + <li>Format your code automatically with code beautifier</li> + <li>Check spelling</li> +</ul> + +<h4 id="Do_I_want_to_add_extra_features_to_my_text_editor">Do I want to add extra features to my text editor?</h4> + +<p>An extensible editor comes with fewer built-in features, but can be extended based on your needs.</p> + +<p>If you aren't sure which features you want, or your favorite editor lacks those features out of the box, look for an extensible editor. The best editors provide many plugins, and ideally a way to look for and install new plugins automatically.</p> + +<p>If you like <em>lots </em>of features and your editor is slowing down because of all your plugins, try using an IDE (integrated development environment). An IDE provides many tools in one interface and it's a bit daunting for beginners, but always an option if your text editor feels too limited. Here are some popular IDEs:</p> + +<ul> + <li><a href="http://www.aptana.com/">Aptana Studio</a></li> + <li><a href="https://eclipse.org/" rel="external">Eclipse</a></li> + <li><a href="http://komodoide.com/" rel="external">Komodo IDE</a></li> + <li><a href="https://netbeans.org/" rel="external">NetBeans IDE</a></li> + <li><a href="http://www.visualstudio.com/" rel="external">Visual Studio</a></li> + <li><a href="https://www.jetbrains.com/webstorm/" rel="external">WebStorm</a></li> +</ul> + +<h4 id="Do_I_need_supporthelp_while_using_my_text_editor">Do I need support/help while using my text editor?</h4> + +<p>Always good to know if you can get help or not when using software. For text editors, check for two different kinds of support:</p> + +<ol> + <li>User-oriented content (FAQ, manual, online help)</li> + <li>Discussion with developers and other users (forum, email, IRC)</li> +</ol> + +<p>Use the written documentation when you're learning how to use the editor. Get in touch with other users if you're troubleshooting while installing or using the editor.</p> + +<h4 id="Does_my_text_editors_look-and-feel_matter_to_me">Does my text editor's look-and-feel matter to me?</h4> + +<p>Well, that's a matter of taste, but some people like customizing every bit of the UI (user interface), from colors to button positions. Editors vary widely in flexibility, so check beforehand. It's not hard to find a text editor that can change color scheme, but if you want hefty customizing you may be better off with an IDE.</p> + +<h3 id="Install_and_set_up">Install and set up</h3> + +<p>Installing a text editor is usually quite straightforward. The method varies based on your platform but it shouldn't be too hard:</p> + +<ul> + <li><strong>Windows. </strong>The developers will give you an <code>.exe</code> or <code>.msi</code> file. Sometimes the software comes in a compressed archive like <code>.zip</code>, <code>.7z</code>, or <code>.rar</code>, and in that case you'll need to install an additional program to extract the content from the archive. Windows supports <code>.zip</code> by default.</li> + <li><strong>Mac. </strong>On the editor's website you can download a <code>.dmg</code> file. Some text editors you can find directly in the Apple Store to make installation even simpler.</li> + <li><strong>Linux. </strong>In the most popular distros you can start with your graphical package manager (Ubuntu Software Center, mintInstall, GNOME Software, &c.). You can often find a <code>.deb</code> or <code>.rpm</code> file for prepackaged software, but most of the time you'll have to use your distro's repository server or, in worst case scenario, compile your editor from source. Take the time to carefully check the installation instructions on the text editor's website.</li> +</ul> + +<p>When you install a new text editor, your OS will probably continue to open text files with its default editor until you change the <em>file association. </em>These instructions will help you specify that your OS should open files in your preferred editor when you double-click them:</p> + +<ul> + <li>Windows + <ul> + <li><a href="http://windows.microsoft.com/en-us/windows-8/choose-programs-windows-uses-default" rel="external">Windows 8</a></li> + <li><a href="http://windows.microsoft.com/en-us/windows/change-default-programs#1TC=windows-7" rel="external">Windows 7</a></li> + <li><a href="http://pcsupport.about.com/od/fixtheproblem/f/chdefprogram.htm">older systems</a></li> + </ul> + </li> + <li><a href="http://osxdaily.com/2013/08/08/change-default-application-open-files-mac-os-x/" rel="external">Mac OS X</a></li> + <li>Linux + <ul> + <li><a href="http://askubuntu.com/questions/289337/how-can-i-change-file-association-globally" rel="external">Ubuntu Unity</a></li> + <li><a href="https://help.gnome.org/users/gnome-help/stable/files-open.html.en" rel="external">GNOME</a></li> + <li><a href="http://doc.opensuse.org/documentation/html/openSUSE_113/opensuse-kdeuser/cha.kde.cust.html#pro.kde.cust.system.fileass">KDE</a></li> + </ul> + </li> +</ul> + +<h2 id="Next_steps">Next steps</h2> + +<p>Now that you have a good text editor, you could take some time to finalize <a href="/en-US/Learn/Set_up_a_basic_working_environment">your basic working environment</a>, or, if you want to play with it right away, write <a href="/en-US/Learn/HTML/Write_a_simple_page_in_HTML">your very first web page</a>.</p> diff --git a/files/ru/learn/common_questions/design_for_all_types_of_users/index.html b/files/ru/learn/common_questions/design_for_all_types_of_users/index.html new file mode 100644 index 0000000000..8980f6ec00 --- /dev/null +++ b/files/ru/learn/common_questions/design_for_all_types_of_users/index.html @@ -0,0 +1,224 @@ +--- +title: 'Как создать дизайн, подходящий для всех пользователей?' +slug: Learn/Common_questions/Design_for_all_types_of_users +tags: + - Дизайн + - Мобильность + - Начинающий + - доступность +translation_of: Learn/Common_questions/Design_for_all_types_of_users +--- +<div>{{IncludeSubnav("/en-US/Learn")}}</div> + +<div class="summary"> +<p>Эта статья содержит основные советы, которые помогут вам создавать веб-сайты для любого типа пользователей.</p> +</div> + +<table class="learn-box nostripe standard-table"> + <tbody> + <tr> + <th scope="row">Перед началом:</th> + <td>Сначала вам следует прочитать <a href="/en-US/Learn/What_is_accessibility">What is accessibility?</a>, поскольку мы не рассматриваем здесь <strong>доступность </strong>подробно.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Универсальный дизайн означает дизайн для всех, независимо от инвалидности или технических ограничений. В этой статье перечислены наиболее важные характеристики для универсального дизайна.</td> + </tr> + </tbody> +</table> + +<h2 id="Краткое_описание">Краткое описание</h2> + +<p>Когда вы создаете веб-сайт, одна из главных проблем, которую нужно учитывать, - это универсальный дизайн: доступность для всех пользователей независимо от инвалидности, технических ограничений, культуры, местоположения и так далее.</p> + +<h2 id="Более_глубокое_изучение">Более глубокое изучение</h2> + +<h3 id="Цветовой_контраст">Цветовой контраст</h3> + +<p>Чтобы сделать ваш текст читаемым, используйте цвет текста, который хорошо контрастирует с цветом фона. Сделайте его особенно легким для чтения текста, чтобы помочь слабовидящим людям и людям, использующим свои телефоны на улице.</p> + +<p>{{Glossary("W3C")}} определяет хорошее сочетание цветов с помощью алгоритма, который вычисляет соотношение яркости между передним и задним планом. Расчет может показаться довольно сложным, но мы можем положиться на инструменты, которые сделают эту работу за нас.</p> + +<p>Давайте загрузим и установим <a href="http://www.paciellogroup.com/resources/contrastanalyser/">анализатор цветового контраста</a> Paciello Group.</p> + +<div class="note"> +<p><strong>Примечание</strong>: в качестве альтернативы вы можете найти ряд инструментов проверки контраста в интернете, таких как <a href="http://webaim.org/resources/contrastchecker/">проверка цветового контраста</a> WebAIM. Мы предлагаем локальную проверку, потому что она поставляется в комплекте с экранным цветоподборщиком, чтобы узнать значение цвета.</p> +</div> + +<p>Например, давайте протестируем цвета на этой странице и посмотрим, как мы справляемся с анализатором цветового контраста:</p> + +<p><img alt="Colour contrast on this page: excellent!" src="https://mdn.mozillademos.org/files/9671/colour-contrast.png" style="height: 575px; width: 799px;"></p> + +<p>Коэффициент контрастности яркости между текстом и фоном составляет 8,30:1, что превышает минимальный стандарт (4,5: 1) и должно позволить многим слабовидящим людям читать эту страницу.</p> + +<h3 id="Размер_шрифта">Размер шрифта</h3> + +<p>Вы можете указать размер шрифта на веб-сайте либо в относительных, либо в абсолютных единицах.</p> + +<h4 id="Абсолютные_единицы">Абсолютные единицы</h4> + +<p>Абсолютные единицы измерения не рассчитываются пропорционально, а относятся к размеру, так сказать, набранному в камне, и выражаются большую часть времени в пикселях (<code>px</code>). Например, если в вашем CSS вы объявите это:</p> + +<pre>body { font-size:16px; } +</pre> + +<p>... вы говорите браузеру, что бы ни случилось, размер шрифта должен быть 16 пикселей. Современные браузеры обходят это правило, делая вид, что вы просите "16 пикселей, когда пользователь устанавливает коэффициент масштабирования 100%".</p> + +<p>Однако, на протяжении многих лет Internet Explorer категорически отображается 16 на 16 пикселей. В этом случае масштабирование ничего не дало, даже в последнем Internet Explorer 8, который нам все еще приходится обслуживать, потому что он все еще существует.</p> + +<h4 id="Относительные_единицы">Относительные единицы</h4> + +<p>Также называемые пропорциональными единицами, относительные единицы вычисляются относительно родительского элемента. Относительные единицы измерения более дружелюбны к доступности, потому что они уважают настройки в системе пользователя.</p> + +<p>Относительные единицы обычно выражаются в <code>em</code>, <code>%</code> и <code>rem</code>:</p> + +<dl> + <dt>Процентные размеры: <code>%</code></dt> + <dd>Этот блок сообщает вашему браузеру, что размер шрифта элемента должен составлять N% от предыдущего элемента, размер шрифта которого был выражен. Если родитель не найден, то размер шрифта по умолчанию в браузере считается базовым размером для расчета (обычно эквивалентным 16 пикселям).</dd> + <dt>Em размеры: <code>em</code></dt> + <dd>Эта единица вычисляется так же, как и проценты, за исключением того, что вы вычисляете в частях 1, а не в частях 100. Говорят, что "em" - это ширина заглавной буквы “М” в алфавите (грубо говоря, буква “М” вписывается в квадрат).</dd> + <dt>Rem размеры: <code>rem</code></dt> + <dd>Эта единица измерения пропорциональна размеру шрифта корневого элемента и выражается в виде частей, таких как em.</dd> +</dl> + +<p>Предположим, что нам нужен базовый размер шрифта 16px и h1 (основной заголовок) в эквиваленте 32px, но если в пределах h1 мы найдем <code>промежуток </code>с классом <code>подзаголовков</code>, он тоже должен быть отрисован с размером шрифта по умолчанию (обычно 16px).</p> + +<p>Вот HTML, который мы используем:</p> + +<pre><!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Эксперимент с размером шрифта</title> +</head> +<body> + + <h1>Это наш главный заголовок + <span class="subheading">Это подзаголовок</span> + </h1> + +</body> +</html></pre> + +<p>CSS на основе процентов будет выглядеть следующим образом:</p> + +<pre>body { font-size:100%; } /* 100% от базового размера шрифта браузера, поэтому в большинстве случаев он будет отображаться как 16 пикселей*/ +h1 { font-size:200%; } /* в два раза больше размера тела, таким образом, 32 пикселя */ +span.subheading { font-size:50%; } /* половина размера h1, таким образом, 16 пикселей, чтобы вернуться к исходному размеру */ +</pre> + +<p>Та же проблема выражена и с ems:</p> + +<pre>body { font-size:1em; } /* 1em = 100% от базового размера браузера, так что в большинстве случаев это будет выглядеть как 16 пикселей */ +h1 { font-size:2em; } /* в 2 раза больше размера тела, так что 32 пикселя */ +span.subheading { font-size:0.5em; } /* половина размера h1, таким образом, 16 пикселей, чтобы вернуться к исходному размеру */ +</pre> + +<p>Как вы можете видеть, математика быстро становится сложной, когда вам нужно следить за родителем, родителем родителя, родителем родителя родителя и так далее. (Большинство проектов выполняется в пиксельном программном обеспечении, поэтому математику должен выполнять человек, кодирующий CSS).</p> + +<p>Теперь о <code>rem</code>. Эта единица измерения относится к размеру корневого элемента, а не к какому-либо другому родительскому элементу. CSS можно переписать таким образом:</p> + +<pre>body { font-size:1em; } /* 1em = 100% от базового размера браузера, так что в большинстве случаев это будет выглядеть как 16 пикселей */ +h1 { font-size:2rem; } /* в 2 раза больше размера тела, так что 32 пикселя */ +span.subheading { font-size:1rem; } /* исходный размер */ +</pre> + +<p>Так ведь проще, правда? Это работает как в Internet Explorer 9, так и в любом другом поддерживаемом браузере, поэтому, пожалуйста, не стесняйтесь использовать этот способ.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Вы можете заметить, что Opera Mini не поддерживает размер шрифта в rem. В конечном итоге он будет устанавливать свой собственный размер шрифта, так что не утруждайте себя кормлением его единицами шрифта.</p> +</div> + +<h4 id="Почему_мне_следует_использовать_пропорциональные_единицы_измерения">Почему мне следует использовать пропорциональные единицы измерения?</h4> + +<p>Потому что вы не знаете, когда браузер придет в себя и откажется увеличивать текст, размер которого выражается в пикселях. Кроме того, проверьте статистику вашего сайта: вы можете получать визиты из старых браузеров.</p> + +<p>Мы бы посоветовали следующее:</p> + +<ul> + <li>Опишите шрифты в единицах rem, большинство браузеров будут очень довольны ими;</li> + <li>Пусть старые браузеры отображают шрифты со своим собственным внутренним движком. Браузерные движки будут игнорировать любое свойство или значение в CSS, если они не могут справиться с ними, так что ваш сайт все еще может быть непригодным для использования, если он не соответствует видению вашего дизайнера. Старые браузеры в любом случае находятся на пути к выходу из использования.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: ваш пробег может варьироваться. Если вам нужно угодить старым браузерам, вам придется использовать ems и сделать немного больше математики.</p> +</div> + +<h3 id="Длина_строки">Длина строки</h3> + +<p>Существует давняя дискуссия о длине строки в интернете, но вот история. Еще в те времена, когда у нас были газеты, Печатники понимали, что глаза читателя будут с трудом переходить от одной строки к другой, если строки будут слишком длинными. Какое же решение? Столбцы.</p> + +<p>Конечно, проблема не исчезает, когда мы переключаемся на интернет. Глаза читателя действуют как челнок, идущий от строки к строке. Чтобы сделать чтение проще для глаз людей, ограничьте ширину строки примерно 60 или 70 символами.</p> + +<p>Для этого вы можете указать размер контейнера вашего текста. Давайте рассмотрим этот HTML:</p> + +<pre><!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Эксперимент с размером шрифта</title> +</head> +<body> + +<div class="container"> + <h1>Это наш главный заголовок + <span class="subheading">Это наш подзаголовок</span> + </h1> + + <p>[длинный текст, который занимает много строк]</p> +</div> + +</body> +</html> +</pre> + +<p>У нас есть <code>div</code> с классом <code>container</code>. Мы можем стилизовать <code>div</code> либо для установки его ширины (используя свойство <code>width</code>), либо для его максимальной ширины, чтобы он никогда не становился слишком большим (используя свойство <code>max-width</code>). Если вам нужен эластичный/адаптивный веб-сайт, и вы не знаете, какова ширина браузера по умолчанию, вы можете использовать свойство <code>max-width</code>, чтобы разрешить до 70 символов в строке и не более:</p> + +<pre>div.container { max-width:70em; }</pre> + +<h3 id="Альтернативный_контент_для_изображений_аудио_и_видео">Альтернативный контент для изображений, аудио и видео</h3> + +<p>Веб-сайты часто включают в себя разные вещи, помимо обычного текста.</p> + +<h4 id="Изображения">Изображения</h4> + +<p>Изобажения могут быть декоративными или информационными, но нет гарантий, что пользователь сможет увидеть их. Например,</p> + +<ul> + <li>Слабовидящие пользователи полагаются на средство чтения с экрана, которое может обрабатывать только текст.</li> + <li>Ваши читатели могут использовать очень строгую интрасеть, которая блокирует изображения, исходящие из {{Glossary("CDN")}}.</li> + <li>Ваши читатели могут отключить изображения для экономии пропускной способности, особенно на мобильных устройствах (см. ниже).</li> +</ul> + +<dl> + <dt>Декоративные изображения</dt> + <dd>Они просто для украшения и не передают никакой полезной информации. Чаще всего их можно было бы заменить фоновым изображением. Убедитесь, что они имеют пустой атрибут <code>alt</code>: <code><img src="deco.gif" alt=""></code>, чтобы они не засоряли текст.</dd> + <dt>Информационнные изоражения</dt> + <dd>Они используются для передачи информации, отсюда и их название. Они могут, например, показать график, жест человека или любую другую информацию. Как минимум, вы должны предоставить соответствующий атрибут <code>alt</code>.</dd> +</dl> + +<p>Если изображение может быть описано кратко, вы можете предоставить атрибут <code>alt </code>и ничего больше. Если изображение не может быть описано кратко, вам придется либо предоставить тот же контент в другой форме на той же странице (например, дополнить круговую диаграмму таблицей, содержащей те же данные), либо прибегнуть к атрибуту <code>longdesc</code>. Значение этого атрибута представляет собой URL-адрес, указывающий на ресурс, явно описывающий в деталях содержимое изображения.</p> + +<div class="note"> +<p><strong>Примечание</strong>: использование и даже существование <code>longdesc </code>обсуждается уже довольно давно. Пожалуйста, обратитесь к <a href="http://www.w3.org/TR/html-longdesc/">расширению описания изображений</a> W3C (longdesc) для получения полного объяснения и подробных примеров.</p> +</div> + +<h4 id="Аудиовидео">Аудио/видео</h4> + +<p>Также вам стоит предоставдять альтернативы мультимедийному контенту.</p> + +<dl> + <dt>Субтитры / закрытие субтитров</dt> + <dd>Вы должны включить подписи в свое видео, чтобы угодить посетителям, которые не могут слышать звук. Некоторые пользователи имеют проблемы со слухом, не имеют функционирующих динамиков или работают в шумной среде (например, в поезде).</dd> + <dt>Расшифровка</dt> + <dd>Субтитры работают только в том случае, если кто-то смотрит видео. Многие пользователи не имеют времени или не имеют соответствующего плагина или кодека. Кроме того, поисковые системы полагаются в основном на текст для индексации вашего контента. По всем этим причинам, пожалуйста, предоставьте текстовую расшифровку видео / аудиофайла.</dd> +</dl> + +<h3 id="Сжатие_изображения">Сжатие изображения</h3> + +<p>Некоторые пользователи могут выбрать отображение изображений, но все еще имеют ограниченную пропускную способность, особенно в развивающихся странах и на мобильных устройствах. Если вы хотите создать успешный сайт, пожалуйста, сожмите ваши изображения. Существуют различные инструменты, которые помогут вам, как онлайн, так и локально:</p> + +<ul> + <li><strong>Устанавливаемое программное обеспечение.</strong> <a href="https://imageoptim.com/">ImageOptim</a> (Mac), <a href="http://optipng.sourceforge.net/">OptiPNG</a> (все платформы), <a href="http://pmt.sourceforge.net/pngcrush/">PNGcrush</a> (DOS, Unix/Linux)</li> + <li><strong>Онлайн инструменты.</strong> Yahoo's <a href="https://imgopt.com/">smushit</a>!, <a href="http://tools.dynamicdrive.com/imageoptimizer/">Онлайн-оптимизатор изображений Dynamic</a> drive (который может автоматически преобразовываться из одного формата в другой, если он более эффективен с пропускной способностью)</li> +</ul> diff --git a/files/ru/learn/common_questions/how_do_you_host_your_website_on_google_app_engine/index.html b/files/ru/learn/common_questions/how_do_you_host_your_website_on_google_app_engine/index.html new file mode 100644 index 0000000000..8cc55f9d12 --- /dev/null +++ b/files/ru/learn/common_questions/how_do_you_host_your_website_on_google_app_engine/index.html @@ -0,0 +1,60 @@ +--- +title: Как разместить свой сайт в Google App Engine +slug: Learn/Common_questions/How_do_you_host_your_website_on_Google_App_Engine +translation_of: Learn/Common_questions/How_do_you_host_your_website_on_Google_App_Engine +--- +<p class="summary"><a href="https://cloud.google.com/appengine/" title="App Engine - Build Scalable Web & Mobile Backends in Any Language | Google Cloud Platform">Google App Engine</a> - это мощная платформа, которая позволяет создавать и запускать приложения в инфраструктуре Google - нужно ли создавать многоуровневое веб-приложение с нуля или размещать статический веб-сайт. Вот пошаговое руководство по размещению вашего сайта в Google App Engine.</p> + +<h2 id="Создание_проекта_Google_Cloud_Platform">Создание проекта Google Cloud Platform</h2> + +<p>Чтобы использовать инструменты Google для своего собственного сайта или приложения, вам нужно создать новый проект на Google Cloud Platform. Для этого требуется наличие учетной записи Google.</p> + +<ol> + <li>Перейдите на панель <a href="https://console.cloud.google.com/projectselector/appengine">App Engine dashboard</a> в консоли Google Cloud Platform и нажмите кнопку «Создать» (<em>Create</em>).</li> + <li>Введите название проекта, отредактируйте свой ID проекта и отметьте его. Для этого урока используются следующие значения: + <ul> + <li>Project name: <em>GAE Sample Site</em></li> + <li>Project ID: <em>gaesamplesite</em></li> + </ul> + </li> + <li>Если вы еще не создали проект раньше, вам нужно будет выбрать, хотите ли вы получать обновления электронной почты или нет, соглашайтесь с Условиями обслуживания, а затем вы можете нажать кнопку «Создать», чтобы создать свой проект.</li> +</ol> + +<h2 id="Создание_приложения">Создание приложения</h2> + +<p>Каждый проект Cloud Platform может содержать одно приложение App Engine. Давайте подготовим приложение для нашего проекта.</p> + +<ol> + <li>Нам понадобится образец приложения для публикации. Если у вас его нет, загрузите и распакуйте это <a href="http://gaesamplesite.appspot.com/downloads.html">sample app</a>..</li> + <li>Посмотрите на структуру образца приложения - папка <code>website</code> содержит содержимое вашего сайта, а <code>app.yaml</code> - ваш файл конфигурации приложения. + <ul> + <li>Ваш веб-сайт должен войти в папку <code>website</code>, а его целевую страницу нужно называть <code>index.html</code>, но кроме того, она может принимать любую форму.</li> + <li>Файл <code>app.yaml</code> - это файл конфигурации, который сообщает App Engine, как сопоставлять URL-адреса вашим статическим файлам. Вам не нужно его редактировать.</li> + </ul> + </li> +</ol> + +<h2 id="Публикация_приложения">Публикация приложения</h2> + +<p>Каждый проект Cloud Platform может содержать одно приложение App Engine. Давайте подготовим приложение для нашего проекта.</p> + +<ol> + <li>Нажмите кнопку Активировать Google Cloud Shell в верхней части окна консоли.<br> + <img alt="Activate Google Cloud Shell button" src="https://mdn.mozillademos.org/files/15041/activate-google-cloud-shell-button.png" style="height: 47px; margin: 1em 0; width: 1279px;"></li> + <li>Откройте редактор кода с панели инструментов Cloud Shell.<br> + <img alt="Code Editor from Cloud Shell toolbar" src="https://mdn.mozillademos.org/files/15940/Screen%20Shot%202018-05-09%20at%2023.13.21.png" style="height: 590px; width: 3000px;"></li> + <li>С помощью drag and drop разместите папку <code>sample-app</code> в левой панели редактора кода.</li> + <li>Вернитесь обратно в Cloud Shell и введите следующую команду для перехода в директорию вашего приложения: + <pre class="brush:bash no-line-numbers notranslate" style="margin: 1em 0;">cd sample-app</pre> + </li> + <li>Теперь вы готовы развернуть ваше приложение, т.е. загрузить его в App Engine: + <pre class="brush:bash no-line-numbers notranslate" style="margin: 1em 0;">gcloud app deploy</pre> + </li> + <li>Введите число от одного до семи, чтобы выбрать регион, в котором вы хотите разместить свое приложение.</li> + <li>Нажмите <code>Y</code> для подтверждения.</li> + <li>Теперь перейдите по ссылке <em>your-project-id</em>.appspot.com, чтобы увидеть ваш сайт. Например, для проекта с ID <em>gaesamplesite, </em>перейдите по ссылке <a href="http://gaesamplesite.appspot.com/">gaesamplesite.appspot.com</a>.</li> +</ol> + +<h2 id="See_also">See also</h2> + +<p>Чтобы узнать больше, смотрите <a href="https://cloud.google.com/appengine/docs/">Google App Engine Documentation</a>.</p> diff --git a/files/ru/learn/common_questions/how_much_does_it_cost/index.html b/files/ru/learn/common_questions/how_much_does_it_cost/index.html new file mode 100644 index 0000000000..315fcf623a --- /dev/null +++ b/files/ru/learn/common_questions/how_much_does_it_cost/index.html @@ -0,0 +1,159 @@ +--- +title: Насколько дорого обойдется сделать что-то с помощью Web? +slug: Learn/Common_questions/How_much_does_it_cost +tags: + - Хостинг + - начинающему + - стоимость +translation_of: Learn/Common_questions/How_much_does_it_cost +--- +<div class="summary"> +<p>Веб-разработка обходится не так дешево, как вам может показаться. В этой статье мы обсудим, как много вам потребуется потратить и почему.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Прежде чем приступить:</th> + <td>Вам следует уже иметь представление о том, <a href="/en-US/Learn/What_software_do_I_need">какое программное обеспечение вам нужно</a>, различия между веб-страницей, веб-сайтом, и тд, а также о том, <a href="/en-US/Learn/Understanding_domain_names">что из себя представляет доменное имя</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Рассмотреть весь процесс создания веб-сайта и оценить расходы на каждом шаге.</td> + </tr> + </tbody> +</table> + +<h2 id="Резюме">Резюме</h2> + +<p><span class="seoSummary">Запуск сайта может вам обойтись в сущее ничто, однако, ваши расходы могут достичь и критических значений. В этой статье мы обсудим, как дорого может что-либо стоить, и как вам получить то, за что вы заплатили (или не платили). </span></p> + +<h2 id="Программное_обеспечение">Программное обеспечение</h2> + +<h3 id="Текстовые_редакторы">Текстовые редакторы</h3> + +<p>Вероятно, у вас уже есть текстовый редактор: например, блокнот на Windows, Gedit на Linux, TextEdit на Mac. Но вам будет легче писать код, если вы выберете редактор, который имеет подсветку синтаксиса и поможет вам наладить структуру кода.</p> + +<p>Многие редакторы бесплатны, например, <a href="https://atom.io/">Atom</a>, <a href="http://brackets.io/">Brackets</a>, <a href="http://bluefish.openoffice.nl/">Bluefish</a>, <a href="http://www.barebones.com/products/textwrangler/">TextWrangler</a>, <a href="http://eclipse.org/">Eclipse</a>, <a href="https://netbeans.org/">Netbeans</a>, и <a href="https://code.visualstudio.com/">Visual Studio Code. </a>Некоторые, такие как <a href="http://www.sublimetext.com/">Sublime Text</a>, вы можете использовать в пробном режиме сколько угодно, но при этом, будете получать рекомендации о возможности приобретения. Некоторые, такие как <a href="https://www.jetbrains.com/phpstorm/">PhpStorm</a>, могут стоить от нескольких десятков до 200 долларов, в зависимости от выбранного плана. Наконец, есть те из них, такие как <a href="http://www.visualstudio.com/">Microsoft Visual Studio</a>, которые могут стоить сотни или даже тысячи долларов; хотя Visual Studio Community бесплатна для индивидуальных разработчиков или проектов с открытым исходным кодом. Часто, у платных редакторов есть также пробные версии.</p> + +<p>Для начала, мы предлагаем вам попробовать несколько редакторов, чтобы понять, какой из них подходит лучше вам. Если вы пишите лишь простые {{Glossary("HTML")}}, {{Glossary("CSS")}}, and {{Glossary("Javascript")}}, используйте простой редактор.</p> + +<p>Цена не влияет на качество или полезность текстового редактора. Вам необходимо попробовать и решить какой из них отвечает вашим потребностям. К примеру, Sublime Text дешевый, но поставляется с множеством бесплатных плагинов которые могут здорово расширить его функциональность.</p> + +<h3 id="Редакторы_изображений">Редакторы изображений</h3> + +<p>Ваша система, вероятно, включает в себя простой редактор изображений или просмотрщик: Paint на Windows, Eye of Gnome на Ubuntu, Preview на Mac. Эти программы относительно ограничены, и в скоре вы захотите более развитый редактор, чтобы иметь возможность добавлять слои, накладывать эффекты и группировать объекты.</p> + +<p>Редакторы могут быть бесплатными (<a href="http://www.gimp.org/">GIMP</a>, <a href="https://www.getpaint.net/">Paint.NET</a>), относительно недорогими (<a href="http://www.paintshoppro.com/">PaintShop Pro</a>, меньше чем $100), или иметь стоимость в пару сотен долларов (<a href="https://www.adobe.com/products/photoshop.html">Adobe Photoshop</a>).</p> + +<p>Вы можете использовать любой из них, так как они имеют похожую функциональность, хотя некоторые из них настолько всеобъемлющие, что вы никогда не сможете использовать весь их функционал. Если в какой то момент вам необходимо обменяться проектами с другими дизайнерами, то вам следует выяснить, какие инструменты они используют. Редакторы могут экспортировать законченные проекты в стандартные форматы, но каждый редактор сохраняет текущие проекты в своем собственном, специализированном формате. Большинство изображений в интернете защищены авторским правом, так что лучше проверить лицензию файла, перед его использованием. Такие сайты, как <a href="https://pixabay.com/">Pixabay</a>, предоставляют изображения под лицензией Creative Commons Zero, так что вы можете использовать, редактировать, и даже публиковать их после изменения, ради коммерческой выгоды.</p> + +<h3 id="Медиа_редакторы">Медиа редакторы</h3> + +<p>Если вы хотите встроить видео или аудио в ваш веб-сайт, то вы можете встроить онлайн сервисы (например, YouTube, Vimeo, или Dailymotion), или встроить ваши собственные видео (см. ниже расходы на пропускную способность).</p> + +<p>Для аудиофайлов, вы можете найти бесплатное программное обеспечение (<a href="http://audacity.sourceforge.net/?lang=en">Audacity</a>, <a href="http://www.wavosaur.com/">Wavosaur</a>), либо заплатить пару сотен долларов (<a href="http://www.sonycreativesoftware.com/soundforge">Sony Sound Forge</a>, <a href="http://www.adobe.com/products/audition.html">Adobe Audition</a>). Подобным образом, видеоредакторы могут быть бесплатными (<a href="http://www.pitivi.org/">PiTiVi</a>, <a href="http://www.openshot.org/">OpenShot</a> для Linux, <a href="https://www.apple.com/mac/imovie/">iMovie</a> для Mac), менее чем $100 (<a href="https://www.adobe.com/us/products/premiere-elements.html">Adobe Premiere Elements</a>), либо иметь стоимость в пару сотен долларов (<a href="https://www.adobe.com/products/premiere.html">Adobe Premiere Pro</a>, <a href="http://www.avid.com/US/products/family/Media-Composer">Avid Media Composer</a>, <a href="https://www.apple.com/final-cut-pro/">Final Cut Pro</a>). Программное обеспечение, поставляемое с вашей цифровой камерой может, также, удовлетворить все ваши нужды.</p> + +<h3 id="Инструменты_публикации">Инструменты публикации</h3> + +<p>Вам также потребуется возможность выгрузки файлов: с вашего жесткого диска на удаленный веб-сервер. Чтобы осуществить это, вам потребуется утилита для публикации, такая как (S)<a href="/en-US/docs/Glossary/FTP">FTP client</a>, <a href="https://en.wikipedia.org/wiki/Rsync">RSync</a>, или <a href="https://help.github.com/articles/using-a-custom-domain-with-github-pages/">Git/GitHub</a>.</p> + +<p>Каждая операционная система включает (S)FTP клиент, как часть своего файлового менеджера. Проводник Windows, Nautilus (распрастраненный файловый менеджер Linux), и Mac Finder - все имеют такую функциональность. Однако, люди часто выбирают удаленные (S)FTP клиенты, для одновременного отображения локальных и удаленных каталогов и хранения паролей сервера.</p> + +<p>Если вы хотите установить (S)FTP клиент, то существует несколько, заслуживающих доверия, бесплатных вариантов: <a href="https://filezilla-project.org/">FileZilla</a>, <a href="http://winscp.net/">WinSCP</a> для Windows, <a href="https://cyberduck.io/">Cyberduck</a> для Mac/Windows, <a href="https://en.wikipedia.org/wiki/List_of_FTP_server_software">и другие</a>.</p> + +<p>Из-за того, что FTP по своей природе небезопасен, вам следует использовать SFTP — безопасную, зашифрованную версию FTP, которую большинство хостинговых сайтов будут предлагать вам по умолчанию — или другое безопасное решение, такое как Rsync, работающее через SSH.</p> + +<h2 id="Браузеры">Браузеры</h2> + +<p>У вас уже есть браузер либо вы можете загрузить его бесплатно. Если необходимо, загрузите Firefox <a href="https://www.mozilla.org/en-US/firefox/all/">отсюда</a> или Google Chrome <a href="https://www.google.com/chrome/browser/">отсюда</a>.</p> + +<h2 id="Веб-доступ">Веб-доступ</h2> + +<h3 id="Компьютер_модем">Компьютер / модем</h3> + +<p>Вам необходим компьютер. Расходы могут сильно варьироваться, в зависимости от вашего бюджета и места проживания. Чтобы опубликовать простой сайт, вам нужен компьютер, способный хотя бы запустить редактор и веб-браузер, таким образом порог вхождения довольно низок.</p> + +<p>Конечно же, вам необходим более мощный компьютер, если вы хотите проектировать сложные конструкции, править фотографии или создавать аудио и видеофайлы.</p> + +<p>Вам потребуется загружать контент на удаленный сервер (<em>см. ниже Хостинг</em>), а значит вам потребуется модем. Ваш {{Glossary("ISP", "провайдер")}} может предоставлять доступ в интернет вам за пару долларов в месяц, однако, это также зависит от места вашего проживания.</p> + +<h3 id="Доступ_по_провайдеру">Доступ по провайдеру</h3> + +<p>Убедитесь что у вас достаточная {{Glossary("Bandwidth", "скорость передачи данных")}}:</p> + +<ul> + <li>Доступ с низкой пропускной способностью может быть приемлем для простого веб-сайта: изображения, тексты, немного CSS и JavaScript. Это, вероятно, обойдется вам в пару долларов, включая аренду модема.</li> + <li>С другой стороны, вам потребуется соединения с высокой пропускной способностью, такие как DSL, оптоволокно, если вы хотите более сложный веб-сайт с сотнями файлов, или если вы хотите предоставить доступ к тяжелым видео/аудио файлам напрямую с вашего веб-сервера. Это может стоить столько же, сколько при соединении с низкой пропускной способностью, а может вырасти до пары сотен долларов в месяц, за более профессиональные потребности.</li> +</ul> + +<h2 id="Хостинг">Хостинг</h2> + +<h3 id="Понимание_пропускной_способности">Понимание пропускной способности</h3> + +<p>Хостинг-провайдеры взимают плату в зависимости от того, сколько {{Glossary("Bandwidth", "bandwidth")}} ваш веб-сайт потребил. Это зависит от того как много людей и бот-сканеров получали доступ к вашему контенту за определенный промежуток времени, и, как много серверного пространства этот контент занимает. Вот почему многие люди, обычно, размещают их видео на удаленных сервисах, таких как Youtube, Dailymotion, и Vimeo. Например, ваш провайдер может иметь план, который позволяет выдерживать до нескольких тысяч посетителей в день. Однако, будьте осторожны, так как это условие меняется от одного провайдера к другому. Возьмите за правило, что надежный, платный персональный хостинг может стоить около 10-15 долларов в месяц.</p> + +<div class="note"> +<p>Заметьте, что не существует такого понятия, как "неограниченная пропускная способность". Если вы использовали огромное количество трафика, будьте готовы выплатить огромную сумму денег.</p> +</div> + +<h3 id="Доменные_имена">Доменные имена</h3> + +<p>Ваше доменное имя должно быть приобретено через провайдера доменных имен (регистратор). Ваш хостинг-провайдер может также быть регистратором (<a href="https://www.1and1.com/">1&1</a>, <a href="https://www.gandi.net/?lang=en">Gandi</a>, например, являются в одно и тоже время регистраторами и хостинг-провайдерами). Доменное имя обычно имеет стоимость в $5-15 за год. Эта цена варьируется в зависимости от:</p> + +<ul> + <li>Местных обязательств: В некоторых странах домены верхнего уровня стоят дороже, так как разные страны устанавливают различные цены.</li> + <li>Сервисов, ассоциированных с доменным именем: некоторые регистраторы предоставляют защиту от спама, скрывая ваш почтовый адрес и адрес электронной почты за их собственными адресами: почтовый адрес может быть под покровительством регистратора, и ваш электронный адрес может быть скрыт под псевдонимом регистратора.</li> +</ul> + +<h3 id="Самодельный_хостинг_vs._хостинг_“из_коробки”">Самодельный хостинг vs. хостинг “из коробки”</h3> + +<p>Когда вы хотите опубликовать веб-сайт, вы можете сделать все самостоятельно: настроить базу данных (если требуется), Систему управления наполнением, или {{Glossary("CMS")}} (такую как <a href="http://wordpress.org/">Wordpress</a>, <a href="http://dotclear.org/">Dotclear</a>, <a href="http://www.spip.net/en_rubrique25.html">spip</a>, и тд.), загружать заранее подготовленные вами шаблоны.</p> + +<p>Вы можете использовать среду хостинг-провайдера, примерно за 10-15 долларов в месяц, или подписаться напрямую к удаленному хостинг-сервису с предустановленным CMSs (такие как, <a href="http://wordpress.com/">Wordpress</a>, <a href="https://www.tumblr.com/">Tumblr</a>, <a href="https://www.blogger.com/">Blogger</a>). В последнем случае, вам не придется платить ни за что, но вы будете иметь меньше контроля над шаблонами и другими элементами.</p> + +<h3 id="Бесплатный_хостинг_vs._платный">Бесплатный хостинг vs. платный</h3> + +<p>Вы могли бы задать вопрос, почему мне следует платить за хостинг, когда существует так много бесплатных сервисов?</p> + +<ul> + <li>У вас есть больше свободы, когда вы платите. Ваш веб-сайт только в ваших руках, и вы можете легко перейти от одного хостинг-провайдера к другому.</li> + <li>Бесплатные хостинги могут добавлять рекламные обьявления к вашему контенту, в обход вашего контроля.</li> +</ul> + +<p>Лучше обратиться к платному хостингу, чем полагаться на бесплатный, так как большинство платных сайтов гарантируют бесперебойную работу и позволяют с легкостью управлять файловой структурой. Большинство хостинг-провайдеров предоставят вам огромную скидку для старта.</p> + +<p>Некоторые люди выбирают смешанный подход. Например, их главный блог на платном хосте, с полным доменном именем, а неожиданный менее важный контент, на бесплатном хосте.</p> + +<h2 id="Профессиональные_веб-сайты_агенств_и_хостингов">Профессиональные веб-сайты агенств и хостингов</h2> + +<p>Если вы хотите профессиональный веб-сайт, вы можете обратиться в агентство по веб-разработке, чтобы оно сделало его для вас.<br> + <br> + Здесь перечислены расходы, зависящие сразу от нескольких факторов:</p> + +<ul> + <li>Это простой веб-сайт с парой страничек текста? Или более сложный, с около тысячей страниц?</li> + <li>Будете ли вы его обновлять регулярно? или это будет статический веб-сайт?</li> + <li>Должен ли веб-сайт подсоединяться к IT структуре вашей компании, чтобы собирать контент (например, внутренние данные)?</li> + <li>Хотите ли вы какую-нибудь уникальную функцию, которая сейчас в моде?</li> + <li>Хотите ли вы, чтобы агенство решало сложные проблемы пользователей {{Glossary("UX")}}?</li> +</ul> + +<p>...и для хостинга:</p> + +<ul> + <li>Хотите ли вы имет резервный сервер, если вдруг ваш упадет?</li> + <li>Надежность 95%, или вам требуется круглосуточный сервис обслуживания?</li> + <li>Вам нужны высокопроизводительные, сверхчувствительные удаленные серверы или вам будет достаточно более медленной, машиной, предназначенной для совместного использования.</li> +</ul> + +<p>В зависимости от ответа на эти вопросы, ваш сайт может обойтись вам в тысячи или даже сотни тысяч долларов.</p> + +<h2 id="Следующие_шаги">Следующие шаги</h2> + +<p>На данный момент у вас есть понимание того, во сколько вам может обойтись ваш сайт, так что настало время проектирования веб-сайта и <a href="/en-US/docs/Learn/Set_up_a_basic_working_environment">настройки вашего рабочего пространства.</a></p> + +<ul> + <li>Прочитайте о том, <a href="/en-US/docs/Learn/Choose,_Install_and_set_up_a_text_editor">как выбрать и установить текстовый редактор</a>.</li> + <li>Если вы больше сфокусированы на проектировании, взгляните на <a href="/en-US/Learn/Anatomy_of_a_web_page">анатомию веб-страницы</a>.</li> +</ul> diff --git a/files/ru/learn/common_questions/index.html b/files/ru/learn/common_questions/index.html new file mode 100644 index 0000000000..7fa9b16baf --- /dev/null +++ b/files/ru/learn/common_questions/index.html @@ -0,0 +1,131 @@ +--- +title: Распространённые вопросы +slug: Learn/Common_questions +tags: + - Веб + - Механика Веба + - распространённые вопросы +translation_of: Learn/Common_questions +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Данный раздел создан для обеспечения ответами на распространённые вопросы, которые могут возникнуть и которые не обязательно являются основным материалом при изучении веб-технологий (например, обучающих статей по <a href="/ru/docs/Learn/HTML">HTML</a> или <a href="/ru/docs/Learn/CSS">CSS</a>). Ниже приведённые статьи созданы для самостоятельной работы над их содержимым.</p> + +<h2 id="Как_работает_Всемирная_паутина">Как работает Всемирная паутина?</h2> + +<p>Данный раздел покрывает "механику" Всемирной паутины — вопросы, относящиеся к общим знаниям о экосистеме Всемирной паутины и тому, как эта экосистема работает.</p> + +<dl> + <dt> + <h3 id="Как_работает_Интернет"><a href="/ru/docs/Learn/Common_questions/How_does_the_Internet_work">Как работает Интернет?</a></h3> + </dt> + <dd><strong>Интернет</strong> - основа Всемирной паутины; техническая инфраструктура, благодаря которой возможно существование Всемирной паутины. Выражаясь проще, Интернет - это большая сеть компьютеров, которые "общаются" друг с другом. В данной статье обсуждается, как он (Интернет) работает на базовом уровне.</dd> + <dt> + <h3 id="В_чём_разница_между_веб-страницей_веб-сайтом_веб-сервером_и_поисковым_движком"><a href="/ru/docs/Learn/Common_questions/Pages_sites_servers_and_search_engines">В чём разница между веб-страницей, веб-сайтом, веб-сервером и поисковым движком?</a></h3> + </dt> + <dd>В этой статье мы рассмотрим различные связанные с вебом концепции: веб-страницы, веб-сайты, веб-сервера и поисковые движки. Новички в вебе часто путают или неправильно используют данные термины. Давайте узнаем, что они означают!</dd> + <dt> + <h3 id="Что_такое_URL"><a href="/ru/docs/Learn/Common_questions/What_is_a_URL">Что такое URL?</a></h3> + </dt> + <dd>Наряду с понятиями <a href="/ru/docs/Glossary/Hypertext">гипертекста</a> и <a href="/ru/docs/Glossary/HTTP">протокола HTTP</a>, понятие <a href="/ru/docs/Glossary/URL">URL</a> является одной из основных концепций Всемирной паутины. Это механизм, используемый <a href="/ru/docs/Glossary/Browser">браузерами</a> для получения любого опубликованного во Всемирной сети ресурса.</dd> + <dt> + <h3 id="Что_такое_доменное_имя"><a href="/ru/docs/Learn/Common_questions/What_is_a_domain_name">Что такое доменное имя?</a></h3> + </dt> + <dd>Доменные имена являются ключевой частью инфраструктуры сети Интернет. С их помощью обеспечивается удобочитаемый адрес для любого веб-сервера, доступного в сети Интернет.</dd> + <dt> + <h3 id="Что_такое_веб-сервер"><a href="/ru/docs/Learn/Common_questions/What_is_a_web_server">Что такое веб-сервер?</a></h3> + </dt> + <dd>Термин «<a href="/ru/docs/Glossary/Server">веб-сервер</a>» может относиться к оборудованию или программному обеспечению (ПО), которое предоставляет клиентам доступ к веб-сайтам через сеть Интернет, или к ним обоим (оборудованию и ПО), работающим вместе. В этой статье мы рассмотрим, как работают веб-серверы и то, почему они важны.</dd> + <dt> + <h3 id="Что_такое_гиперссылки"><a href="/ru/docs/Learn/Common_questions/What_are_hyperlinks">Что такое гиперссылки?</a></h3> + </dt> + <dd>В этой статье мы рассмотрим, что такое <a href="/ru/docs/Glossary/Hyperlink">гиперссылки</a> и почему они важны.</dd> +</dl> + +<h2 id="Инструменты_и_настройка">Инструменты и настройка</h2> + +<p>Вопросы, связанные с инструментами / программным обеспечением, которое вы можете использовать для создания веб-сайтов.</p> + +<dl> + <dt> + <h3 id="Сколько_стоит_сделать_что-то_в_Интернете"><a href="/ru/docs/Learn/Common_questions/How_much_does_it_cost">Сколько стоит сделать что-то в Интернете?</a></h3> + </dt> + <dd>Когда вы запускаете веб-сайт, вы можете ничего не потратить, или ваши расходы могут быть достаточно высокими. В этой статье мы обсудим, сколько всё стоит и что вы получаете за то, за что вы платите (или не платите).</dd> + <dt> + <h3 id="Какое_ПО_мне_необходимо_для_создания_веб-сайта"><a href="/ru/docs/Learn/Common_questions/What_software_do_I_need">Какое ПО мне необходимо для создания веб-сайта?</a></h3> + </dt> + <dd>В этой статье мы объясним, какие программные компоненты необходимы вам при редактировании, выгрузке или просмотре веб-сайта.</dd> + <dt> + <h3 id="Какие_текстовые_редакторы_доступны"><a href="/ru/docs/Learn/Common_questions/Available_text_editors">Какие текстовые редакторы доступны?</a></h3> + </dt> + <dd>В этой статье мы выделили некоторые моменты, которые следует учитывать при выборе и установке текстового редактора для веб-разработки.</dd> + <dt> + <h3 id="Что_такое_Инструменты_разработчика_браузера"><a href="/ru/docs/Learn/Common_questions/What_are_browser_developer_tools">Что такое "Инструменты разработчика" браузера?</a></h3> + </dt> + <dd>Каждый браузер имеет набор инструментов разработчика для отладки HTML, CSS и другого веб-кода. В этой статье объясняется, как использовать основные функции из инструментов разработчика вашего браузера.</dd> + <dt> + <h3 id="Как_убедиться_в_том_что_веб-сайт_работает_правильно"><a href="/ru/docs/Learn/Common_questions/Checking_that_your_web_site_is_working_properly">Как убедиться в том, что веб-сайт работает правильно?</a></h3> + </dt> + <dd>Итак, вы опубликовали свой сайт в Интернете - очень хорошо! Но уверены ли вы в том, что он работает правильно? В этой статье приведены некоторые основные шаги по устранению неполадок.</dd> + <dt> + <h3 id="Как_настроить_локальный_сервер_тестирования"><a href="/ru/docs/Learn/Common_questions/set_up_a_local_testing_server">Как настроить локальный сервер тестирования?</a></h3> + </dt> + <dd> + <div> + <p>В этой статье объясняется, как настроить простой локальный сервер тестирования на вашем компьютере, и основы его использования.</p> + </div> + </dd> + <dt> + <h3 id="Как_загрузить_файлы_на_веб-сервер"><a href="/ru/docs/Learn/Common_questions/Upload_files_to_a_web_server">Как загрузить файлы на веб-сервер?</a></h3> + </dt> + <dd>В этой статье показано, как публиковать свой сайт в Интернете с помощью инструментов FTP - одним из самых распространенных способов сделать сайт общедоступным, чтобы другие пользователи могли получить доступ к нему со своих компьютеров.</dd> + <dt> + <h3 id="Как_использовать_GitHub_Pages"><a href="/ru/docs/Learn/Common_questions/Using_GitHub_Pages">Как использовать GitHub Pages?</a></h3> + </dt> + <dd>В этой статье представлено базовое руководство по публикации контента с использованием функции <strong>gh-pages</strong> сайта GitHub.</dd> + <dt> + <h3 id="Как_разместить_сайт_в_Интернете_при_помощи_платформы_Google_App_Engine"><a href="/en-US/Learn/Common_questions/How_do_you_host_your_website_on_Google_App_Engine">Как разместить сайт в Интернете при помощи платформы Google App Engine?</a></h3> + </dt> + <dd>Ищете место для размещения вашего сайта? Здесь представлено пошаговое руководство по размещению вашего сайта с помощью платформы Google App Engine.</dd> + <dt> + <h3 id="Какие_существуют_инструменты_для_отладки_сайта_и_увеличения_его_производительности"><a href="/ru/docs/Tools/Performance">Какие существуют инструменты для отладки сайта и увеличения его производительности?</a></h3> + </dt> + <dd>В этом группе статей рассказывается, как использовать инструменты разработчика в браузере Firefox для отладки и повышения производительности вашего веб-сайта, а именно инструменты для проверки использования памяти, просмотра дерева вызовов <a href="/ru/docs/Glossary/JavaScript">JavaScript</a>, количества отображаемых узлов <a href="/ru/docs/Glossary/DOM">DOM</a> и т. д.</dd> +</dl> + +<h2 id="Дизайн_и_удобство_использования">Дизайн и удобство использования</h2> + +<p>В этом разделе перечислены вопросы, связанные с эстетикой, структурой страницы, техниками для достижения удобства пользованием сайта и т. д.</p> + +<dl> + <dt> + <h3 id="С_чего_мне_следует_начать_создание_дизайна_веб-сайта"><a href="/ru/docs/Learn/Common_questions/Thinking_before_coding">С чего мне следует начать создание дизайна веб-сайта?</a></h3> + </dt> + <dd>В этой статье рассматривается крайне важный первый шаг каждого проекта: определение того, чего вы хотите достичь с его помощью.</dd> + <dt> + <h3 id="Какова_структура_наиболее_используемых_макетов_сайтов"><a href="/ru/docs/Learn/Common_questions/Common_web_layouts">Какова структура наиболее используемых макетов сайтов?</a></h3> + </dt> + <dd>При разработке страниц вашего сайта хорошо иметь представление о наиболее распространенных макетах. В этой статье приведены некоторые типичные макеты веб-сайтов, а также части, которые входят в каждый макет.</dd> + <dt> + <h3 id="Что_такое_удобство_использования"><a href="/ru/docs/Learn/Common_questions/What_is_accessibility">Что такое удобство использования?</a></h3> + </dt> + <dd>В этой статье представлены основные концепции достижения удобства пользования веб-страницами.</dd> + <dt> + <h3 id="Как_разрабатывать_сайты_для_всех_категорий_пользователей"><a href="/ru/docs/Learn/Common_questions/Design_for_all_types_of_users">Как разрабатывать сайты для всех категорий пользователей?</a></h3> + </dt> + <dd>В этой статье приводятся основные методы, которые помогут вам создавать веб-сайты для любого пользователя.</dd> + <dt> + <h3 id="Какие_средства_HTML_используются_для_обеспечения_удобства_использования"><a href="/ru/docs/Learn/Common_questions/HTML_features_for_accessibility">Какие средства HTML используются для обеспечения удобства использования?</a></h3> + </dt> + <dd>В этой статье описываются специфические особенности HTML, которые могут использоваться для того, чтобы сделать веб-страницу более доступной для людей с различными нарушениями.</dd> +</dl> + +<h2 id="Вопросы_по_HTML_CSS_и_JavaScript">Вопросы по HTML, CSS и JavaScript</h2> + +<p>Чтобы узнать о распространённых решениях большинства проблем в HTML / CSS / JavaScript, используйте следующие статьи:</p> + +<ul> + <li><a href="/ru/docs/Learn/HTML/Howto">Использование HTML для решения распространённных проблем</a></li> + <li><a href="/ru/docs/Learn/CSS/Howto">Использование CSS для решения распространённых проблем </a></li> + <li><a href="/ru/docs/Learn/JavaScript/Howto">Использование JavaScript для решения распрстранённых проблем</a></li> +</ul> diff --git a/files/ru/learn/common_questions/set_up_a_local_testing_server/index.html b/files/ru/learn/common_questions/set_up_a_local_testing_server/index.html new file mode 100644 index 0000000000..0ab424414d --- /dev/null +++ b/files/ru/learn/common_questions/set_up_a_local_testing_server/index.html @@ -0,0 +1,97 @@ +--- +title: Как настроить локальный сервер для тестирования? +slug: Learn/Common_questions/set_up_a_local_testing_server +translation_of: Learn/Common_questions/set_up_a_local_testing_server +--- +<div class="summary"> +<p>Эта статья объясняет как установить простой локальный тестовый сервер на Вашем компьютере, а так же основы его использования.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Сначала Вам необходимо изучить <a href="/en-US/docs/Learn/How_the_Internet_works">как работает интернет</a>, а также <a href="/en-US/docs/Learn/What_is_a_Web_server">что такое веб-сервер</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Вы научитесь как установливать локальный тестовый сервер.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Локальные_и_удаленные_файлы">Локальные и удаленные файлы</h2> + +<p>На протяжении всего обучения, вы будете открывать примеры непосредственно в браузере — двойным кликом по HTML файлу, перетаскиванием файла в окно браузера, или через меню <em>File</em> > <em>Open...</em> и указывая необходимый HTML файл. Существует множество способов как это сделать.</p> + +<p>Если веб-адрес начинается с <code>file://</code> в котором далее прописан путь к файлу на вашем локальном жестком диске, значит используется локальный файл. В противоположность этому, если вы откроете на просмотр один из наших примеров, расположенных на GitHub (или пример расположенный на любом другом удаленном сервере), веб-адресс будет начинаться с <code>http://</code> или <code>https://</code>, что означает что файл был получен через HTTP.</p> + +<h2 id="Проблемы_тестирования_локальных_файлов">Проблемы тестирования локальных файлов</h2> + +<p>Некоторые примеры могут не запуститься, если вы попробуете открыть их как локальные файлы. Это может произойти по нескольким причинам, самые распространенные из которых:</p> + +<ul> + <li><strong>Они содержат ассинхронные запросы.</strong> Некоторые браузеры (включая Chrome) не будут запускать асинхронные запросы (см. <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a>), если вы просто запускаете пример из локального файла. Это связано с ограничениями безопасности (для получения дополнительной информации о безопасности в Интернете, ознакомьтесь с <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a>).</li> + <li><strong>Они имеют серверный язык.</strong> Серверные языки (например, PHP или Python) требуют специального сервера для интерпретации кода и предоставления результатов.</li> +</ul> + +<h2 id="Запуск_простого_локального_HTTP_сервера">Запуск простого локального HTTP сервера</h2> + +<p>Чтобы обойти проблему ассинхронных запросов, нам нужно протестировать такие примеры, запустив их через локальный веб-сервер. Один из самых простых способов сделать это для наших целей - использовать модуль <code>SimpleHTTPServer</code> Python.</p> + +<p>Для этого нужно:</p> + +<ol> + <li> + <p>Установить Python. Если Вы пользуетесь Linux или Mac OS X, все уже готово в Вашей системе. Если Вы пользователь Windows, Вы можете скачать установочный файл с домашней страницы Python:</p> + + <ul> + <li>Зайдите на <a href="https://www.python.org/">python.org</a></li> + <li>В секции загрузок, выберите линк для Python "3.xxx".</li> + <li>Внизу страницы выберите <em>Windows x86 executable installer</em> и скачайте его.</li> + <li>Послезагрузки файла запустите его.</li> + <li>На первой странице инсталлятора выберите чекбокс "Add Python 3.xxx to PATH".</li> + <li>Нажмите <em>Install</em>, затем нажмите <em>Close</em> когда установка закончится.</li> + </ul> + </li> + <li> + <p>Откройте командную строку (Windows)/ (OS X/Linux). Для проверки установки Python введите следующую команду:</p> + + <pre class="brush: bash notranslate">python -V</pre> + </li> + <li> + <p>Система вернет Вам номер версии установленной программы. В случае успешного выполнения команды <code>python -V </code> нужно перейти в директорию с вашим проектом, используя команду <code>cd</code>:</p> + + <pre class="brush: bash notranslate"># include the directory name to enter it, for example +cd Desktop +# use two dots to jump up one directory level if you need to +cd ..</pre> + </li> + <li> + <p>Введите команду для запуска сервера в том каталоге:</p> + + <pre class="brush: bash notranslate"># If Python version returned above is 3.X +python -m http.server +# If Python version returned above is 2.X +python -m <code>SimpleHTTPServer</code></pre> + </li> + <li> + <p>По умолчанию это приведет к запуску содержимого каталога на локальном веб-сервере на порту 8000. Вы можете перейти на этот сервер, перейдя на URL-адрес <code>localhost: 8000</code> в своем веб-браузере. Здесь вы увидите содержимое указанного каталога - щелкните файл HTML, который вы хотите запустить.</p> + </li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>. Если у вас уже есть что-то на порту 8000, вы можете выбрать другой порт, запустив команду сервера, за которой следует альтернативный номер порта, например: <code>python -m http.server 7800</code> (Python 3.x) или <code>python -m SimpleHTTPServer 7800</code> (Python 2.x). Затем вы можете получить доступ к своему контенту на <code>localhost: 7800</code>.</p> +</div> + +<h2 id="Запуск_серверных_языков_локально">Запуск серверных языков локально</h2> + +<p>Модуль Python <code>SimpleHTTPServer (python 2.0) http.server (python 3.0)</code> полезен, но он не знает, как запускать код, написанный на таких языках, как Python, PHP или JavaScript. Чтобы справиться с этим, вам понадобится нечто большее - именно то, что вам нужно, зависит от языка сервера, который вы пытаетесь запустить. Вот несколько примеров:</p> + +<ul> + <li>Для запуска кода на стороне сервера Python вам необходимо использовать веб-инфраструктуру Python. Вы можете узнать, как использовать структуру Django, прочитав <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django">Django Web Framework (Python)</a>. <a href="http://flask.pocoo.org/">Flask</a> также является хорошей (чуть менее тяжелой) альтернативой Django. Чтобы запустить это, ознакомьтесь с <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/development_environment#Installing_Python_3">install Python/PIP</a>, а затем установите Flask с помощью <code>pip3 install flask</code>. На этом этапе вы сможете запустить примеры Python Flask, используя, например, <code>python3 python-example.py</code>, затем перейдя на <code>localhost: 5000</code> в свой браузер.</li> + <li>Чтобы запустить серверный код Node.js (JavaScript), вам нужно использовать Node.js или фреймворк, построенный поверх него. Express - хороший выбор - см. <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs">Express Web Framework (Node.js/JavaScript)</a>.</li> + <li>Чтобы запустить PHP-серверный код, вам понадобится настройка сервера, которая может интерпретировать PHP. Хорошими вариантами для локального тестирования PHP являются <a class="external external-icon" href="https://www.mamp.info/en/downloads/">MAMP</a> (Mac и Windows), <a class="external external-icon" href="http://ampps.com/download">AMPPS</a> (Mac, Windows, Linux) и <a href="https://www.linux.com/learn/easy-lamp-server-installation">LAMP</a> (Linux, Apache, MySQL и PHP / Python / Perl). Это полные пакеты, которые создают локальные настройки, позволяющие запускать базы данных Apache, PHP и MySQL.</li> +</ul> diff --git a/files/ru/learn/common_questions/thinking_before_coding/index.html b/files/ru/learn/common_questions/thinking_before_coding/index.html new file mode 100644 index 0000000000..7d9243ac0d --- /dev/null +++ b/files/ru/learn/common_questions/thinking_before_coding/index.html @@ -0,0 +1,176 @@ +--- +title: Как начать разрабатывать свой сайт? +slug: Learn/Common_questions/Thinking_before_coding +tags: + - Включает активное обучение + - Для начинающих + - Необходимое Схематично + - Планирование +translation_of: Learn/Common_questions/Thinking_before_coding +--- +<p class="summary">Эта статья покрывает первый и крайне важный шаг в создании любого проекта: определить, что вы хотите получить.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Никаких</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Научиться определять цели, которые позволят дать направление вашему web-проекту.</td> + </tr> + </tbody> +</table> + +<h2 id="Определение_идеи_проекта">Определение идеи проекта</h2> + +<p><span class="seoSummary">Большинство людей, начиная свой web-проект, фокусируются прежде всего на технической его стороне. Безусловно, вы должны иметь представление о технической стороне своей работы, но гораздо важнее сперва узнать, что вы хотели бы получить в результате. Конечно это кажется очевидным, однако слишком много проектов не доживают до релиза не из-за отсутствия технических знаний, но из-за отсутствия целей и видения.</span></p> + +<p>Так что когда у вас появляется какая-то идея и желание воплотить ее в web-сайте, вам необходимо ответить на 3 простых вопроса, и уже потом предпринимать что-либо иное :</p> + +<ul> + <li>Что я хочу в конце-концов получить?</li> + <li>Каким образом web-сайт поможет мне в достижении моих целей?</li> + <li>Что и в каком порядке должно быть реализовано, чтобы достичь моих целей?</li> +</ul> + +<p>Совокупность и анализ ответов на эти вопросы поможет определить <em>идею проекта</em>, которая является <strong>необходимым</strong> первым шагом в достижении ваших целей, вне зависимости от того, имеется ли у вас опыт разработки или же вы новичек.</p> + +<h2 id="Активное_Обучение">Активное Обучение</h2> + +<p><em>На данный момент этот раздел еще не готов. Вы можете помочь сообществу разработчиков, вступив в <a href="https://developer.mozilla.org/en-US/docs/MDN/Getting_started">Please, consider contributing</a>.</em></p> + +<h2 id="Более_глубокое_погружение">Более глубокое погружение</h2> + +<p>Проект никогда не начинается с реализации. Музыканты никогда не делали бы музыку, пока не решили, что же они хотят сыграть, аналогию можно провести к художникам, писателям, и web-разработчикам. Реализация второстепенна.</p> + +<p>Технические навыки безусловно важны. Музыканты обязаны владеть своим инструментом. Но даже хороший музыкант никогда не создаст хорошую музыку не имея идеи. Следовательно, прежде чем переходить к вашей любимой IDE, вы должны отойти немного назад и детально представить, что же вы на самом деле хотите сделать.</p> + +<p>Часовая конференция-обсуждение с вашими друзьями - хорошее начало, но не совсем рациональное. Лучше будет спокойно сесть и структурировать всю информацию, это позволит вам получить наиболее адекватное представление пути к реализации вашей идеи. Для этого вам нужны лишь только листочек, ручка и немного времени для ответа на следующие вопросы.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Имеется неисчислимое множество способов, как сформулировать идею проекта. К сожалению, мы не можем собрать здесь все сразу (и даже увесистой книги не хватит). То, что мы представляем в этой статье - это простой способ выполнить шаги, которые профессионалы называют <a href="http://en.wikipedia.org/wiki/Ideation_(idea_generation)">Project Ideation</a>, <a href="http://en.wikipedia.org/wiki/Project_planning">Project Planning</a> и <a href="http://en.wikipedia.org/wiki/Project_management">Project Management</a>.</p> +</div> + +<h3 class="highlight-spanned" id="Что_же_в_конце_концов_я_хочу_получить"><span class="highlight-span">Что же в конце концов я хочу получить?</span></h3> + +<p>Этот вопрос наиболее остро нуждается в ответе, поскольку ответ является решающим в дальнейших действиях. Лучше всего подойдет список целей, которых вы хотите достичь. Это может быть что угодно: интернет-магазин, выражение политических взглядов, расширение круга общения, организация концертов, коллекционирование картинок с котиками, или что угодно еще, что вы хотите получить.</p> + +<p>Представьте себя музыкантом. Должно быть, вы хотите:</p> + +<ul> + <li>Предоставить людям возможность прослушать ваше творчество.</li> + <li>Создать интернет-магазин.</li> + <li>Наладить контакт с другими музыкантами.</li> + <li>Поговорить о музыке.</li> + <li>Обучать своему творчеству с помощью видео-уроков.</li> + <li>Публиковать фото вашего кота.</li> + <li>Найти нового друга (подругу).</li> +</ul> + +<p>Когда вы получили такой список, необходимо упорядочить его согласно приоритетам. Разместим цели в порядке убывания важности:</p> + +<ol> + <li>Найти нового друга (подругу).</li> + <li>Предоставить людям возможность прослушать ваше творчество.</li> + <li>Поговорить о музыке.</li> + <li>Наладить контакт с другими музыкантами.</li> + <li>Создать интернет-магазин.</li> + <li>Обучать своему творчеству с помощью видео-уроков.</li> + <li>Публиковать фото вашего кота.</li> +</ol> + +<p>Выполнив это простое упражнение, написав ваши цели и отсортировав их, вам будет гораздо легче принимать решения. (Нужно ли мне добавить какие-то возможности, использовать эти или иные сервисы, создавать именно <em>такой</em> дизайн?)</p> + +<p>Теперь, когда вы получили приоритетный список ваших целей, имеет смысл перейти к следующему вопросу.</p> + +<h3 class="highlight-spanned" id="Как_сайт_поможет_мне_в_достижении_цели"><span class="highlight-span">Как сайт поможет мне в достижении цели?</span></h3> + +<p>И так, у вас есть конкретная цель и вам кажется, что для ее достижения нужен веб-сайт. Вы уверены?</p> + +<p>Вернемся к нашему примеру. У нас есть 5 задач, связанных с музыкой, одна из области личной жизни (поиск своей пары), и ни с чем не связанные фото кота. Есть ли смысл создавать сайт, который способен удовлетворить всем этим требованиям? Так ли это необходимо? В конце концов, десятки уже существующих web-сервисов способны помочь вам в достижении ваших целей.</p> + +<p>Поиск пары - главная задача, и более разумно использовать уже существующие ресурсы, чем создавать свой. Почему? Мы потратим больше времени на создание и поддержание сайта чем на поиск своей потенциальной пары. Пока эта цель сохраняет наибольший приоритет, логичнее тратить время и силы на использование (освоение) существующего инструмента, чем начинать его создание с нуля. Аналогично, существует достаточное количество сайтов, которые уже предоставляют возможность демонстрации фотографий, чтобы на создание еще одного можно было очень коротко ответить: это того не стоит.</p> + +<p>Оставшиеся пять задач непосредственно связанны с музыкой. Конечно же, на данный момент уже достаточно сайтов, обладающих подобным функционалом, но в текущем контексте имеет смысл создать сайт, посвященный именно вам. Прежде всего, сайт - это лучший способ <em>чтобы собрать все</em>, что мы хотим опубликовать, в одном месте (для решения проблем под номерами 3, 5 и 6) и создать среду для взаимодействия между нами и публикой (для решения проблем 2 и 4). Если проще, то так как все эти задачи из одной области, содержание всего в одном месте (веб-сайте) поможет нам в достижении целей, а также поможет нашим поклонникам связаться с нами.</p> + +<p>Как способен сайт помочь мне решить мои проблемы? Ответив на это, вы найдете наилучшее решение для себя и убережетесь от траты усилий впустую.</p> + +<h3 class="highlight-spanned" id="Что_и_в_какие_сроки_должно_быть_реализовано_для_достижения_целей"><span class="highlight-span">Что и в какие сроки должно быть реализовано для достижения целей?</span></h3> + +<p>Теперь, когда вы уже узнали, что вам на самом деле нужно, настало время составить план, раскладывающий ваши цели на небольшие выполнимые шаги. Еще нужно помнить, что все ваши планы не есть догмы. Они постоянно эволюционируют вместе с изменением курса проекта. К примеру, если вы вдруг вспомните о чем-то ранее неучтенном, или просто измените свое видение проекта.</p> + +<p>Как водится, лучше один раз увидеть, чем сто раз услышать, так что вернемся к нашему примеру:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Цель</th> + <th scope="col">План по достижению</th> + </tr> + </thead> + <tbody> + <tr> + <td style="vertical-align: top;">Предоставить людям доступ к вашему творчеству</td> + <td> + <ol> + <li>Записать музыку</li> + <li>Опубликовать ваши аудиозаписи в сети (Можете ли вы использовать для этого существующие сервисы?)</li> + <li>Предоставить людям доступ к вашей музыке в некоторых частях вашего сайта</li> + </ol> + </td> + </tr> + <tr> + <td style="vertical-align: top;">Обсудить вашу музыкальную деятельность</td> + <td> + <ol> + <li>Написать несколько статей для затравки обсуждений</li> + <li>Определить, как должны быть оформлены статьи</li> + <li>Опубликовать готовые тексты на вашем сайте (Как это делается?)</li> + </ol> + </td> + </tr> + <tr> + <td style="vertical-align: top;">Познакомиться с коллегами по цеху</td> + <td> + <ol> + <li>Предоставить людям способ связаться с вами (Email? Соц. сеть? Номер телефона? Письмо?)</li> + <li>Определить, как люди могут узнать эти данные на вашем сайте</li> + </ol> + </td> + </tr> + <tr> + <td style="vertical-align: top;">Создать интернет-магазин</td> + <td> + <ol> + <li>Приготовить их</li> + <li>Разместить в магазине</li> + <li>Найти способ доставки</li> + <li>Определиться с платежной системой</li> + <li>Добавить способ делать заказы на вашем сайте</li> + </ol> + </td> + </tr> + <tr> + <td style="vertical-align: top;">Обучать музыке в своих видео-уроках</td> + <td> + <ol> + <li>Записать видео-уроки</li> + <li>Разместить видео в онлайне (И снова: стоит ли использовать для этого уже готовые платформы?)</li> + <li>Предоставить людям доступ к видео на вашем сайте (проинформировать)</li> + </ol> + </td> + </tr> + </tbody> +</table> + +<p><strong>Два важных замечания.</strong></p> + +<p>Во-первых, некоторые из этих задач не привязаны к интернету (к примеру, запись музыки или написание статей). И очень часто такие "офлайн" вещи играют большую роль в достижении целей, чем сам сайт. В продажах, к примеру, гораздо большее значение и тяжелую реализацию представляют решения вопросов доставки, оплаты и налогообложения, чем непосредственная реализация сайта с возможностью оформления заказов.</p> + +<p>Во-вторых, написание плана порождает новые вопросы, которые тоже нуждаются в ответах. И, как правило, этих вопросов больше чем рассмотренно в этой статье. (К примеру, можете ли вы сделать что-то из плана самостоятельно, лучше попросить кого-то из знакомых или придётся прибегнуть к помощи третьих лиц?)</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Как стало понятно, простая мысль "А не сделать ли мне сайт?" порождает очень много работы, и при каждом следующем обдумывании она только растет. В скором она может стать очень большой, но это не повод для паники. Вы не обязаны отвечать на <em>все </em>вопросы, а также выполнять каждый пункт плана. Что действительно имеет значение, так это ваше видение результата и понимание целей. Однажды создав идею, вам нужно определиться, как и когда ее реализовать. Разбивайте большие задачи на меньшие и более выполнимые. И каждая выполненная задача приблизит вас к грандиозному успеху.</p> diff --git a/files/ru/learn/common_questions/upload_files_to_a_web_server/index.html b/files/ru/learn/common_questions/upload_files_to_a_web_server/index.html new file mode 100644 index 0000000000..2f156c3985 --- /dev/null +++ b/files/ru/learn/common_questions/upload_files_to_a_web_server/index.html @@ -0,0 +1,168 @@ +--- +title: Как загрузить файлы на веб-сервер +slug: Learn/Common_questions/Upload_files_to_a_web_server +translation_of: Learn/Common_questions/Upload_files_to_a_web_server +--- +<div class="summary"> +<p>Данная статья покажет, как можно опубликовать сайт в Интернет с помощью инструментов передачи файлов(file transfer tools).</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Вы должны знать <a href="https://developer.mozilla.org/ru/docs/Learn/%D0%A7%D1%82%D0%BE_%D1%82%D0%B0%D0%BA%D0%BE%D0%B5_%D0%B2%D0%B5%D0%B1_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80">что такое веб-сервер</a> и <a href="https://developer.mozilla.org/ru/docs/Learn/Understanding_domain_names">как работают доменные имена</a>. Также вы должны знать, <a href="https://developer.mozilla.org/ru/docs/Learn/Common_questions/set_up_a_local_testing_server">как установить базовую среду</a> и <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web">как написать простую веб-страницу</a>.</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Научиться передавать файлы на сервер используя различные доступные инструменты передачи файлов(file transfer tools).</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Сводка">Сводка</h2> + +<p>Если вы создали простую веб-страницу (для примера смотрите <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a>), вы, вероятно, захотите отобразить её онлайн, на веб-сервере. В данной статье мы обсудим как сделать это, используя различные доступные настройки, такие как SFTP клиенты, RSync и GitHub.</p> + +<h2 id="SFTP_Безопасный_Протокол_Передачи_Файлов">SFTP (Безопасный Протокол Передачи Файлов)</h2> + +<p>Существуют различные варианты SFTP клиентов. В нашем примере мы будем использовать <a href="https://filezilla-project.org/">FileZilla</a>, тк он бесплатен и подходит для Windows, macOS и Linux. Чтобы установить менеджер перейдите на страницу загрузки <a href="https://filezilla-project.org/download.php?type=client">FileZilla downloads page</a>, нажмите на кнопку загрузки, затем установите пакет из установочного файла обычным способом.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Конечно, есть много других вариантов. Смотрите <a href="/en-US/Learn/How_much_does_it_cost#Publishing_tools.3A_FTP_client">Publishing tools</a> для других способов.</p> +</div> + +<p>Откройте приложение FileZilla; Вы должны увидеть что-то вроде этого:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15767/filezilla-ui.png" style="display: block; height: 451px; margin: 0px auto; width: 690px;"></p> + +<h3 id="Вход_в_систему">Вход в систему</h3> + +<p>В этом примере мы предположим, что наш хостинг-провайдер (сервис, на котором находится наш HTTP веб сервер) является фиктивной компанией "Example Hosting Provider", чьи URL адреса выглядят следующим образом: <code>mypersonalwebsite.examplehostingprovider.net</code>.</p> + +<p>Сейчас мы создали аккаунт и получили от хостинг-провайдера следующую информацию:</p> + +<blockquote> +<p>Поздравляем с созданием аккаунта на сервисе "Example Hosting Provider".</p> + +<p>Ваш аккаунт: <code>demozilla</code></p> + +<p>Ваш сайт доступен по адресу:</p> + +<p><code>demozilla.examplehostingprovider.net</code></p> + +<p>Для загрузки файлов на этот аккаунт, пожалуйста, подключитесь через SFTP с использованием следующих учетных данных:</p> + +<ul> + <li>SFTP сервер: <code>sftp://demozilla.examplehostingprovider.net</code></li> + <li>Имя пользователя: <code>demozilla</code></li> + <li>Пароль: <code>quickbrownfox</code></li> + <li>Порт: <code>5548</code></li> + <li>Для публикации в интернет, поместите ваши файлы в папку <code>Public/htdocs</code> .</li> +</ul> +</blockquote> + +<p>Давайте сначала посмотрим на <code>http://demozilla.examplehostingprovider.net/</code> — как вы можете видеть, то здесь пока ничего нет:</p> + +<p><img alt="Our demozilla personal website, seen in a browser: it's empty" src="https://mdn.mozillademos.org/files/9615/demozilla-empty.png" style="border-style: solid; border-width: 1px; display: block; height: 233px; margin: 0 auto; width: 409px;"></p> + +<div class="note"> +<p><strong>Заметка</strong>: В зависимости от вашего хостинг-провайдера, когда вы впервые заходите на свой веб-адрес, большую часть времени вы будете видеть страницу, на которой написано что-то вроде этого: “This website is hosted by [Hosting Service].”</p> +</div> + +<p>Чтобы подключить SFTP клиент к удаленному серверу, выполните следующие действия:</p> + +<ol> + <li>Выбирите <em>File > Site Manager...</em> в главном меню.</li> + <li>В окне <em>Site Manager</em>, нажмите кнопку <em>New Site</em>, затем введите название сайта как <strong>demozilla</strong> в предоставленном месте.</li> + <li>Укражите SFTP-сервер вашего хоста в предоставленном поле: Host.</li> + <li>В раскрывающемся списке <em>Logon Type: </em>выберите <em>Normal</em>, затем введите предоставленные имя пользователя и пароль в соответствующие поля.</li> + <li>Введите правильный порт и другую информацию.</li> +</ol> + +<p>Ваше окно должно выглядеть как показано ниже:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15769/site-manager.png" style="display: block; height: 561px; margin: 0px auto; width: 684px;"></p> + +<p>Теперь нажмите <em>Connect</em> для подключения к SFTP-серверу.</p> + +<p>Заметка: Убедитесь, что ваш хостинг-провайдер предлагает SFTP (безопасный FTP) подключение к вашему хостинговому пространству. FTP по своей сути небезопасен, и вам не следует его использовать.</p> + +<h3 id="Здесь_и_там_локальный_и_удаленный_просмотр">Здесь и там: локальный и удаленный просмотр</h3> + +<p>После подключения ваш экран должен выглядеть примерно так (мы подключились к нашему собственному примеру, чтобы дать вам представление):<img alt="" src="https://mdn.mozillademos.org/files/15768/connected.png" style="border-style: solid; border-width: 1px; display: block; height: 199px; margin: 0px auto; width: 700px;"></p> + +<p>Давайте посмотрим, что вы видите:</p> + +<ul> + <li>По центру левой панели вы можете видеть локальные файлы. Перейдите в каталог, в котором вы храните свой веб-сайт (например, <code>mdn</code>).</li> + <li>По центру правой панели вы увидете удаленные файли. Мы вошли в наш удаленный корень FTP (в данном случае: <code>users/demozilla</code>)</li> + <li>Вы можете пока игнорировать нижнюю и верхнюю панели. Соответственно, это журнал сообщений, показывающий состояние соединения между вашим компьютером и SFTP-сервером, и журнал в реальном времени каждого взаимодействия между вашим SFTP-клиентом и сервером.</li> +</ul> + +<h3 id="Загрузка_на_сервер">Загрузка на сервер</h3> + +<p>Наш пример инструкций для хостинга указывает нам следующее: "Чтобы опубликовать в Интернете, поместите свои файлы в каталог: <code>Public/htdocs</code>." Вам нужно перейти в указанный каталог на правой панели. Этот каталог фактически является корнем вашего веб-сайта, где находятся ваши <code>index.html</code> , откуда ваши файл и другие активы будуть отправлены.</p> + +<p>После того, как вы нашли правильный удаленный каталог для размещения файлов, чтобы загрузить файлы на сервер, вам необходимо переместить их с левой панели на правую.</p> + +<h3 id="Как_узнать_что_они_online">Как узнать, что они online?</h3> + +<p>Пока все хорошо, но действительно ли файлы в сети? Вы можете перепроверить, перейдя на ваш сайт (например, <code>http://demozilla.examplehostingprovider.net/</code>) в вашем браузере:</p> + +<p><img alt="Here we go: our website is live!" src="https://mdn.mozillademos.org/files/9627/here-we-go.png" style="border-style: solid; border-width: 1px; display: block; height: 442px; margin: 0 auto; width: 400px;"></p> + +<p>И вуаля! Наш сайт работает!</p> + +<h2 id="Rsync">Rsync</h2> + +<p>{{Glossary("Rsync")}} is a local-to-remote file synchronizing tool, which is generally available on most Unix-based systems (like macOS and Linux), but Windows versions exist too.</p> + +<p>It is seen as a more advanced tool than SFTP, beause by default it is used on the command line. A basic command looks like so:</p> + +<pre class="brush: bash notranslate">rsync [-options] SOURCE user@x.x.x.x:DESTINATION</pre> + +<ul> + <li><code>-options</code> is a dash followed by a one or more letters, for example <code>-v</code> for verbose error messages, and <code>-b</code> to make backups. You can see the full list at the <a href="https://linux.die.net/man/1/rsync">rsync man page</a> (search for "Options summary").</li> + <li><code>SOURCE</code> is the path to the local file or directory that you want to copy files over from.</li> + <li><code>user@</code> is the credentials of the user on the remote server you want to copy files over to.</li> + <li><code>x.x.x.x</code> is the IP address of the remote server.</li> + <li><code>DESTINATION</code> is the path to the location you want to copy your directory or files to on the remote server.</li> +</ul> + +<p>You'd need to get such details from your hosting provider.</p> + +<p>For more information and further eamples, see <a href="https://www.atlantic.net/hipaa-compliant-cloud-hosting-services/how-to-use-rsync-copy-sync-files-servers/">How to Use Rsync to Copy/Sync Files Between Servers</a>.</p> + +<p>Of course, it is a good idea to use a secure connection, like with FTP. In the case of Rsync, you specify SSH details to make the connection over SSH, using the <code>-e</code> option. For example:</p> + +<pre class="brush: bash notranslate">rsync [-options] -e "ssh [SSH DETAILS GO HERE]" SOURCE user@x.x.x.x:DESTINATION</pre> + +<p>You can find more details of what is needed at <a href="https://www.digitalocean.com/community/tutorials/how-to-copy-files-with-rsync-over-ssh">How To Copy Files With Rsync Over SSH</a>.</p> + +<h3 id="Rsync_GUI_tools">Rsync GUI tools</h3> + +<p>As with other command line tools, GUI tools also exist for Rsync, for those who are not as comfortable with using the command line. <a href="https://acrosync.com/mac.html">Acrosync</a> is one such tool, and it is available for Windows and macOS.</p> + +<p>Again, you would have to get the connection credentials from your hosting provider, but this way you'd have a GUI to enter them in.</p> + +<h2 id="GitHub">GitHub</h2> + +<p>GitHub allows you to publish websites via <a href="https://pages.github.com/">GitHub pages</a> (gh-pages).</p> + +<p>We've covered the basics of using this in the <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Publishing_your_website">Publishing your website</a> article from our <a href="/en-US/Learn/Getting_started_with_the_web">Getting started with the Web</a> guide, so we aren't going to repeat it all here.</p> + +<p>However, it is worth knowing that you can also host a website on GitHub, but use a custom domain with it. See <a href="https://help.github.com/articles/using-a-custom-domain-with-github-pages/">Using a custom domain with GitHub Pages</a> for a detailed guide.</p> + +<h2 id="Other_methods_to_upload_files">Other methods to upload files</h2> + +<p>The FTP protocol is one well-known method for publishing a website, but not the only one. Here are a few other possibilities:</p> + +<ul> + <li><strong>Web interfaces</strong>. An HTML interface acting as front-end for a remote file upload service. Provided by your hosting service.</li> + <li><strong>{{Glossary("WebDAV")}}</strong>. An extension of the {{Glossary("HTTP")}} protocol to allow more advanced file management.</li> +</ul> diff --git a/files/ru/learn/common_questions/using_github_pages/index.html b/files/ru/learn/common_questions/using_github_pages/index.html new file mode 100644 index 0000000000..d32300b1fe --- /dev/null +++ b/files/ru/learn/common_questions/using_github_pages/index.html @@ -0,0 +1,100 @@ +--- +title: Как использовать GitHub Pages? +slug: Learn/Common_questions/Using_Github_pages +translation_of: Learn/Common_questions/Using_Github_pages +--- +<p class="summary"><a href="https://github.com/">GitHub</a> является сайтом «социального кодирования». Он позволяет загружать репозитории кода для хранения в системе управления версиями <a href="http://git-scm.com/">Git</a>. Затем вы можете сотрудничать с проектами кода, а система по умолчанию открыта с открытым исходным кодом, что означает, что любой человек в мире может найти ваш код GitHub, использовать его, учиться на нем и улучшать его. Вы можете сделать это и с кодом других людей! В этой статье представлено основное руководство по публикации контента с использованием функции gh-pages Github.</p> + +<h2 id="Публикация_контента">Публикация контента</h2> + +<p>GitHub - очень важное и полезное сообщество для участия, а Git/GitHub - очень популярная система управления версиями (<a href="http://git-scm.com/book/en/v2/Getting-Started-About-Version-Control">version control system</a>) - большинство технологических компаний теперь используют ее в своем рабочем процессе. GitHub имеет очень полезную функцию <a href="https://pages.github.com/">GitHub Pages</a>, которая позволяет публиковать код сайта в прямом эфире в Интернете.</p> + +<h3 id="Базовая_установка_Github">Базовая установка Github</h3> + +<ol> + <li>Прежде всего, <a href="https://git-scm.com/downloads">установите Git</a> на свой компьютер. Это базовое программное обеспечение для управления версиями, GitHub работает поверх него.</li> + <li>Затем <a href="https://github.com/">зарегистрируйтесь в учетной записи GitHub</a>. Это просто и легко.</li> + <li>После того, как вы зарегистрировались, войдите в <a href="https://github.com">github.com</a> с вашим именем пользователя и паролем.</li> +</ol> + +<h3 id="Подготовка_кода_для_загрузки">Подготовка кода для загрузки</h3> + +<p>Вы можете хранить любой код, который вам нравится, в репозитории Github, но для полнофункционального использования функции GitHub Pages ваш код должен быть структурирован как типичный веб-сайт, причем основной точкой входа является HTML-файл с именем <code>index.html</code>.</p> + +<p>Другое, что вам нужно сделать, прежде чем двигаться дальше - это инициализировать вашу кодовую директорию как репозиторий Git. Сделать это:</p> + +<ol> + <li>Направьте командную строку в каталог вашего <code>test-site</code> (или то, что вы назвали каталогом, содержащим ваш сайт). Для этого используйте команду <code>cd</code> (т.е. "<em>c</em>hange <em>d</em>irectory" - «каталог изменений»). Вот что вы набрали, если бы вы разместили свой сайт в каталоге, называемом <code>test-site</code> на рабочем столе: + + <pre class="brush: bash">cd Desktop/test-site</pre> + </li> + <li>Когда командная строка указывает внутри вашего каталога веб-сайта, введите следующую команду, которая сообщает инструменту <code>git</code>, чтобы он превратил каталог в репозиторий git: + <pre class="brush: bash">git init</pre> + </li> +</ol> + +<h4 id="В_сторону_интерфейсов_командной_строки">В сторону интерфейсов командной строки</h4> + +<p>Лучший способ загрузить код в Github - через командную строку - это окно, в котором вы вводите команды, чтобы делать такие вещи, как создавать файлы и запускать программы, а не щелкать внутри пользовательского интерфейса. Он будет выглядеть примерно так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9483/command-line.png" style="display: block; height: 478px; margin: 0px auto; width: 697px;"></p> + +<div class="note"> +<p><strong>Примечание</strong><strong>:</strong> Вы также можете использовать <a href="https://git-scm.com/downloads/guis">графический пользовательский интерфейс Git </a>для выполнения одной и той же работы, если вам неудобно работать с командной строкой.</p> +</div> + +<p>Каждая операционная система поставляется с инструментом командной строки:</p> + +<ul> + <li><strong>Windows: Командная строка</strong> (<strong>Command Prompt)</strong> может быть получена нажатием клавиши Windows, набрав <em>Command Prompt</em> и выбрав ее из появившегося списка. Обратите внимание, что Windows имеет свои собственные условные обозначения команд, отличные от Linux и OS X, поэтому приведенные ниже команды могут отличаться на вашем компьютере.</li> + <li><strong>OS X: Терминал</strong> (<strong>Terminal)</strong> можно найти в <em>Applications > Utilities</em>.</li> + <li><strong>Linux: </strong>Обычно вы можете вытащить терминал с помощью <em>Ctrl + Alt + T</em>. Если это не сработает, найдите <strong>Terminal</strong> в панели приложений или меню.</li> +</ul> + +<p>Сначала это может показаться немного пугающим, но не волнуйтесь - вы скоро почувствуете основы. Вы говорите компьютеру что-то делать в терминале, введя команду и нажав Enter, как показано выше.</p> + +<h3 id="Создание_repo_для_вашего_кода">Создание repo для вашего кода</h3> + +<ol> + <li>Затем вам нужно создать новое repo для ваших файлов. Нажмите «Плюс» (+) в правом верхнем углу главной страницы GitHub и выберите «Новый репозиторий» (<em>New Repository</em>).</li> + <li>На этой странице в поле Имя репозитория (<em>Repository name</em>) введите имя для своего репозитория, например <em>my-repository</em>.</li> + <li>Также добавьте описание, чтобы сказать, что будет содержать ваш репозиторий. Ваш экран должен выглядеть так:<br> + <img alt="" src="https://mdn.mozillademos.org/files/12143/create-new-repo.png" style="display: block; height: 548px; margin: 0px auto; width: 800px;"></li> + <li>Нажмите Создать репозиторий (<em>Create repository</em>); это приведет вас к следующей странице:<br> + <img alt="" src="https://mdn.mozillademos.org/files/12141/github-repo.png" style="display: block; height: 520px; margin: 0px auto; width: 800px;"></li> +</ol> + +<h3 id="Загрузка_файлов_на_GitHub">Загрузка файлов на GitHub</h3> + +<ol> + <li>На текущей странице вас интересует раздел <em>…or push an existing repository from the command line</em> (...или нажмите существующий репозиторий из командной строки). Вы должны увидеть две строки кода, перечисленные в этом разделе. Скопируйте всю первую строку, вставьте ее в командную строку и нажмите Enter. Команда должна выглядеть примерно так: + + <pre class="copyable-terminal-content js-zeroclipboard-target"><span class="user-select-contain">git remote add origin <span class="js-live-clone-url">https://github.com/chrisdavidmills/my-repository.git</span></span></pre> + </li> + <li>Затем введите следующие две команды, нажав Enter после каждого из них. Они готовят код для загрузки в GitHub и просят Git управлять этими файлами. + <pre class="brush: bash">git add --all +git commit -m 'adding my files to my repository'</pre> + </li> + <li>Наконец, нажмите код до GitHub, перейдя на веб-страницу GitHub, на которой вы находитесь, и введите в терминал вторую из двух команд, которые мы увидели <em>…or push an existing repository from the command line</em>: + <pre class="brush: bash">git push -u origin master</pre> + </li> + <li>Теперь вам нужно создать ветвь gh-pages вашего repo; обновите текущую страницу и вы увидите страницу репозитория, как показано ниже. Вам нужно нажать кнопку, в которой говорится о <em>Branch: <strong>master</strong></em>, введите <em>gh-pages</em> в текстовом вводе, затем нажмите синюю кнопку с надписью <em>Create branch: gh-pages</em>. Это создает специальную ветвь кода, называемую gh-pages, которая публикуется в специальном месте. URL-адрес принимает форму <em>username.github.io/my-repository-name</em>, поэтому в моем примере URL-адрес будет <em>https://chrisdavidmills.github.io/my-repository</em>. Отображаемая страница - это страница index.html.<br> + <img alt="" src="https://mdn.mozillademos.org/files/12145/repo-site.png" style="display: block; margin: 0 auto;"></li> + <li>Перейдите на веб-адрес GitHub Pages на новой вкладке браузера, и вы должны увидеть свой сайт онлайн! Отправьте его по электронной почте своим друзьям и продемонстрируйте свое мастерство.</li> +</ol> + +<div class="note"> +<p><strong>Примечание:</strong> Если вы застряли, страница <a href="https://pages.github.com/">GitHub Pages homepage</a> также очень полезна.</p> +</div> + +<h3 id="Дальнейшее_знание_GitHub">Дальнейшее знание GitHub</h3> + +<p>Если вы хотите сделать больше изменений на своем тестовом сайте и загрузить их на GitHub, вам просто нужно внести изменения в свои файлы, как и раньше. Затем вам нужно ввести следующие команды (нажав Enter после каждого), чтобы вставить эти изменения в GitHub:</p> + +<pre>git add --all +git commit -m 'another commit' +git push</pre> + +<p>Вы можете заменить <em>another commit</em> более подходящим сообщением, чтобы описать, какое изменение вы только что сделали.</p> + +<p>Мы едва коснулись Git. Чтобы узнать больше, начните с <a href="https://help.github.com/index.html">GitHub Help site</a>.</p> diff --git a/files/ru/learn/common_questions/what_software_do_i_need/index.html b/files/ru/learn/common_questions/what_software_do_i_need/index.html new file mode 100644 index 0000000000..8432ce45c3 --- /dev/null +++ b/files/ru/learn/common_questions/what_software_do_i_need/index.html @@ -0,0 +1,156 @@ +--- +title: Какое программное обеспечение необходимо для создания веб-сайта? +slug: Learn/Common_questions/What_software_do_I_need +translation_of: Learn/Common_questions/What_software_do_I_need +--- +<div class="summary"> +<p>В этой статье мы изложим какие программные компоненты вам понадобятся при редактировании, загрузке или просмотре веб-сайта.</p> +</div> + +<table class="learn-box nostripe standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Вы должны уже знать <a href="/ru/docs/Learn/Pages_sites_servers_and_search_engines">разницу между веб-страницами, веб-сайтами, веб-серверами и поисковыми системами.</a></td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Узнать, какие программные компоненты вам понадобятся при редактировании, загрузке или просмотре веб-сайта.</td> + </tr> + </tbody> +</table> + +<h2 id="Аннотация">Аннотация</h2> + +<p>Вы можете бесплатно загрузить большинство программ, необходимых для веб-разработки. Мы предоставим несколько ссылок в этой статье. Вам понадобятся инструменты: 1) создания и редактирования веб-страниц, 2) загружать файлы на ваш веб-сервер, 3) просматривать ваш веб-сайт.</p> + +<p>Почти все операционные системы по умолчанию включают текстовый редактор и просмоторщик веб-сайтов (называемый браузером). Поэтому обычно вам нужно приобрести лишь программное обеспечение для передачи файлов на ваш веб-сервер.</p> + +<h2 id="Активное_изучение">Активное изучение</h2> + +<p><em>Пока нет активного обучения. </em><a href="/ru/docs/MDN/Getting_started">Пожалуйста, подумайте о том, чтобы внести свой вклад.</a></p> + +<h2 id="Копай_глубже">Копай глубже</h2> + +<h3 id="Создание_и_редактирование_веб-страниц">Создание и редактирование веб-страниц</h3> + +<p>Для создания и редактирования веб-страниц необходим текстовый редактор. Тестовые редакторы создают и изменяют неотформатированные текстовые файлы. (Другие форматы, такие как <strong>{{Glossary("RTF")}}</strong>, позволяют добавить форматирование, такое как полужирное или подчеркивание. Эти форматы не подходят для написания веб-страниц.) Вам следует выбирать текстовый редактор с умом, так как вы будете активно работать с ним, при создании веб-сайта.</p> + +<p>Все настольные операционные системы поставляются с основным текстовым редактором. Они просты, но не имеют специальных возможностей для кодирования веб-страниц. Если вы хотите что-то более интересное, то доступно много сторонних инструментов. Сторонние редакторы часто поставляются с дополнительными функциями, включая подсветку синтаксиса, автозавершение, сворачиваемые блоки кода и поиск кода. Вот краткий список редакторов:</p> + +<p> </p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Операционная система</th> + <th scope="col">Встроенный редактор</th> + <th scope="col">Сторонний редактор</th> + </tr> + </thead> + <tbody> + <tr> + <td>Windows</td> + <td><a href="http://en.wikipedia.org/wiki/Notepad_%28software%29" rel="external">Notepad</a></td> + <td> + <p><a href="http://notepad-plus-plus.org/">Notepad++</a></p> + + <p><a href="https://www.visualstudio.com/">Visual Studio Code</a></p> + + <p><a href="https://www.jetbrains.com/webstorm/">Web Storm</a></p> + + <p><a href="http://brackets.io/">Brackets</a></p> + </td> + </tr> + <tr> + <td>Mac OS</td> + <td><a href="http://en.wikipedia.org/wiki/TextEdit" rel="external">TextEdit</a></td> + <td> + <p><a href="http://www.barebones.com/products/textwrangler/">TextWrangler</a></p> + + <p><a href="https://www.visualstudio.com/">Visual Studio Code</a></p> + + <p><a href="http://brackets.io/">Brackets</a></p> + </td> + </tr> + <tr> + <td>Linux</td> + <td><a href="http://en.wikipedia.org/wiki/Vi" rel="external">Vi</a> (All UNIX)<br> + <a href="http://en.wikipedia.org/wiki/Gedit" rel="external">GEdit</a> (Gnome)<br> + <a href="http://en.wikipedia.org/wiki/Kate_%28text_editor%29" rel="external">Kate</a> (KDE)<br> + <a href="http://en.wikipedia.org/wiki/Kate_(text_editor)" rel="external">LeafPad</a> (Xfce)</td> + <td> + <p><a href="http://www.gnu.org/software/emacs/">Emacs</a><br> + <a href="http://www.vim.org/" rel="external">Vim</a></p> + + <p><a href="https://www.visualstudio.com/">Visual Studio Code</a></p> + + <p><a href="http://brackets.io/">Brackets</a></p> + </td> + </tr> + </tbody> +</table> + +<p>Ниже скриншот продвинутого текстового редактора:</p> + +<p><img alt="Screenshot of Notepad++." src="https://mdn.mozillademos.org/files/8221/NotepadPlusPlus.png" style="height: 311px; width: 450px;"></p> + +<h3 id="Загрузка_файлов_в_Интернете">Загрузка файлов в Интернете</h3> + +<p>Когда ваш сайт будет готов для публичного просмотра, вам придется загрузить свои веб-страницы на веб-сервер. Вы можете купить место на сервере у различных провайдеров (см. <a href="/en-US/docs/Learn/How_much_does_it_cost">Сколько стоит делать что-то в Интернете?</a>). После того, как вы решите, какого провайдера использовать, провайдер отправит вам по электронной почте информацию о доступе к протоколу FTP (протокол передачи файлов). Загрузка файлов на веб-сервер является важным шагом при создании сайта, поэтому мы подробно расскажем об этом <a href="/en-US/docs/Learn/Upload_files_to_a_web_server">в отдельной статье</a>. А сейчас, вот краткий список бесплатных базовых FTP-клиентов:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Операционная система</th> + <th colspan="2" rowspan="1" scope="col" style="text-align: center;">Программное обеспечение FTP</th> + </tr> + </thead> + <tbody> + <tr> + <td>Windows</td> + <td> + <p><a href="http://winscp.net" rel="external">WinSCP</a></p> + + <p><a href="http://mobaxterm.mobatek.net/">Moba Xterm</a></p> + </td> + <td colspan="1" rowspan="3"><a href="https://filezilla-project.org/">FileZilla</a> (All OS)</td> + </tr> + <tr> + <td>Linux</td> + <td><a href="https://live.gnome.org/Nautilus" rel="external">Nautilus</a> (Gnome)<br> + <a href="http://dolphin.com/" rel="external">Dolphin</a> (KDE)</td> + </tr> + <tr> + <td>Mac OS</td> + <td><a href="http://cyberduck.de/">Cyberduck</a></td> + </tr> + </tbody> +</table> + +<h3 id="Просмотр_веб-сайтов">Просмотр веб-сайтов</h3> + +<p>Как вы уже знаете, вам необходим веб-браузер для просмотра веб-сайтов. Существуют десятки браузеров для вашего личного использования, однако когда вы разрабатываете веб-сайт, вы должны протестировать его, по крайней мере, со следующими основными браузерами, чтобы убедиться, что ваш сайт работает для большинста пользователей:</p> + +<ul> + <li><a href="https://www.mozilla.org/en-US/firefox/new/" rel="external">Mozilla Firefox</a></li> + <li><a href="https://www.google.fr/chrome/browser/" rel="external">Google Chrome</a></li> + <li><a href="http://windows.microsoft.com/en-US/internet-explorer/download-ie" rel="external">Microsoft Internet Explorer</a></li> + <li><a href="http://www.apple.com/safari/" rel="external">Apple Safari</a></li> +</ul> + +<p>Если вы ориентируетесь на определенную группу (например, техническую платформу или страну), возможно, вам придется протестировать ваш сайт с помощью дополнительных браузеров, таких как <a href="http://www.opera.com/" rel="external">Opera</a>, <a href="http://www.konqueror.org/">Konqueror</a>, или<a href="http://www.ucweb.com/ucbrowser/" rel="external"> UC Browser</a>.</p> + +<p>Но тестирование усложняется, потому что некоторые браузеры работают только в определенных операционных системах. Apple Safari работает на iOS и Mac OS, а Internet Explorer работает только в Windows. Поэтому лучше воспользоваться такими сервисами, как <a href="http://browsershots.org/" rel="external">Browsershots</a> или <a href="http://www.browserstack.com/" rel="external">Browserstack</a>. Browsershots предоставляет скриншоты вашего сайта, того как ваш сайт будет выглядить в различных браузерах. Browserstack фактически предоставляет вам полный удаленный доступ к виртуальным машинам, поэтому вы можете протестировать ваш сайт в наиболее распространенных средах. Кроме того, вы можете настроить свою собственную виртуальную машину, но это требует некоторого опыта. (Если вы следуете этому пути, Microsoft имеет инструменты для разработчиков, включая готовую к использованию виртуальую машину на <a href="https://modern.ie" rel="external">modern.ie</a>.)</p> + +<p>Обязательно проведите тестирование на реальном устройстве, особенно на реальных мобильных устройствах. Симуляция мобильных устройств - это новая, развивающаяся технология и менее надежна, чем симуляция настольных устройств. Разумеется, мобильные устройства стоят денег, поэтому мы предлагаем взглянуть на <a href="http://opendevicelab.com/" rel="external">Open Device Lab initiative</a>. Вы также можете обмениваться устройствами, если вы хотите протестировать на многих платформах, не тратя слишком много.</p> + +<h2 id="Следующие_шаги">Следующие шаги</h2> + +<ul> + <li>Некоторые из перечисленных программ бесплатны, но не все. <a href="/en-US/docs/Learn/Common_questions/How_much_does_it_cost">Узнайте, сколько стоит сделать что-то в Интернете.</a></li> + <li>Если вы хотите больше узнать о текстовых редакторах, прочитайте нашу статью о том <a href="/en-US/docs/Learn/Choose,_Install_and_set_up_a_text_editor">как выбрать и установить текстовый редактор</a>.</li> + <li>Если вам интересно, как опубликовать ваш веб-сайт в Интернете, посмотрите статью <a href="/en-US/docs/Learn/Upload_files_to_a_web_server">"Как загрузить файлы на веб-сервер"</a>.</li> +</ul> + +<p> </p> diff --git a/files/ru/learn/css/building_blocks/advanced_styling_effects/index.html b/files/ru/learn/css/building_blocks/advanced_styling_effects/index.html new file mode 100644 index 0000000000..174d980693 --- /dev/null +++ b/files/ru/learn/css/building_blocks/advanced_styling_effects/index.html @@ -0,0 +1,329 @@ +--- +title: Узконаправленные функции CSS +slug: Learn/CSS/Building_blocks/Advanced_styling_effects +tags: + - Beginner + - Blend + - Boxes + - CSS + - Filters + - Styling + - effects + - Контейнеры + - Начинающий + - Смешивание + - Формы + - фигуры + - фильтры +translation_of: Learn/CSS/Building_blocks/Advanced_styling_effects +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">В этой статье описаны некоторые хитрости, которые познакомят Вас с такими узкоспециализированными свойствами, как box-shadow, режимы смешивания и фильтры.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Основы HTML (изучите <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>) и CSS (статья <a href="https://developer.cdn.mozilla.net/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>).</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Понять принцип работы узко используемых эффектов в современных браузерах.</td> + </tr> + </tbody> +</table> + +<h2 id="Блок-тень">Блок-тень</h2> + +<p>{{cssxref("box-shadow")}} позволяет добавить одну и более тень к контейнеру. Как и <code>text-shadow</code>, <code>box-shadows</code> отлично поддерживаются брузерами, включая IE9+ и Edge. У пользователей ранних версий IE будет просто копия без тени, поэтому убедитесь, что контент с дизайном разборчив и без теней.</p> + +<p>Вы можете найти примеры из стати на <a href="http://mdn.github.io/learning-area/css/styling-boxes/advanced_box_effects/box-shadow.html">box-shadow.html</a> (или в <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/advanced_box_effects/box-shadow.html">исходном коде</a>).</p> + +<h3 id="Обычная_тень">Обычная тень</h3> + +<p>Для начала взглянем на простой пример:</p> + +<pre class="brush: html"><article class="simple"> + <p><strong>Предупреждение</strong>: Температура ракетного двигателя достигла критической отметки.</p> +</article></pre> + +<p>А теперь CSS:</p> + +<pre class="brush: css">p { + margin: 0; +} + +article { + max-width: 500px; + padding: 10px; + background-color: red; + background-image: linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,0.25)); +} + +.simple { + box-shadow: 5px 5px 5px rgba(0,0,0,0.7); +}</pre> + +<p>В результате получится вот это:</p> + +<p>{{ EmbedLiveSample('Обычная_тень', '100%', 100) }}</p> + +<p>Как видите, у нас четыре значения в свойстве <code>box-shadow</code>:</p> + +<ol> + <li>Первое значение — <strong>смещение по горизонтали</strong> — расстояние, на которое смещена тень вправо (если значение отрицательное, то влево).</li> + <li><strong>Смещение по вертикали</strong> — расстояние, на которое смещена тень вниз (или вверх, если значение отрицательное).</li> + <li>Третье значение — это <strong>радиус размытия</strong> — уровень размытия тени.</li> + <li>Значение цвета — это <strong>основной цвет</strong> тени.</li> +</ol> + +<p>Вы можете использовать абсолютно любые значения и цвета, если это необходимо.</p> + +<h3 id="Несколько_теней">Несколько теней</h3> + +<p>Вы можете определить несколько блок-теней, разделяя их запятыми при объявлении <code>box-shadow</code>:</p> + +<div class="hidden"> +<pre class="brush: html"><article class="multiple"> + <p><strong>Предупреждение</strong>: Температура ракетного двигателя достигла критической отметки.</p> +</article></pre> +</div> + +<pre class="brush: css">p { + margin: 0; +} + +article { + max-width: 500px; + padding: 10px; + background-color: red; + background-image: linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,0.25)); +} + +.multiple { + box-shadow: 1px 1px 1px black, + 2px 2px 1px black, + 3px 3px 1px red, + 4px 4px 1px red, + 5px 5px 1px black, + 6px 6px 1px black; +}</pre> + +<p>В итоге мы получим:</p> + +<p>{{ EmbedLiveSample('Несколько_теней', '100%', 100) }}</p> + +<p>Мы сделали контейнер с несколькими ступенчатыми цветными тенями, но Вы можете делать, как считаете то нужным, например, чтобы добавить реалистичности, опираясь на какие-нибудь источники света.</p> + +<h3 id="Другие_опции_блок-теней">Другие опции блок-теней</h3> + +<p>В отличие от {{cssxref("text-shadow")}}, у свойства {{cssxref("box-shadow")}} есть значение <code>inset</code> — оно добавляет внутреннюю тень. Поясним это на примере.</p> + +<p>Для этого примера используем другой HTML-код:</p> + +<pre class="brush: html"><button>Нажми на меня!</button></pre> + +<pre class="brush: css">button { + width: 150px; + font-size: 1.1rem; + line-height: 2; + border-radius: 10px; + border: none; + background-image: linear-gradient(to bottom right, #777, #ddd); + box-shadow: 1px 1px 1px black, + inset 2px 3px 5px rgba(0,0,0,0.3), + inset -2px -3px 5px rgba(255,255,255,0.5); +} + +button:focus, button:hover { + background-image: linear-gradient(to bottom right, #888, #eee); +} + +button:active { + box-shadow: inset 2px 2px 1px black, + inset 2px 3px 5px rgba(0,0,0,0.3), + inset -2px -3px 5px rgba(255,255,255,0.5); +}</pre> + +<p>Получим:</p> + +<p>{{ EmbedLiveSample('Другие_опции_блок-теней', '100%', 70) }}</p> + +<p>Мы стилизовали кнопку с помощью состояний <em>focus</em>, <em>hover</em> и <em>active</em>. Для кнопки по умолчанию установлены несколько простых чёрных теней плюс пара внутренних теней в противополжном углу кнопки для эстетичности.</p> + +<p>При нажатии на кнопку первая тень становится внутренней, чтобы создать ощущение нажатия кнопки.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Есть ещё одно значение <code>box-shadow</code>, которое устанавливается перед значением свойства, — <strong>радиус разброса</strong>. При его использовании тень становится больше оригинального контейнера. Свойство не так часто используют, но оно стоит упоминания.</p> +</div> + +<h2 id="Фильтры">Фильтры</h2> + +<p>Замечательное свойство, благодаря которому ваш дизайн станет интереснее, — это свойство {{cssxref("filter")}}. Это что-то вроде фильтров Photoshop, но в CSS.</p> + +<p>В примере ниже мы использовали два значения этого свойства: первое — <code>blur()</code> — определяет, насколько изображение размыто.</p> + +<p>Второе значение — <code>grayscale()</code>; оно определяет, насколько изображение насыщено.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/filter.html", '100%', 700)}}</p> + +<p><strong>Попробуйте изменить значения в примере, чтобы посмотреть на изменения. Вы можете менять значения на другие. Попробуйте добавить <code>contrast(200%)</code>, <code>invert(100%)</code> или <code>hue-rotate(20deg)</code> в примере ниже. Прочтите статью <code><a href="https://developer.mozilla.org/ru/docs/Web/CSS/filter">filter</a></code>, чтобы узнать о многих других значениях этого свойства.</strong></p> + +<p>Вы можете добавлять фильтры к любым объектам. Некоторые значения свойства работают почти так же, как CSS-свойства, например, <code>drop-shadow()</code> даёт эффект, схожий с <a href="https://developer.mozilla.org/ru/docs/Web/CSS/box-shadow" title="The box-shadow CSS property adds shadow effects around an element's frame. You can set multiple effects separated by commas."><code>box-shadow</code></a> или <a href="https://developer.mozilla.org/ru/docs/Web/CSS/text-shadow" title="The text-shadow CSS property adds shadows to text. It accepts a comma-separated list of shadows to be applied to the text and any of its decorations."><code>text-shadow</code></a>.</p> + +<p>В фильтрах замечательно то, что они применяются к каждому элементу контейнера. Ниже мы сравнили фильтр и блок-тень. Как видите, фильтр применился к каждой чёрточке. А блок-тень просто выделила тень, равную размерам контейнера.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/filter-text.html", '100%', 600)}}</p> + +<h2 id="Режимы_смешивания">Режимы смешивания</h2> + +<p>Режимы смешивания CSS позволяют определить смешивание при наложении двух элементов. Смешивание очень знакомо пользователям редакторов вроде Photoshop.</p> + +<p>В режимах смешивания CSS два значения:</p> + +<ul> + <li>{{cssxref("background-blend-mode")}}, которое смешивает цвет фона и цвета отдельного элемента.</li> + <li>{{cssxref("mix-blend-mode")}}, которое смешивает элементы, наложенные друг на друга.</li> +</ul> + +<p>Вы можете найти больше примеров смешивания на странице <a href="http://mdn.github.io/learning-area/css/styling-boxes/advanced_box_effects/blend-modes.html">blend-modes.html</a> (смотрите <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/advanced_box_effects/blend-modes.html">источник</a>) и на странице {{cssxref("<blend-mode>")}}.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Смешивание относительно новое свойство, поэтому поддерживается хуже, чем фильтры. Оно совсем не поддерживается на Edge, а Safari поддерживает лишь некоторые значения свойства.</p> +</div> + +<h3 id="background-blend-mode">background-blend-mode</h3> + +<p>Снова обратимся к примеру. Во-первых, {{cssxref("background-blend-mode")}} — мы покажем несколько контейнеров {{htmlelement("div")}}, чтобы Вы сравнили оригинал с редактированной версией:</p> + +<pre class="brush: html"><div> +</div> +<div class="multiply"> +</div></pre> + +<p>Воспользуемся CSS — добавим к <code><div></code> одно фоновое изображение и зелёный фон:</p> + +<pre class="brush: css">div { + width: 250px; + height: 130px; + padding: 10px; + margin: 10px; + display: inline-block; + background: url(https://mdn.mozillademos.org/files/13090/colorful-heart.png) no-repeat center 20px; + background-color: green; +} + +.multiply { + background-blend-mode: multiply; +}</pre> + +<p>Слева вы видите оригинал, справа — изменённое изображение:</p> + +<p>{{ EmbedLiveSample('background-blend-mode', '100%', 200) }}</p> + +<h3 id="mix-blend-mode">mix-blend-mode</h3> + +<p>Рассмотрим {{cssxref("mix-blend-mode")}}. Здесь мы также используем несколько <code><div></code>, но каждый из них расположен над простым <code><div></code> с фиолетовым фоном, чтобы показать, как элементы будут смешаны:</p> + +<pre class="brush: html"><article> + Нет режима смешивания + <div> + + </div> + <div> + </div> +</article> + +<article> + Множественное смешивание + <div class="multiply-mix"> + + </div> + <div> + </div> +</article></pre> + +<p>А здесь CSS:</p> + +<pre class="brush: css">article { + width: 280px; + height: 180px; + margin: 10px; + position: relative; + display: inline-block; +} + +div { + width: 250px; + height: 130px; + padding: 10px; + margin: 10px; +} + +article div:first-child { + position: absolute; + top: 10px; + left: 0; + background: url(https://mdn.mozillademos.org/files/13090/colorful-heart.png) no-repeat center 20px; + background-color: green; +} + +article div:last-child { + background-color: purple; + position: absolute; + bottom: -10px; + right: 0; + z-index: -1; +} + +.multiply-mix { + mix-blend-mode: multiply; +}</pre> + +<p>И это даст нам следующее:</p> + +<p>{{ EmbedLiveSample('mix-blend-mode', '100%', 200) }}</p> + +<p>Как видите, смешались не только фоновые изображения, но и <code><div></code> под ними.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Не переживайте, если Вы не знаете такие свойства разметки, как {{cssxref("position")}}, {{cssxref("top")}}, {{cssxref("bottom")}}, {{cssxref("z-index")}} и т. д. Мы детально рассмотрим это в модуле <a href="https://developer.cdn.mozilla.net/ru/docs/Learn/CSS/CSS_layout">CSS Layout</a>.</p> +</div> + +<h2 id="CSS-фигуры">CSS-фигуры</h2> + +<p>Мы можем сделать обтекание содержимым непрямоугольных фигур, используя <a href="https://wiki.developer.mozilla.org/ru/docs/Web/CSS/CSS_Shapes">CSS-фигуры</a>.</p> + +<p>В примере ниже мы эффектно округлили воздушный шар. В действительности изображение прямоугольное, но с определением свойства <em>float</em> (по-другому формы не добавляются) и использованием свойства {{cssxref("shape-outside")}} со значением <code>circle(50%)</code>, мы можем создать эффект обтекания текста.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/shapes.html", '100%', 1000)}}</p> + +<p>Форма в этом примере не реагирует на содержание изображения. Вместо этого в центре изображения определяется центр окружности, как если бы мы начертили циркулем окружность, вписанную в изображение. Это та окружность, которую обтекает текст.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: В Firefox Вы можеет использовать <a href="https://developer.mozilla.org/ru/docs/Tools/Page_Inspector/How_to/Edit_CSS_shapes">Инспектор фигур</a>, чтобы редактировать фигуры.</p> +</div> + +<p>Значение <code>circle()</code> — лишь одно из нескольких базовых фигур для этого свойства, но можно и создавать формы. (Читайте <a href="/en-US/docs/Web/CSS/CSS_Shapes/Overview_of_CSS_Shapes">Обзор CSS-фигур</a> на MDN.)</p> + +<h2 id="-webkit-background-clip_text">-webkit-background-clip: text</h2> + +<p>Функция, о которой мы, кажется, упомянули в свйстве <code>text</code> для значения {{cssxref("background-clip")}}. Опция <code>-webkit-text-fill-color: transparent;</code> позволяет обрезать фоновые изображения под форму текста. Это неофициальный стандарт, но он был подключён во множестве браузеров. В данном контексте обязательно используется префикс <code>-webkit-</code> для любых браузеров:</p> + +<pre class="brush: css">.text-clip { + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +}</pre> + +<p>Так почему остальные браузеры используют префикс <code>-webkit-</code>? В основном для совместимости — поэтому многие веб-разработчики стали вставлять префиксы <code>-webkit-</code>, отчего другие браузеры казались сломанными, когда, по факту, всё было выполнено по всем стандартам. Поэтому были введены некоторые такие функции.</p> + +<p>Если вы собираетесь использовать подобные опции, проверьте совместимость их с браузерами.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Пример с <code>-webkit-background-clip: text</code> смотрите на <a href="http://mdn.github.io/learning-area/css/styling-boxes/advanced_box_effects/background-clip-text.html">background-clip-text.html</a> (или <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/advanced_box_effects/background-clip-text.html">источнике</a>).</p> +</div> + +<h2 id="Итог">Итог</h2> + +<p>Надеемся, статья была весёлой — игра с кодами уж точно. Всегда интересно следить за появлением новых узконаправленных свойств в современных браузерах.</p> diff --git a/files/ru/learn/css/building_blocks/backgrounds_and_borders/index.html b/files/ru/learn/css/building_blocks/backgrounds_and_borders/index.html new file mode 100644 index 0000000000..9f747a06f4 --- /dev/null +++ b/files/ru/learn/css/building_blocks/backgrounds_and_borders/index.html @@ -0,0 +1,332 @@ +--- +title: Фон и границы +slug: Learn/CSS/Building_blocks/Backgrounds_and_borders +tags: + - Beginner + - CSS + - Learn + - Границы + - Изображение + - Обучение + - Позиция + - Фон + - Цвет +translation_of: Learn/CSS/Building_blocks/Backgrounds_and_borders +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/The_box_model", "Learn/CSS/Building_blocks/Handling_different_text_directions", "Learn/CSS/Building_blocks")}}</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В этом уроке мы рассмотрим некоторые интересные возможности, которые вы можете сделать с помощью CSS свойств фона и границ .</span> <span title="">Благодаря добавлению градиентов, фоновых изображений и закругленных углов свойства фона и границ ответят на многие вопросы стилизации в CSS.</span></span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые умения:</th> + <td>Базовая компьютерная грамотность, <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">основное программное обеспечение</a>, понимание <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работы с файлами</a>, базовые знания HTML (смотрите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>) и представление о том, как работает CSS (смотрите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Научиться стилизации фона и границ объектов.</td> + </tr> + </tbody> +</table> + +<h2 id="Стилизация_фона_в_CSS">Стилизация фона в CSS</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">CSS cвойство {{cssxref ("background")}} является сокращением для ряда полных свойств фона, с которыми мы познакомимся в этом уроке.</span> <span title="">Если вы обнаружите сложное свойство </span></span><code>background</code><span class="tlid-translation translation" lang="ru"><span title=""> в таблице стилей, это может показаться трудным для понимания, так как одновременно может быть передано так много значений.</span></span></p> + +<pre class="brush: css notranslate"><code>.box { + background: linear-gradient(105deg, rgba(255,255,255,.2) 39%, rgba(51,56,57,1) 96%) center center / 400px 200px no-repeat, + url(big-star.png) center no-repeat, rebeccapurple; +} </code> +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Мы вернемся к тому, как работает сокращение </span></span>позже<span class="tlid-translation translation" lang="ru"><span title="">, </span></span>а пока<span class="tlid-translation translation" lang="ru"><span title=""> давайте взглянем на различные вещи, которые вы можете делать с фоном в CSS, посмотрев на отдельные свойства </span></span><code>background</code><span class="tlid-translation translation" lang="ru"><span title="">.</span></span></p> + +<h3 id="Фоновый_цвет">Фоновый цвет</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Свойство {{cssxref ("background-color")}} определяет цвет фона для любого элемента в CSS.</span> <span title="">Свойство принимает любой допустимый </span></span>цвет<span class="tlid-translation translation" lang="ru"><span title=""> </span></span><code><a href="/ru/docs/Web/CSS/color_value"><color></a></code><span class="tlid-translation translation" lang="ru"><span title="">.</span> </span><code>background-color</code><span class="tlid-translation translation" lang="ru"><span title=""> распространяется на сам контент и отступы от него </span></span>(padding)<span class="tlid-translation translation" lang="ru"><span title="">.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В приведенном ниже примере мы использовали различные значения цвета, чтобы добавить цвет фона к блоку, заголовку и элементу {{htmlelement ("span")}}.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title=""><strong>Поиграйте с ними, используя любое доступное значение</strong> </span></span><strong><a href="/ru/docs/Web/CSS/color_value"><color></a><span class="tlid-translation translation" lang="ru"><span title="">.</span></span></strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/color.html", '100%', 600)}}</p> + +<h3 id="Фоновое_изображение">Фоновое изображение</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Свойство {{cssxref ("background-image")}} позволяет отображать изображение </span></span>в качестве фона элемента<span class="tlid-translation translation" lang="ru"><span title="">.</span> <span title="">В приведенном ниже примере у нас есть два блока </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> в одном фоновое изображение больше, чем размеры блока, а в другом - маленькое изображение звезды.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Этот пример демонстрирует две </span></span>особенности<span class="tlid-translation translation" lang="ru"><span title=""> фоновых изображений.</span> <span title="">По умолчанию большое изображение не масштабируется до размера блока, поэтому мы видим только его небольшой угол, в то время как маленькое изображение повторяется, чтобы заполнить весь блок.</span> <span title="">В нашем случае фактически было использовано изображение одной маленькой звезды.</span></span></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/background-image.html", '100%', 600)}}</p> + +<div class="blockIndicator note"> +<p><strong>Если кроме фонового изображения вы добавили фоновый цвет, то изображение будет отображаться над цветом.</strong> Попробуйте добавить свойство <code>background-color</code> в <span class="tlid-translation translation" lang="ru"><span title="">приведенный выше пример, чтобы увидеть это в действии.</span></span></p> +</div> + +<h4 id="Свойство_background-repeat">Свойство background-repeat</h4> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Свойство {{cssxref ("background-repeat")}} используется для управления повторениями фонового изображения.</span> <span title="">Доступные значения:</span></span></p> + +<ul> + <li><code>no-repeat</code> — останавливает повторение фонового изображения во всех направлениях.</li> + <li><code>repeat-x</code> — повторение фонового изображения по горизонтали.</li> + <li><code>repeat-y</code> — повторение фонового изображения по вертикали.</li> + <li><code>repeat</code> — повторение фонового изображения в обоих направлениях. Установлено по умолчанию.</li> +</ul> + +<p><strong><span class="tlid-translation translation" lang="ru"><span title="">Попробуйте эти значения в примере ниже.</span> <span title="">Мы установили значение </span></span><code>no-repeat</code><span class="tlid-translation translation" lang="ru"><span title="">, поэтому вы видите только одну звезду.</span> <span title="">Попробуйте разные значения - </span></span></strong> <strong><code>repeat-x</code></strong> <strong><span class="tlid-translation translation" lang="ru"><span title=""> и </span></span></strong> <strong><code>repeat-y</code></strong> <strong>—</strong> <strong><span class="tlid-translation translation" lang="ru"><span title=""> чтобы увидеть, какие эффекты они оказывают.</span></span></strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/repeat.html", '100%', 480)}}</p> + +<h4 id="Изменение_размеров_фонового_изображения">Изменение размеров фонового изображения</h4> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В приведенном выше примере у нас есть большое изображение, которое в конечном итоге было обрезано, так как оно больше, чем элемент, фоном которого оно является.</span> <span title="">В этом случае мы могли бы использовать свойство {{cssxref ("background-size")}}, которое может принимать значения </span></span><a href="/ru/docs/Web/CSS/размер">длины</a><span class="tlid-translation translation" lang="ru"><span title=""> или в <a href="/ru/docs/Web/CSS/percentage">процентах</a>, чтобы размер изображения соответствовал размеру фона.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы также можете использовать ключевые слова</span></span>:</p> + +<ul> + <li><code>cover</code> <span class="tlid-translation translation" lang="ru"><span title=""> </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> браузер сделает изображение достаточно большим, чтобы оно полностью заполнило блок, сохраняя при этом соотношение сторон.</span> <span title="">В этом случае часть изображения, скорее всего, окажется за пределами блока.</span></span></li> + <li><code>contain</code> — <span class="tlid-translation translation" lang="ru"><span title="">браузер сделает изображение нужного размера, чтобы поместиться в блоке.</span> <span title="">В этом случае могут появиться пробелы с обеих сторон или сверху и снизу изображения, если соотношение сторон изображения отличается от соотношения сторон блока.</span></span></li> +</ul> + +<p>Ниже я применил значения длины к размерам изображения. Глядите, как это исказило изображение.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В приведенном ниже примере я использовал большое изображение из ранее рассмотренного примера и указал значения длины, чтобы определить его размер внутри блока.</span> <span title="">Вы можете посмотреть, как это исказило изображение.</span></span></p> + +<p>Попробуйте следующее.</p> + +<ul> + <li><span class="tlid-translation translation" lang="ru"><span title="">Измените </span></span>значения<span class="tlid-translation translation" lang="ru"><span title=""> длины, используемые для изменения размера фона.</span></span></li> + <li>Измените значение длины на <code>background-size: cover</code> или <code>background-size: contain</code>. </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Если ваше изображение меньше </span></span>размеров блока<span class="tlid-translation translation" lang="ru"><span title="">, вы можете изменить значение свойства </span></span><code>background-repeat</code><span class="tlid-translation translation" lang="ru"><span title="">, чтобы повторить изображение.</span></span></li> +</ul> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/size.html", '100%', 600)}}</p> + +<h4 id="Позиционирование_фонового_изображения">Позиционирование фонового изображения</h4> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Свойство {{cssxref ("background-position")}} позволяет вам изменять позицию, в которой фоновое изображение появляется в блоке.</span> <span title="">При этом используется система координат, в которой <em>левый верхний угол</em> блока равен <code>(0,0)</code>, а </span></span>сам блок располагается вдоль<span class="tlid-translation translation" lang="ru"><span title=""> горизонтальной (<code>x</code>) и вертикальной (<code>y</code>) осей.</span></span></p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: По умолчанию значение <code>background-position</code> равно <code>(0,0)</code>.</p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Обычно свойство <code>background-position</code> задают в ввиде двух последовательных значений </span></span> — <span class="tlid-translation translation" lang="ru"><span title=""> значение по горизонтали, за которым следует значение по вертикали.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете использовать такие ключевые слова, как <code>top</code> и <code>right</code> (с остальными можете ознакомиться на странице {{cssxref ("background-position")}}):</span></span></p> + +<pre class="brush: css notranslate"><code>.box { + background-image: url(star.png); + background-repeat: no-repeat; + background-position: top center; +} </code> +</pre> + +<p>Допустимы значения <a href="/ru/docs/Web/CSS/размер">длины</a> и <a href="/ru/docs/Web/CSS/percentage">процентные</a>:</p> + +<pre class="brush: css notranslate"><code>.box { + background-image: url(star.png); + background-repeat: no-repeat; + background-position: 20px 10%; +} </code> +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы также можете смешивать значения ключевых слов с длинами или процентами, например:</span></span></p> + +<pre class="brush: css notranslate">.box { + background-image: url(star.png); + background-repeat: no-repeat; + background-position: top 20px; +}</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">И наконец, вы также можете использовать синтаксис с четырьмя значениями, чтобы указать расстояние от определенных краёв блока - единица длины в данном случае представляет собой смещение от значения ключевого слова.</span> <span title="">Итак, в CSS ниже мы сместили фон на 20 пикселей сверху и на 10 пикселей справа:</span></span></p> + +<pre class="brush: css notranslate"><code>.box { + background-image: url(star.png); + background-repeat: no-repeat; + background-position: top 20px right 10px; +} </code></pre> + +<p><strong><span class="tlid-translation translation" lang="ru"><span title="">Используйте приведенный ниже пример, чтобы поэкспериментировать с этими значениями и переместить звезду внутри блока.</span></span></strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/position.html", '100%', 480)}}</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: <code>background-position</code> — это сокращение для {{cssxref("background-position-x")}} и {{cssxref("background-position-y")}}, <span class="tlid-translation translation" lang="ru"><span title="">которые позволяют вам устанавливать различные значения положения по оси индивидуально</span></span>.</p> +</div> + +<h3 id="Градиент_в_качестве_фона">Градиент в качестве фона</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Градиент - при использовании для фона - действует так же, как изображение, и поэтому задаётся свойством {{cssxref ("background-image")}}.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете прочитать больше о различных типах градиентов и о том, что вы можете с ними делать на странице MDN для типа данных </span></span><code><a href="/en-US/docs/Web/CSS/gradient"><gradient></a></code><span class="tlid-translation translation" lang="ru"><span title="">.</span> <span title="">Поиграть с градиентами Вы можете используя один из многих генераторов градиентов CSS, доступных в Интернете, например </span></span><a href="https://cssgradient.io/">этот</a><span class="tlid-translation translation" lang="ru"><span title="">.</span> <span title="">Вы можете создать градиент, а затем скопировать и вставить его </span></span>в свой код<span class="tlid-translation translation" lang="ru"><span title="">.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Попробуйте использовать разные градиенты в примере ниже.</span> <span title="">В двух блоках соответственно у нас есть линейный градиент, растянутый на весь блок, и радиальный градиент с заданным размером, который поэтому повторяется.</span></span></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/gradients.html", '100%', 600)}}</p> + +<h3 id="Несколько_фоновых_изображений">Несколько фоновых изображений</h3> + +<p>Также возможно создавать несколько фоновых изображений — просто разделив значения свойства <code>background-image</code> запятыми.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Когда Вы сделаете это, произойдёт наложение фоновых изображений друг на друга.</span> <span title="">Фоновые изображения будут наложены слоями, где каждое новое фоновое изображение, перечисленное в коде, будет накладываться поверх ранее указанного изображения.</span></span> </p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Градиенты можно <span class="tlid-translation translation" lang="ru"><span title="">легко смешивать с обычными фоновыми изображениями</span></span>.</p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Другие свойства <code>background- *</code> также могут иметь значения, разделенные запятыми, как и <code>background-image</code>:</span></span></p> + +<pre class="brush: css notranslate">background-image: url(image1.png), url(image2.png), url(image3.png), url(image1.png); +background-repeat: no-repeat, repeat-x, repeat; +background-position: 10px 20px, top right;</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Каждое значение различных свойств будет соответствовать значениям в той же позиции в других свойствах.</span> <span title="">Выше, например, значение <code>background-repeat</code> для <code>image1</code> будет <code>no-repeat</code>.</span> <span title="">Однако, что происходит, когда разные свойства имеют разное количество значений?</span> <span title="">Ответ заключается в том, что меньшее количество значений будет циклически повторяться - в приведенном выше примере есть четыре фоновых изображения, и только два значения <code>background-position</code>.</span> <span title="">Первые два значения позиции будут применены к первым двум изображениям, затем они снова будут циклически повторяться - <code>image3</code> будет присвоено первое значение позиции, а <code>image4</code> будет присвоено второе значение позиции.</span></span></p> + +<p><strong><span class="tlid-translation translation" lang="ru"><span title="">Поиграем?</span> <span title="">В приведенном ниже примере я добавил два изображения.</span> <span title="">Чтобы продемонстрировать порядок наложения, попробуйте </span></span>поменять порядок фоновых изображений<span class="tlid-translation translation" lang="ru"><span title=""> в списке.</span> <span title="">Или поиграйте с другими свойствами, чтобы изменить положение, размер или повторяемость значений.</span></span></strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/multiple-background-image.html", '100%', 480)}}</p> + +<h3 id="Закрепление_фона">Закрепление фона</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Другая опция, которую можно применить к фону, - это указать, как он будет прокручиваться при прокрутке содержимого.</span> <span title="">Это контролируется с помощью свойства {{cssxref ("background-attachment")}}, которое может принимать следующие значения:</span></span></p> + +<ul> + <li><code>scroll</code>: Заставляет <span class="tlid-translation translation" lang="ru"><span title="">элементы фона прокручиваться при прокрутке страницы.</span> <span title="">Если содержимое элемента прокручивается, фон не перемещается.</span> <span title="">Фактически, фон фиксируется в той же позиции на странице, поэтому он прокручивается по мере прокрутки страницы.</span></span></li> + <li><code>fixed</code>: <span class="tlid-translation translation" lang="ru"><span title="">Фиксирует элементы фона в области просмотра, чтобы он не прокручивался при прокрутке страницы или содержимого элемента.</span> <span title="">Фон всегда будет оставаться на одном и том же месте на экране.</span></span></li> + <li><code>local</code>: <span class="tlid-translation translation" lang="ru"><span title="">Это значение было добавлено позже (оно поддерживается только в Internet Explorer 9+, тогда как другие поддерживаются в IE4+), потому что значение </span></span><code>scroll</code><span class="tlid-translation translation" lang="ru"><span title=""> довольно запутанно и во многих случаях действительно не делает то, что вы хотите.</span> <span title="">Значение </span></span><code>local</code><span class="tlid-translation translation" lang="ru"><span title=""> фиксирует фон для элемента, к которому он применён, поэтому, когда вы прокручиваете элемент, фон прокручивается вместе с ним.</span></span> </li> +</ul> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Свойство {{cssxref ("background-attachment")}} действует только тогда, когда есть контент для прокрутки, поэтому мы сделали пример, чтобы продемонстрировать различия между тремя значениями - взгляните на </span></span><a href="http://mdn.github.io/learning-area/css/styling-boxes/backgrounds/background-attachment.html">background-attachment.html</a><span class="tlid-translation translation" lang="ru"> <span title="">(также смотри <a href="https://github.com/mdn/learning-area/tree/master/css/styling-boxes/backgrounds">исходный код</a> здесь).</span></span></p> + +<h3 id="Использование_сокращенного_свойства_background"><span class="tlid-translation translation" lang="ru"><span title="">Использование сокращенного свойства background</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Как я упоминал в начале этого урока, вы часто будете видеть фон, заданный с помощью свойства {{cssxref ("background")}}.</span> <span title="">Это сокращение позволяет вам одновременно устанавливать все различные свойства.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">При использовании нескольких фонов необходимо указать все свойства для первого фона, а затем добавить следующий фон после запятой.</span> <span title="">В приведенном ниже примере у нас есть градиент с размером и положением, затем фоновое изображение со значением </span></span><code>no-repeat</code><span class="tlid-translation translation" lang="ru"><span title=""> и положением, затем цвет.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">При записи сокращенных значений фонового изображения необходимо соблюдать несколько правил, например:</span></span></p> + +<ul> + <li><code>background-color</code> можно указывать только после последней запятой.</li> + <li>Значения <code>background-size</code> могут быть включены только сразу после <code>background-position</code>, разделенные символом '/', например: <code>center/80%</code>. </li> +</ul> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Посетите страницу MDN свойства {{cssref ("background")}}, чтобы увидеть полное описание.</span></span></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/background.html", '100%', 600)}} </p> + +<h3 id="Доступность_просмотра">Доступность просмотра</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Помещая текст поверх фонового изображения или цвета, вы должны позаботиться о том, чтобы у вас было достаточно контраста, чтобы текст был читаемым для посетителей вашего сайта.</span> <span title="">Если указывается изображение, и текст будет помещен поверх этого изображения, вы также должны указать </span></span><code>background-color</code><span class="tlid-translation translation" lang="ru"><span title="">, который позволит тексту быть разборчивым, если изображение не загружается.</span></span></p> + +<p>Программы чтения с экрана не могут анализировать фоновые изображения, поэтому они должны быть чисто декоративными; любой важный контент должен быть частью HTML-страницы, а не находиться в фоне.</p> + +<h2 id="Границы">Границы</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Изучая Блочную модель, мы обнаружили, как границы влияют на размер нашего блока.</span> <span title="">В этом уроке мы рассмотрим, как творчески использовать границы.</span> <span title="">Обычно, когда мы добавляем границы к элементу с помощью CSS, мы используем сокращенное свойство, которое устанавливает цвет, ширину и стиль границы в одной строке CSS.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Мы можем установить границу для всех четырех сторон блока с помощью {{cssxref ("border")}}:</span></span></p> + +<pre class="brush: css notranslate"><code>.box { + border: 1px solid black; +} </code></pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Или мы можем нацеливаться на один край блока, например:</span></span></p> + +<pre class="brush: css notranslate"><code>.box { + border-top: 1px solid black; +} </code></pre> + +<p>Индивидуальные свойства этих сокращений будут следующими:</p> + +<pre class="brush: css notranslate"><code>.box { + border-width: 1px; + border-style: solid; + border-color: black; +} </code></pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">И более детально:</span></span></p> + +<pre class="brush: css notranslate"><code>.box { + border-top-width: 1px; + border-top-style: solid; + border-top-color: black; +} </code></pre> + +<div class="blockIndicator note"> +<p><strong><span class="tlid-translation translation" lang="ru"><span title="">Примечание</span></span></strong>: <span class="tlid-translation translation" lang="ru"><span title="">Свойства границ </span></span>top, right, bottom, и left<span class="tlid-translation translation" lang="ru"><span title=""> также имеют сопоставленные <em>логические</em> свойства, которые относятся к режиму написания документа (например, текст слева направо, справа налево или сверху вниз).</span></span> <span class="tlid-translation translation" lang="ru"><span title="">Мы рассмотрим их в следующем уроке, который касается <a href="/ru/docs/CSS/Building_blocks/Handling_different_text_directions">работы с разными направлениями текста</a>.</span></span></p> +</div> + +<p><strong>Есть множество стилей, которые вы можете использовать для границ. В приведенном ниже примере мы использовали <span class="tlid-translation translation" lang="ru"><span title="">разные стили границ для четырех сторон моего блока</span></span>. Поиграйте со стилем, шириной и цветом границы, чтобы увидеть, как они работают.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/borders.html", '100%', 640)}}</p> + +<h3 id="Закруглённые_углы">Закруглённые углы</h3> + +<p>Закругление углов блока достигается с помощью свойства {{cssxref ("border-radius")}} и связанных свойств, которые относятся к каждому углу блока. В качестве значения могут использоваться два значения длины или процента: первое значение определяет горизонтальный радиус, а второе - вертикальный радиус. Чаще задают только одно значение, которое используется для обоих.</p> + +<p>Например, чтобы сделать все четыре угла блока радиусом 10px:</p> + +<pre class="brush: css notranslate"><code>.box { + border-radius: 10px; +} </code></pre> + +<p>Или, чтобы верхний правый угол имел горизонтальный радиус 1em и вертикальный радиус 10%:</p> + +<pre class="brush: css notranslate"><code>.box { + border-top-right-radius: 1em 10%; +} </code></pre> + +<p>В примере ниже мы установили все четыре угла, а затем изменили значения для верхнего правого угла, чтобы сделать его другим. Вы можете поиграть со значениями, чтобы изменить углы. Взгляните на страницу свойств для {{cssxref("border-radius")}} чтобы увидеть доступные варианты синтаксиса.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/corners.html", '100%', 620)}}</p> + +<h2 id="Упражнение_с_границами_и_фоном">Упражнение с границами и фоном</h2> + +<p>Чтобы проверить свои новые знания, попробуйте создать следующее, используя фон и границы, используя приведенный ниже пример в качестве отправной точки:</p> + +<ol> + <li>Задайте рамку равную 5px black solid, с закругленными углами 10px.</li> + <li>Добавить фоновое изображение (используйте URL <code>balloons.jpg</code>) и установите размер таким образом, чтобы он покрыл весь блок.</li> + <li>Задайте для <code><h2></code> полупрозрачный черный цвет фона и сделайте текст белым.</li> +</ol> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/task.html", '100%', 555)}} </p> + +<div class="blockIndicator note"> +<p><strong><span class="tlid-translation translation" lang="ru"><span title="">Примечание</span></span>:</strong> Вы можете посмотреть <a href="https://github.com/mdn/css-examples/blob/master/learn/solutions.md">решение</a> здесь — <span class="tlid-translation translation" lang="ru"><span title="">но сначала попробуйте сделать это сами</span></span>!</p> +</div> + +<h2 id="Итоги">Итоги</h2> + +<p>В этой теме мы рассмотрели довольно много, но как вы можете увидеть, возможностей по стилизации фона или границ блока намного больше. Изучите различные страницы свойств, если хотите узнать больше о каких-либо функциях, которые мы обсуждали. На каждой странице MDN есть много примеров использования свойств, с которыми вы можете поиграть и расширить свои знания.</p> + +<p>В следующем уроке мы узнаем, как Режим написания вашего документа взаимодействует с вашим CSS. Что происходит, если текст не перетекает слева направо?</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/The_box_model", "Learn/CSS/Building_blocks/Handling_different_text_directions", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование </a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B">Селекторы CSS</a> <a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы"> </a> + <ul> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Type_Class_and_ID_Selectors">Селекторы типа, класса и ID</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Attribute_selectors">Селекторы атрибута</a> <a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Attribute_selectors"> </a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">Псевдоклассы и псевдоэлементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Combinators">Комбинаторы</a> <a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Combinators"> </a></li> + </ul> + </li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/The_box_model">Модель коробки</a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Фон и границы </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Изменение направления текста </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Overflowing_content">Перекрытие содержимого</a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Values_and_units">Значения свойств CSS </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Изменение размеров в CSS </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Изображения, формы и прочие медиа-элементы </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Styling_tables">Стилизация таблиц </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Organizing">Организация CSS-кода</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/cascade_and_inheritance/index.html b/files/ru/learn/css/building_blocks/cascade_and_inheritance/index.html new file mode 100644 index 0000000000..5d29314cea --- /dev/null +++ b/files/ru/learn/css/building_blocks/cascade_and_inheritance/index.html @@ -0,0 +1,345 @@ +--- +title: Каскад и наследование +slug: Learn/CSS/Building_blocks/Cascade_and_inheritance +tags: + - CSS + - Каскад + - Наследование + - Начинающий + - Обучение + - Порядок следования + - Правила + - Специфичность +translation_of: Learn/CSS/Building_blocks/Cascade_and_inheritance +--- +<div>{{LearnSidebar}}{{NextMenu("Learn/CSS/Building_blocks/Selectors", "Learn/CSS/Building_blocks")}}</div> + +<p>Цель этого урока — углубить Ваше понимание некоторых основополагающих концепций CSS — каскадов, спецификаций и наследования, — которые контролируют то, как CSS применяется к HTML и как разрешаются конфликты.</p> + +<p>Хотя изучение этого урока может показаться менее актуальным и немного более академичным, чем некоторые другие части курса, понимание этих вещей спасёт вас от головной боли в дальнейшем! Мы рекомендуем вам внимательно изучить этот раздел и убедиться, что вы понимаете концепции, перед тем, как двигаться дальше.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/ru-RU/Learn/Getting_started_with_the_web/Installing_basic_software">Установка базового ПО</a>, базовые знания <a href="https://developer.mozilla.org/ru-RU/Learn/Getting_started_with_the_web/Dealing_with_files">работы с файлами</a>, основы HTML (<a href="/ru-RU/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), и общее представление о том, как работает CSS (<a href="/ru-RU/docs/Learn/CSS/First_steps">Введение в CSS</a>.)</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Изучить понятие о каскаде и специфичности, и как работает наследование CSS.</td> + </tr> + </tbody> +</table> + +<h2 id="Конфликтующие_правила">Конфликтующие правила</h2> + +<p>CSS (Cascading Style Sheets) означает Каскадные Таблицы Стилей и первое слово <em>"каскадные" </em>является невероятно важным для понимания: то, как ведёт себя каскад — ключевой момент в понимании CSS.</p> + +<p>В какой-то момент, работая над проектом, вы обнаружите, что CSS, который, по-вашему, должен быть применен к элементу, не работает. Обычно проблема заключается в том, что вы создали два правила, которые могут потенциально применяться к одному и тому же элементу. <strong>Каскад</strong> и тесно связанная концепция <strong>специфичности</strong> <span style='font-family: "Times New Roman",serif; font-size: 12.0pt; line-height: 200%;'>— </span> это механизмы, которые контролируют, какое именно правило применяется, когда имеется такой конфликт. Стиль вашего элемента может определять не то правило, на которое вы рассчитывали, поэтому вам необходимо понимать, как работают эти механизмы.</p> + +<p>Также значимой является концепция <strong>наследования, </strong>которая заключается в том, что некоторые свойства CSS наследуют по умолчанию значения, установленные для родительского элемента текущего элемента, а некоторые не наследуют. Это также может стать причиной поведения, которое вы, возможно, не ожидаете.</p> + +<p>Давайте начнём с краткого обзора ключевых моментов, которых мы касаемся, далее рассмотрим каждый из них по очереди и посмотрим, как они взаимодействуют друг с другом и с вашим CSS. Это может показаться набором сложных для понимания понятий. Однако, когда вы получите больше опыта в написании CSS, для вас станет более очевидным то, как это работает.</p> + +<h3 id="Каскад">Каскад</h3> + +<p>Каскад таблицы стилей, если говорить упрощённо, означает, что порядок следования правил в CSS имеет значение; когда применимы два правила, имеющие одинаковую специфичность, используется то, которое идёт в CSS последним.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В приведенном ниже примере у нас есть два правила, которые могут применяться к h1. В результате </span><span title="">h1 окрасится синим цветом </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> эти правила имеют идентичный селектор и, следовательно, одинаковую специфичность, поэтому побеждает последний в порядке следования.</span></span></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/cascade-simple.html", '100%', 400)}} </p> + +<h3 id="Специфичность">Специфичность</h3> + +<p>Cпецифичность определяет, как браузер решает, какое именно правило применяется в случае, когда несколько правил имеют разные селекторы, но, тем не менее, могут быть применены к одному и тому же элементу. <em>Различные типы селекторов ( селекторы элементов <code>h1{...}</code>, селекторы классов, селекторы идентификаторов и т.д ) имеют разной степени влияние на элементы страницы. Чем более общее влияние оказывает селектор на элементы страницы тем меньше его специфичность, конкретность.</em> По существу, это мера того, насколько специфическим будет отбор по селектору:</p> + +<ul> + <li>Селектор элементов ( <em>например <code>h1</code></em> ) менее специфичен — он выберет все элементы этого типа на странице — поэтому получит меньше баллов.</li> + <li> + <p class="brush: css">Селектор класса более специфичен — он выберет только те элементы на странице, которые имеют конкретное значение атрибута <code>class</code> — поэтому получит больше баллов, <em>селектор класса применится после селектора элемента и поэтому перекроет его стили</em>.</p> + </li> +</ul> + +<p>Например. Как указано ниже, у нас опять есть два правила, которые могут применяться к <code>h1</code>. <code>h1</code> в результате будет окрашен красным цветом — селектор класса даёт своему правилу более высокую специфичность, поэтому он будет применён, несмотря на то, что правило для селектора элемента расположено ниже в таблице стилей.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/specificity-simple.html", '100%', 500)}} </p> + +<p>Позже мы объясним, как сделать оценку специфичности, и прочие детали.</p> + +<h3 id="Наследование">Наследование</h3> + +<p>Наследование также надо понимать в этом контексте — некоторые значения свойства CSS, установленные для родительских элементов наследуются их дочерними элементами, а некоторые нет.</p> + +<p>Например, если вы установили значение <code>color</code> и <code>font-family</code> для элемента, то каждый элемент внутри него также будет иметь этот цвет и шрифт, если только вы не применили к ним напрямую стиль с другим цветом и шрифтом.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/inheritance-simple.html", '100%', 550)}} </p> + +<p>Некоторые свойства не наследуются — например, если вы установили для элемента {{cssxref("width")}} равным 50%, все его дочерние элементы не получат ширину в 50% от ширины своего родительского элемента. Если бы это было так, CSS было бы черезвычайно трудно использовать!</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: На страницах справочника CSS свойств вы можете найти окно технической информации, обычно в конце раздела спецификации, в котором перечислены некоторые технические данные об этом свойстве, в том числе наследуется оно или нет. Например, здесь: <a href="https://developer.mozilla.org/ru-RU/docs/Web/CSS/color#Specifications">color property Specifications section</a>.</p> +</div> + +<h2 id="Понимание_взаимодействия_этих_концепций">Понимание взаимодействия этих концепций</h2> + +<p>Эти три концепции вместе определяют, какая CSS применяется и к какому элементу; в следующих разделах мы увидим, как они взаимодействуют. Это может показаться сложным, но вы начнёте лучше понимать их по мере приобретения опыта работы с CSS, и вы всегда можете обратиться к справочной информации, если что-то забыли. Даже опытные разработчики не помнят всех деталей!</p> + +<p>Видео ниже показывает, как вы можете использовать Firefox DevTools для проверки каскада стилей, спецификации, и т.д. на странице:</p> + +<p>{{EmbedYouTube("Sp9ZfSvpf7A")}}</p> + +<h2 id="Понимание_наследования">Понимание наследования</h2> + +<p>Итак, наследование. В примере ниже мы имеем {{HTMLElement("ul")}} с двумя уровнями неупорядоченных списков, вложенных в него. Мы устанавили для внешнего <code><ul></code> стиль границы, внутренние отступы и цвет шрифта.</p> + +<p>Цвет шрифта применён к прямому потомку, но также и к непрямому потомку — к прямому потомку <code><li></code> и к элементам внутри первого вложенного списка. Далее мы добавили класс <code>special</code> ко второму вложенному списку и применили к нему другой цвет шрифта. Теперь это свойство наследуется всеми его потомками.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/inheritance.html", '100%', 700)}} </p> + +<p>Такие свойства, как ширина (как в примере выше), внутренние и внешние отступы и стиль границы не наследуются. Если бы потомки нашего списка наследовали бы границу, то каждый отдельный список и каждая позиция в списке получили бы такую же границу — вряд ли мы хотели бы получить такой эффект!</p> + +<p>Какие свойства наследуются по умолчанию, а какие нет, чаще всего определяется здравым смыслом.</p> + +<h3 id="Контроль_наследования">Контроль наследования</h3> + +<p>CSS предоставляет четыре специальных универсальных значения свойства для контроля наследования. Каждое свойство CSS принимает эти значения.</p> + +<dl> + <dt>{{cssxref("inherit")}}</dt> + <dd>Устанавливает значение свойства, применённого к элементу, таким же, как у его родительского элемента. Фактически, это "включает наследование".</dd> + <dt>{{cssxref("initial")}}</dt> + <dd>Устанавливает значение свойства, применённого к выбранному элементу, равным <a href="https://wiki.developer.mozilla.org/ru-RU/docs/Web/CSS/initial_value">initial value</a> этого свойства (<em>в соответствии с настройками браузера по умолчанию. Если в таблице стилей браузера отсутствует значение этого свойства, оно наследуется естественным образом.)</em></dd> + <dt>{{cssxref("unset")}}</dt> + <dd>Возвращает свойству его естественное значение, что означает, что если свойство наследуется естественным образом, оно действует как <code>inherit</code>, иначе оно действует как <code>initial</code>.</dd> +</dl> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Существует также более новое значение {{cssxref("revert")}}, которое имеет ограниченную поддержку браузерами.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Смотрите {{SectionOnPage("/ru-RU/docs/Web/CSS/Cascade", "Origin of CSS declarations")}} для более подробной информации о каждом из них, и о том, как они работают.</p> +</div> + +<p>Можно посмотреть список ссылок и изучить, как работают универсальные значения. Пример, следующий ниже, позволяет вам поиграть с CSS и увидеть, что происходит, когда вы вносите изменения. Подобные эксперименты с кодом — лучший способ освоить HTML и CSS.</p> + +<p>Например:</p> + +<ol> + <li>Второй элемент списка имеет класс <code>my-class-1</code>. Таким образом, цвет для следующего вложенного элемента <code>a</code> устанавливается по наследству. Как изменится цвет, если это правило будет удалено?</li> + <li>Понятно ли, почему третий и четвертый элементы <code>a</code> имеют именно такой цвет? Если нет, перечитайте описание значений, представленное выше.</li> + <li>Какая из ссылок изменит цвет, если вы зададите новый цвет для элемента <code><a></code> — например: <code>a { color: red; }</code>?</li> +</ol> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/keywords.html", '100%', 700)}}</p> + +<h3 id="Возврат_всех_исходных_значений_свойств">Возврат всех исходных значений свойств</h3> + +<p>Стенографическое свойство CSS <code>all</code> можно использовать для того, чтобы присвоить одно из значений наследования к (почти) всем свойствам одновременно. Это одно из четырех значений (<code>inherit</code>, <code>initial</code>, <code>unset</code>, или <code>revert</code>). Это удобный способ для отмены изменений, внесённых в стили, для того, чтобы вы могли вернуться к стартовой точке перед внесением новых изменений.</p> + +<p>В примере ниже имеются два блока <code><blockquote></code>. Первый имеет стиль, который применён к самому элементу <code>blockquote</code>, второй имеет класс <code>fix-this</code>, который устанавливает значение <code>all</code> в <code>unset</code>.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/all.html", '100%', 700)}} </p> + +<p>Попробуйте установить для <code>all</code> ещё одно из доступных значений и исследуйте, в чём заключается разница.</p> + +<h2 id="Понимание_каскада">Понимание каскада</h2> + +<p>Теперь мы понимаем, почему параграф, следующий по глубине в структуре HTML документа, имеет тот же цвет, что CSS применяет к body, а вводные уроки дали понимание того, как изменить применение CSS к чему-либо в любой точке документа — или назначить CSS элементу, или создать класс. Теперь рассмотрим подробнее то, как каскад определяет выбор CSS правил, применяемых в случае влияния на стиль элемента нескольких объектов.</p> + +<p>Вот три фактора, перечисленные в порядке возрастания важности. Следующий отменяет предыдущий.</p> + +<ol> + <li><strong>Порядок следования</strong></li> + <li><strong>Специфичность</strong></li> + <li><strong>Важность</strong></li> +</ol> + +<p>Мы внимательно изучим их, чтобы увидеть, как именно браузеры определяют, какой CSS следует применить.</p> + +<h3 id="Порядок_следования">Порядок следования</h3> + +<p>Мы уже видели, какое значение для каскада имеет порядок следования. Если у вас несколько правил, которые имеют одинаковую важность, то побеждает правило, которое идет последним в CSS. Другими словами, правила, более близкие к самому элементу, переписывают более ранние, пока последнее не победит, оно и стилизует элемент. </p> + +<h3 id="Специфичность_2">Специфичность</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Понимая, что порядок следования правил имеет значение, в какой-то момент вы окажетесь в ситуации, когда вы знаете, что правило появляется позже в таблице стилей, но применяется более раннее, конфликтующее правило.</span> <span title="">Это связано с тем, что более раннее правило имеет более <strong>высокую специфичность</strong> </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> оно более специфично и поэтому выбирается браузером как правило, которое должно стилизовать элемент.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Как мы видели ранее в этом уроке, селектор класса имеет больший вес, чем селектор элемента, поэтому свойства, определенные в классе, будут переопределять свойства, примененные непосредственно к элементу.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Здесь следует отметить, что, хотя мы думаем о селекторах и правилах, применяемых к объекту, который они выбирают, переписывается не всё правило, а только свойства, которые являются одинаковыми.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Такое поведение помогает избежать повторения в вашем CSS.</span> <span title="">Обычной практикой является определение общих стилей для базовых элементов, а затем создание классов для тех, которые отличаются.</span> <span title="">Например, в таблице стилей ниже мы определяем общие стили для заголовков второго уровня, а затем создаём несколько классов, которые изменяют только некоторые свойства и значения.</span> <span title="">Определенные вначале значения применяются ко всем заголовкам, затем к заголовкам с классами применяются более конкретные значения.</span></span></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/mixing-rules.html", '100%', 700)}} </p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Давайте теперь посмотрим, как браузер будет вычислять специфичность.</span> <span title="">Мы уже знаем, что селектор элемента имеет низкую специфичность и может быть перезаписан классом.</span> <span title="">По существу, значение в баллах присуждается различным типам селекторов, и их сложение дает вам вес этого конкретного селектора, который затем может быть оценён в сравнении с другими потенциальными соперниками.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Степень специфичности, которой обладает селектор, измеряется с использованием четырех различных значений (или компонентов), которые можно представить как тысячи, сотни, десятки и единицы </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> четыре однозначные цифры в четырех столбцах:</span></span></p> + +<ol> + <li><strong>Тысячи</strong>: поставьте единицу в эту колонку, если объявление стиля находится внутри атрибута {{htmlattrxref("style")}} (встроенные стили). Такие объявления не имеют селекторов, поэтому их специфичность всегда просто 1000.</li> + <li><strong>Сотни</strong>: поставьте единицу в эту колонку за каждый селектор ID, содержащийся в общем селекторе.</li> + <li><strong>Десятки</strong>: поставьте единицу в эту колонку за каждый <span class="tlid-translation translation" lang="ru"><span title="">селектор класса, селектор атрибута или псевдокласс, содержащийся в общем селекторе.</span></span></li> + <li><strong>Единицы</strong>: поставьте общее число единиц в эту колонку за каждый <span class="tlid-translation translation" lang="ru"><span title="">селектор элемента или псевдоэлемент, содержащийся в общем селекторе.</span></span></li> +</ol> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title=""><strong>Примечание:</strong> Универсальный селектор (*), комбинаторы (+, >, ~, '') и псевдо-класс отрицания (:not) не влияют на специфичность.</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Следующая таблица показывает несколько несвязанных примеров, которые помогут вам</span></span> разобраться. <span class="tlid-translation translation" lang="ru"><span title="">Посмотрите их все и убедитесь, что вы понимаете, почему они обладают той специфичностью, которую мы им дали.</span></span> <span class="tlid-translation translation" lang="ru"><span title="">Мы ещё не рассмотрели селекторы детально, но вы можете найти подробную информацию о каждом селекторе в</span></span> <a href="/ru/docs/Web/CSS/CSS_Селекторы">справочнике селекторов</a> MDN.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Селектор</th> + <th scope="col">Тысячи</th> + <th scope="col">Сотни</th> + <th scope="col">Десятки</th> + <th scope="col">Единицы</th> + <th scope="col">Специфичность</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>h1</code></td> + <td>0</td> + <td>0</td> + <td>0</td> + <td>1</td> + <td>0001</td> + </tr> + <tr> + <td><code>h1 + p::first-letter</code></td> + <td>0</td> + <td>0</td> + <td>0</td> + <td>3</td> + <td>0003</td> + </tr> + <tr> + <td><code>li > a[href*="en-US"] > .inline-warning</code></td> + <td>0</td> + <td>0</td> + <td>2</td> + <td>2</td> + <td>0022</td> + </tr> + <tr> + <td><code>#identifier</code></td> + <td>0</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>0100</td> + </tr> + <tr> + <td>Без селектора, с правилом внутри атрибута {{htmlattrxref("style")}} элемента.</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>0</td> + <td>1000</td> + </tr> + </tbody> +</table> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Прежде чем мы продолжим, давайте посмотрим на пример в действии.</span></span></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/specificity-boxes.html", '100%', 700)}} </p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Так что здесь происходит?</span> <span title="">Прежде всего, нас интересуют только первые семь правил этого примера, и, как вы заметите, мы включили их значения специфичности в комментарий перед каждым правилом.</span></span></p> + +<ul> + <li><span class="tlid-translation translation" lang="ru"><span title="">Первые два правила конкурируют за стилизацию цвета фона ссылки </span></span> — <span class="tlid-translation translation" lang="ru"><span title=""> второе выигрывает и делает фоновый цвет синим, потому что у него есть дополнительный селектор ID в цепочке: его специфичность 201 против 101.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Третье и четвертое правило конкурируют за стилизацию цвета текста ссылки </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> второе выигрывает и делает текст белым, потому что, хотя у него на один селектор элемента меньше, отсутствующий селектор заменяется на селектор класса, который оценивается в десять вместо единицы</span><span title="">.</span> <span title="">Таким образом, приоритетная специфичность составляет 113 против 104.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Правила 5–7 соревнуются за определение стиля границы ссылки при наведении курсора.</span> <span title="">Шестой селектор со специфичностью 23 явно проигрывает пятому со специфичностью 24 </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> у него в цепочке на один селектор элемента меньше.</span> <span title="">Седьмой селектор, однако, превосходит как пятый, так и шестой </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> </span></span><span class="tlid-translation translation" lang="ru"><span title="">он имеет то же количество подселекторов в цепочке, что и пятый, но один элемент заменён селектором класса.</span> <span title="">Таким образом, приоритетная специфичность 33 против 23 и 24.</span></span></li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Это был условный пример для более простого усвоения. В действительности, каждый тип селектора имеет собственный уровень специфичности, который не может быть замещён селекторами с более низким уровнем специфичности. Например, <em>миллион</em> соединённых селекторов <strong>класса</strong> не способны переписать правила <em>одного</em> селектора <strong>id</strong>.</p> + +<p>Более правильный способ вычисления специфичности состоит в индивидуальной оценке уровней специфичности, начиная с наивысшего и продвигаясь к самому нижнему, когда это необходимо. Только когда оценки уровня специфичности совпадают, следует вычислять следующий нижний уровень; в противном случае, вы можете пренебречь селекторами с меньшим уровнем специфичности, поскольку они никогда не смогут преодолеть уровни более высокой специфичности.</p> +</div> + +<h3 id="!important">!important</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Существует специальный элемент CSS, который вы можете использовать для отмены всех вышеперечисленных вычислений, однако вы должны быть очень осторожны с его использованием</span></span> — <code>!important</code>. <span class="tlid-translation translation" lang="ru"><span title="">Он используется, чтобы сделать конкретное свойство и значение самыми специфичными, таким образом переопределяя нормальные правила каскада.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Взгляните на этот пример, где у нас есть два абзаца, один из которых имеет ID.</span></span></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/important.html", '100%', 700)}} </p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Давайте пройдемся по этому примеру, чтобы увидеть, что происходит </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> попробуйте удалить некоторые свойства, чтобы увидеть, что получится, если вам трудно понять:</span></span></p> + +<ol> + <li>Вы увидите, что применены значения {{cssxref("color")}} и {{cssxref("padding")}} третьего правила, но {{cssxref("background-color")}} — нет. Почему? <span class="tlid-translation translation" lang="ru"><span title="">Действительно, все три безусловно должны применяться, потому что правила, более поздние в порядке следования, обычно переопределяют более ранние правила.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Однако вышеприведенные правила выигрывают, потому что селекторы классов имеют более высокую специфичность, чем селекторы элементов.</span></span></li> + <li>Оба элемента имеют {{htmlattrxref("class")}} с названием <code>better</code>, но у второго также есть {{htmlattrxref("id")}} с названием <code>winning</code>. <span class="tlid-translation translation" lang="ru"><span title="">Поскольку ID имеют <em>ещё более высокую</em> специфичность, чем классы (у вас может быть только один элемент с каждым уникальным ID на странице, но много элементов с одним и тем же классом </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> селекторы ID <em>очень специфичны</em>, на что они и нацелены), красный цвет фона и однопиксельная</span> <span title="">черная граница должны быть применены ко 2-му элементу, причём первый элемент получает серый фоновый цвет и отсутствие границы, как определено классом.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">2-й элемент получил красный цвет фона и отсутствие границы.</span> Почему<span title="">?</span> </span> Из-за объявления <code>!important</code> во втором правиле — размещение которого после <code>border: none</code> <span class="tlid-translation translation" lang="ru"><span title="">означает, что это объявление перевесит значение границы в предыдущем правиле, даже если ID имеет более высокую специфичность.</span></span></li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: <span class="tlid-translation translation" lang="ru"><span title="">Единственный способ переопределить объявление</span></span> <code>!important</code> – <span class="tlid-translation translation" lang="ru"><span title="">это включить другое объявление </span></span><code>!important</code> <span class="tlid-translation translation" lang="ru"><span title="">в правило <em>с такой же специфичностью</em> позже или в правило с более высокой специфичностью.</span></span></p> +</div> + +<p>Полезно знать о существовании <code>!important</code>, чтобы вы понимали, что это такое, когда встретите в чужом коде. <strong><span class="tlid-translation translation" lang="ru"><span title="">Тем не менее, мы настоятельно рекомендуем вам никогда не использовать его, если в этом нет острой необходимости</span></span>.</strong> <code>!important</code> <span class="tlid-translation translation" lang="ru"><span title="">меняет обычный порядок работы каскада, поэтому он может серьёзно затруднить отладку проблем CSS, особенно в большой таблице стилей.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Одна из ситуаций, в которой вам, возможно, придётся это использовать, </span></span> — <span class="tlid-translation translation" lang="ru"><span title=""> это когда вы работаете с CMS, где вы не можете редактировать модули CSS ядра, и вы действительно хотите переопределить стиль, который нельзя переопределить другим способом.</span> <span title="">Но, вообще говоря, не стоит использовать этот элемент, если можно этого избежать.</span></span></p> + +<h2 id="Влияние_расположения_CSS">Влияние расположения CSS</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Наконец, также полезно отметить, что важность объявления CSS зависит от того, в какой таблице стилей оно указано </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> у пользователя есть возможность установить индивидуальные таблицы стилей для переопределения стилей разработчика, например, пользователь может иметь проблемы со зрением и захочет</span> <span title="">установить размер шрифта на всех посещаемых им веб-страницах в два раза больше нормального размера, чтобы облегчить чтение.</span></span></p> + +<h2 id="Подведение_итогов">Подведение итогов</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Конфликтующие объявления будут применяться в следующем порядке, с учётом замены более ранних более поздними</span></span>:</p> + +<ol> + <li><span class="tlid-translation translation" lang="ru"><span title="">Объявления в таблицах стилей клиентского приложения (например, стили браузера по умолчанию, используемые, когда не заданы другие стили).</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Обычные объявления в пользовательских таблицах стилей (индивидуальные стили устанавливаются пользователем).</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Обычные объявления в авторских таблицах стилей (это стили, установленные нами, веб-разработчиками)</span></span>.</li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Важные объявления в авторских таблицах стилей.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Важные объявления в пользовательских таблицах стилей.</span></span></li> +</ol> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Для таблиц стилей веб-разработчиков имеет смысл переопределить пользовательские таблицы стилей так, чтобы можно было сохранить запланированный дизайн, но иногда у пользователей есть веские причины для переопределения стилей веб-разработчика, как упомянуто выше </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> это может быть достигнуто с помощью использования</span></span> <code>!important</code> <span class="tlid-translation translation" lang="ru"><span title="">в их правилах.</span></span></p> + +<h2 id="Проверьте_ваши_навыки"><span class="tlid-translation translation" lang="ru"><span title="">Проверьте ваши навыки</span></span></h2> + +<p>Мы охватили много тем в этой статье. А вы смогли запомнить наиболее важную информацию? Можете пройти несколько дополнительных тестов для того чтобы убедиться в том, что вы усвоили эту информацию, прежде чем пойдёте дальше — смотрите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4_%D0%B7%D0%B0%D0%B4%D0%B0%D1%87%D0%B8">Test your skills: the Cascade</a>.</p> + +<h2 id="Что_дальше">Что дальше?</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Если вы поняли большую часть этой статьи,</span></span><span class="tlid-translation translation" lang="ru"><span title=""> отлично </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> вы начали знакомиться с фундаментальными механизмами CSS.</span> <span title="">Далее мы рассмотрим селекторы подробно.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Если вы не до конца поняли каскад, специфичность и наследование, не волнуйтесь!</span> <span title="">Это, безусловно, самая сложная вещь из тех, что мы до сих пор изучали в курсе, и даже профессиональные веб-разработчики иногда считают её коварной.</span> <span title="">Мы советуем вам вернуться к этой статье несколько раз в ходе изучения курса и продолжать обдумывать эту тему.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Обратитесь сюда, если вы столкнетесь со странными проблемами, когда стили применяются не так, как вы ожидаете.</span> <span title="">Это может быть проблемой специфичности.</span></span></p> + +<p>{{NextMenu("Learn/CSS/Building_blocks/Selectors", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B">Селекторы CSS</a> + <ul> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Type_Class_and_ID_Selectors">Селекторы типа, класса и ID</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Attribute_selectors">Селекторы атрибута</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">Псевдоклассы и псевдоэлементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Combinators">Комбинаторы</a></li> + </ul> + </li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/The_box_model">Модель коробки (The box model)</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Фон и границы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Обработка разных направлений текста</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Overflowing_content">Переполнение содержимого</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Values_and_units">Значения и единицы измерения</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Изменение размеров в CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Элементы изображений, форм и медиа-элементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Styling_tables">Стилизация таблиц</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Organizing">Организация вашей CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/debugging_css/index.html b/files/ru/learn/css/building_blocks/debugging_css/index.html new file mode 100644 index 0000000000..1e78277f4b --- /dev/null +++ b/files/ru/learn/css/building_blocks/debugging_css/index.html @@ -0,0 +1,200 @@ +--- +title: Отладка CSS +slug: Learn/CSS/Building_blocks/Debugging_CSS +translation_of: Learn/CSS/Building_blocks/Debugging_CSS +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Styling_tables", "Learn/CSS/Building_blocks/Organizing", "Learn/CSS/Building_blocks")}}</div> + +<p>Порой, при написании CSS, вы будете сталкиваться с проблемой, при которой будет казаться, что CSS не делает того, чего вы оживаете от него. <span class="tlid-translation translation" lang="ru"><span title="">Возможно, вы считаете, что определенный селектор должен соответствовать элементу, но ничего не происходит, или поле имеет размер, отличный от ожидаемого.</span></span> Эта статья поможет вам с тем, как отладить CSS проблемы и покажет вам как DevTools (инструменты разработчика), включенные во все современные браузеры, могут помочь разобраться с тем, что происходит.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Basic computer literacy, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">basic software installed</a>, basic knowledge of <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">working with files</a>, HTML basics (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), and an idea of how CSS works (study <a href="/en-US/docs/Learn/CSS/First_steps">CSS first steps</a>.)</td> + </tr> + <tr> + <th scope="row">Задачи:</th> + <td> + <p>Изучить основы того, что такое DevTools и как выполнять простую инспекцию и редактирование CSS.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Как_получить_доступ_к_DevTools_браузера">Как получить доступ к DevTools браузера</h2> + +<p>Статья <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools</a> это обновленное руководство объясняющее как получить доступ к инструментам разных браузеров и платформ. Хотя вы можете выбрать в основном разрабатывать в конкретном браузере и поэтому инструменты, включенные в этот браузер, будут вам знакомы больше всего, стоит знать, как получать доступ к инструментам и в других браузерах. Это поможет вам если вы наблюдаете разное отображение среди разных браузеров.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы также обнаружите, что браузеры фокусировались на различных областях при создании своих DevTools.</span></span> Например в Firefox существует несколько замечательных инструментов для визуальной работы с CSS Layout (разметкой), позволяющих вам проводить инспекцию и править <a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts">Grid Layouts</a>, <a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_Flexbox_layouts">Flexbox</a>, и <a href="/en-US/docs/Tools/Page_Inspector/How_to/Edit_CSS_shapes">Shapes</a>. Тем не менее, все другие браузеры имеют схожие фундаментальные инструменты, например для инспекции свойств и значений примененных к элементам на вашей странице и для выполнения изменений к ним в редакторе.</p> + +<p>В этом уроке мы рассмотрим некоторые полезные функции Firefox DevTools для работы с CSS. Для того чтобы сделать это я буду использовать <a href="https://mdn.github.io/css-examples/learn/inspecting/inspecting.html">файл примера</a>. Загрузите его в новой вкладке если хотите следовать и откройте ваш DevTools как описано в статье, ссылка на которую дана выше.</p> + +<h2 id="DOM_vs_View_Source">DOM vs View Source</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">То, что может сбить с толку новичков в DevTools, </span></span>— <span class="tlid-translation translation" lang="ru"><span title=""> это разница между тем, что вы видите когда</span></span> <a href="/en-US/docs/Tools/View_source">просматриваете источник</a> веб-страницы или смотрите на HTML файл который поместили на сервер и то что вы видите на <a href="/en-US/docs/Tools/Page_Inspector/UI_Tour#HTML_pane">HTML панели</a> DevTools. Хотя это выглядит примерно так же, как то, что вы видите через View Source, существуют некоторые отличия.</p> + +<p>В визуализированном DOM браузер мог скорректировать некоторый плохо-написанный HTML за вас. Если вы неправильно закрыли элемент, например открывали <code><h2></code>, но закрыли <code></h3></code>, браузер поймет, что вы хотели сделать и HTML в DOM будет правильно закрывать <code><h2></code> с <code></h2></code>. Браузер также нормализует весь HTML,а DOM также покажет любые изменения сделанные через JavaScript.</p> + +<p>View Source же для сравнения — это <span class="tlid-translation translation" lang="ru"><span title="">просто исходный код HTML, хранящийся на сервере. </span></span><a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_and_edit_HTML#HTML_tree">HTML дерево</a> в вашем DevTools показывает, <span class="tlid-translation translation" lang="ru"><span title="">что именно браузер отображает в любой момент времени, что дает вам представление от том, что действительно происходит.</span></span></p> + +<h2 id="Инспекция_примененного_CSS">Инспекция примененного CSS</h2> + +<p>Выбирать элемент на вашей странице можно либо правым/ctrl-кликом по нему и выбрав <em>Inspect</em>, либо выбрав его из дерева HTML в левой панели DevTools. Попробуйте выбрать элемент с классом <code>box1</code>; это первый элемент на странице с блоком, ограниченным рамками вокруг него.</p> + +<p><img alt="The example page for this tutorial with DevTools open." src="https://mdn.mozillademos.org/files/16606/inspecting1.png" style="border-style: solid; border-width: 1px; height: 1527px; width: 2278px;"></p> + +<p>Если вы посмотрите на <a href="/en-US/docs/Tools/Page_Inspector/UI_Tour#Rules_view">Rules view</a> справа от вашего HTML, вы должны увидеть свойства и значения CSS примененные к элементу. Вы увидите правила, напрямую примененные к классу <code>box1</code> и также CSS который наследуется блоком от предков, в этом случае от <code><body></code>. Это полезно в случае, если вы видите, что применяется какой-либо CSS, который вы не ожидали. Вполне возможно, что он наследуется от родительского элемента и вам необходимо добавить правило, чтобы переписать его в контексте этого элемента.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Также полезна возможность расширения (развертывания) свойств коротких записей.</span></span> В нашем примере используется короткая запись <code>margin</code>.</p> + +<p><strong>Кликните по маленькой стрелке для того, чтобы развернуть вид, показывающий полную запись различных свойств и значений.</strong></p> + +<p><strong>Вы можете переключать значения в Rules view в положение включено или выключено если эта панель активна — <span class="tlid-translation translation" lang="ru"><span title="">если навести на нее курсор мыши, появятся флажки</span></span>. <span class="tlid-translation translation" lang="ru"><span title="">Снимите флажок правила, например, border-radius, и CSS перестанет применяться.</span></span></strong></p> + +<p>Вы можете использовать это чтобы делать сравнения по типу A/B, принимая решение если что-то выглядит лучше с примененным правилом или нет, а также это помогает в отладке — например если layout не в порядке и вы пытаетесь разобраться какое свойство является причиной проблемы.</p> + +<h2 id="Редактирование_значений">Редактирование значений</h2> + +<p>В дополнение к включению и выключению свойств, вы можете редактировать их значения. Возможно, вам захочется посмотреть будет ли другой цвет выглядеть лучше или захотите настроить размер чего-либо. DevTools поможет вам сэкономить кучу времени редактируя таблицу стиля и перезагружая страницу.</p> + +<p><strong>Выбрав <code>box1</code>, кликните на образчик (маленький цветной круг) который показывает цвет, примененный к границе. Откроется панель выбора цвета и сможете попробовать некоторые другие цвета; это действие обновится на странице в режиме реального времени. </strong> <strong><span class="tlid-translation translation" lang="ru"><span title="">Аналогичным образом вы можете изменить ширину или стиль границ.</span></span></strong></p> + +<p><img alt="DevTools Styles Panel with a color picker open." src="https://mdn.mozillademos.org/files/16607/inspecting2-color-picker.png" style="border-style: solid; border-width: 1px; height: 1173px; width: 2275px;"></p> + +<h2 id="Добавление_нового_свойства">Добавление нового свойства</h2> + +<p>Используя DevTools вы можете добавлять новые свойства. Возможно, вы осознали, что не хотите, чтобы ваш блок наследовал размер шрифта элементов <code><body></code>, а хотите установить его собственный конкретный размер. Вы можете попробовать это в DevTools до того, как внесете изменения в ваше CSS файл.</p> + +<p><strong>Вы можете кликнуть по закрывающей фигурной скобке в правиле чтобы начать вводить новое объявление в нем, с этого момента вы можете начинать вводить новое свойство и DevTools покажет список автозаполнения подходящих свойств. Выбрав <code>font-size</code>, вводите значение, которое хотите попробовать. Вы также можете кликнуть на кнопку + чтобы добавить дополнительное правило с тем же селектором и добавить ваши новые правила туда.</strong></p> + +<p><img alt="The DevTools Panel, adding a new property to the rules, with the autocomplete for font- open" src="https://mdn.mozillademos.org/files/16608/inspecting3-font-size.png" style="border-style: solid; border-width: 1px; height: 956px; width: 2275px;"></p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Также существуют другие полезные функции в Rules view, например объявления с не валидными значениями зачеркнуты. Вы можете узнать больше в <a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_and_edit_CSS">Examine and edit CSS</a>.</p> +</div> + +<h2 id="Понимание_модели_блоков">Понимание модели блоков</h2> + +<p>В предыдущем уроке мы обсудили <a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">модель блоков</a> и <span class="tlid-translation translation" lang="ru"><span title="">тот факт, что у нас есть альтернативная модель блоков, которая изменяет способ расчета размера элементов основываясь на размере который вы им задаете, плюс </span></span>padding и границы. DevTools может действительно помочь вам понять, как вычисляется размер элемента.</p> + +<p><a href="/en-US/docs/Tools/Page_Inspector/UI_Tour#Layout_view">Layout view</a> показывает вам диаграмму блочной модели выбранного элемента, вместе с описанием свойств и значений, которые изменяют способ расположения элемента. Это включает описание свойств, которые вы могли и не использовать напрямую к элементу, но которые имеют набор начальных значений.</p> + +<p>В этой панели одним из детальных свойств является свойство <code>box-sizing</code>, которое контролирует какую блочную модель использует элемент.</p> + +<p><strong>Сравните два блока с классами <code>box1</code> и <code>box2</code>. Они оба имеют одинаковую ширину (400px) примененную к ним, однако <code>box1</code> визуально шире. В layout panel вы можете увидеть, что он использует <code>content-box</code>. Это значение, которое принимает размер, который вы даете элементу и затем добавляет padding </strong><strong>и ширину границ.</strong></p> + +<p>Элемент с классом <code>box2</code> использует <code>border-box</code>, поэтому здесь padding и граница вычтены из размера, который вы дали элементу. <span class="tlid-translation translation" lang="ru"><span title="">Это означает, что пространство, занимаемое на странице блоком, соответствует указанному вами размеру </span></span>— в нашем случае <code>width: 400px</code>.</p> + +<p><img alt="The Layout section of the DevTools" src="https://mdn.mozillademos.org/files/16609/inspecting4-box-model.png" style="border-style: solid; border-width: 1px; height: 1532px; width: 2275px;"></p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Узнать больше на <a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_and_edit_the_box_model">Examining and Inspecting the Box Model</a>.</p> +</div> + +<h2 id="Решение_проблем_специфичности">Решение проблем специфичности</h2> + +<p>Порой во время разработки, в частности когда вам нужно отредактировать CSS на существующем сайте вы, вы столкнетесь с трудностями применения некоторого CSS. Вне зависимости от того, что вы делаете, кажется, что элемент просто не реагирует на CSS. Что же обычно происходит в таких ситуациях - это то, что более специфичный селектор переопределяет ваши изменения и в таких случаях DevTools действительно поможет вам.</p> + +<p>В нашем примере два слова обернуты в элемент <code><em></code>. Один отображается оранжевым, а второй ярко-розовым. В CSS мы применили:</p> + +<pre class="brush: css">em { + color: hotpink; + font-weight: bold; +}</pre> + +<p>Кроме того в таблице стилей есть правило с селектором <code>.special</code>:</p> + +<pre class="brush: css">.special { + color: orange; +}</pre> + +<p>Как вы помните из урока <a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">каскад и наследование</a> где мы обсуждали специфичность, селекторы классов являются более специфичными чем селекторы элементов, и поэтому это то значение которое применяется. DevTools может помочь вам найти такие проблемы, особенно если информация закопана где-то в дебрях огромной таблицы стилей.</p> + +<p><strong>Проведите инспекцию <code><em></code> с классом <code>.special</code> и DevTools покажет вам что оранжевый это цвет который применяется, а также отобразит вам свойство <code>color</code> примененное к em зачеркнутым. Теперь вы можете видеть, что класс переопределяет селектор элемента. </strong></p> + +<p><img alt="Selecting an em and looking at DevTools to see what is over-riding the color." src="https://mdn.mozillademos.org/files/16610/inspecting5-specificity.png" style="border-style: solid; border-width: 1px; height: 1161px; width: 2275px;"></p> + +<h2 id="Узнайте_больше_о_Firefox_DevTools">Узнайте больше о Firefox DevTools</h2> + +<p>На MDN имеется много информации о Firefox DevTools. <span class="tlid-translation translation" lang="ru"><span title="">Взгляните на основной </span></span><a href="/en-US/docs/Tools">раздел DevTools</a>, а больше деталей о вещах которые коротко рассмотрели в этом уроке смотрите <a href="/en-US/docs/Tools/Page_Inspector#How_to">The How To Guides</a>.</p> + +<h2 id="Отладка_проблем_в_CSS">Отладка проблем в CSS</h2> + +<p>DevTools может помочь при решении проблем CSS, итак, когда вы окажетесь в ситуации, где CSS ведет себя не так, как вы ожидаете, как же вам следует решать эту проблему? Следующие шаги должны помочь.</p> + +<h3 id="Сделайте_шаг_назад">Сделайте шаг назад</h3> + +<p>Любая проблема кодирования может быть неприятной, особенно проблемы CSS, потому что зачастую вы не получаете каких-либо сообщений об ошибках чтобы найти решение в интернете. Если вы начинаете разочаровываться оторвитесь от проблемы на время — прогуляйтесь, попейте, пообщайтесь с коллегами или займите себя чем-нибудь другим на время. Иногда решение появляется магическим образом, когда вы перестаете думать об этой проблеме, а даже если нет, работать над ней гораздо проще, когда вы чувствуете себя отдохнувшими.</p> + +<h3 id="Валидны_ли_ваши_HTML_и_CSS">Валидны ли ваши HTML и CSS?</h3> + +<p>Браузеры ожидают, что CSS и HTML написаны корректно, однако в это же время браузеры очень снисходительны и сделают все чтобы отобразить вашу веб-страницу даже если у вас есть ошибки в разметке и таблице стилей. Если у вас есть ошибки в коде, то браузеру нужно угадать что вы имели в виду, и он может принять решение не такое какое было у вас в голове. И дополнительно, два разных браузера могут решать проблему двумя разными способами. Поэтому хорошим первым шагом является запуск вашего HTML и CSS в валидаторе чтобы выявить и исправить ошибки.</p> + +<ul> + <li><a href="https://jigsaw.w3.org/css-validator/">CSS Validator</a></li> + <li><a href="https://validator.w3.org/">HTML validator</a></li> +</ul> + +<h3 id="Поддерживаются_ли_свойство_и_значение_браузером_в_котором_вы_тестируете">Поддерживаются ли свойство и значение браузером в котором вы тестируете?</h3> + +<p>Браузеры попросту игнорируют CSS который они не понимают. Если свойство или значение, которое вы используете не поддерживается браузером, в котором вы тестируете, то ничего не "сломается", кроме того, что тот CSS не будет применен. Обычно DevTools выделяет неподдерживаемые свойства и значения каким-либо образом. На скриншоте ниже браузер не поддерживает значение "подсетки" (subgrid) {{cssxref("grid-template-columns")}}.</p> + +<p><img alt="Image of browser DevTools with the grid-template-columns: subgrid crossed out as the subgrid value is not supported." src="https://mdn.mozillademos.org/files/16641/no-support.png" style="height: 397px; width: 1649px;"></p> + +<p>Вы также можете смотреть таблицы совместимости браузеров в конце всех страниц свойств MDN. <span class="tlid-translation translation" lang="ru"><span title="">Они показывают, что браузер поддерживает это свойство, часто "ломается", если есть поддержка только для какого-то использования свойства, и нет для других. Таблица ниже показывает данные совместимости свойства </span></span> {{cssxref("shape-outside")}}.</p> + +<p>{{compat("css.shape-outside")}}</p> + +<h3 id="Не_переопределяется_ли_ваш_CSS_чем-нибудь_еще">Не переопределяется ли ваш CSS чем-нибудь еще?</h3> + +<p>Это тот момент, когда изученная вами информация о специфичности придет вам на помощь. Если у вас имеется что-то более специфичное, что может переписывать то, что вы пытаетесь сделать, то вы можете вступить в очень расстраивающую игру пытаясь выяснить что же именно. Однако, как описано выше, DevTools покажет вам какой CSS применяется, и вы сможете решить, как сделать новый селектор достаточно специфичным чтобы переопределить его.</p> + +<h3 id="Сделайте_сокращенный_контрольный_пример_проблемы">Сделайте <span class="tlid-translation translation" lang="ru"><span title="">сокращенный контрольный пример</span></span> проблемы</h3> + +<p>Если проблема не решена шагами, описанными выше, тогда вам надо будет сделать своего рода расследование. Лучшее что можно сделать в этом случае это создать нечто известное как с<span class="tlid-translation translation" lang="ru"><span title="">окращенный контрольный пример</span></span>. Возможность "уменьшить проблему" — действительно полезный навык. Он поможет вам найти проблемы как в вашем собственном коде, так в коде ваших коллег, а также <span class="tlid-translation translation" lang="ru"><span title="">позволит вам сообщать об ошибках и более эффективно обращаться за помощью.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Сокращенный контрольный пример </span></span>— <span class="tlid-translation translation" lang="ru"><span title="">это пример кода, который демонстрирует проблему самым простым способом с удалением несвязанного окружающего контента и стиля. </span></span> <span class="tlid-translation translation" lang="ru"><span title="">Это часто будет означать удаление проблемного кода из вашего макета (</span></span>layout<span class="tlid-translation translation" lang="ru"><span title="">), чтобы сделать небольшой пример, который показывает только этот код или функцию.</span></span></p> + +<p>Создание сокращенного контрольного примера:</p> + +<ol> + <li>Если ваша разметка генерируется динамически — например через CMS — сделайте статичную версию вывода, которая показывает проблему. Сайты обмена кодами как <a href="https://codepen.io/">CodePen</a> являются полезными для размещения сокращенных контрольных примеров, так как они доступны онлайн, и вы легко можете поделиться с коллегами. Вы можете начать просматривать страницу во View Source и скопировать HTML в CodePen, затем взять релевантный CSS и JavaScript и включить их тоже. После этого вы можете проверить очевидна ли проблема.</li> + <li>Если удаление JavaScript не устраняет проблему, то не включайте JavaScript. Если же удаление JavaScript <em>устраняет</em> проблему, тогда удалите столько JavaScript, сколько сможете, оставляя все что вызывает проблему.</li> + <li>Удалите весь HTML который не влияет на проблему. Удалите компоненты или даже главные элементы макета. Опять же постарайтесь добиться наименьшего количества кода, который все еще показывает проблему.</li> + <li>Удалите весь CSS который не влияет на проблему.</li> +</ol> + +<p>В процессе вы можете обнаружить что причиняет проблему или, хотя бы, сможете включать или выключать ее путем удаления чего-то конкретного. Стоит добавлять какие-то комментарии к вашему коду по ходу изучения вещей. Если вам надо попросить помощи, то они покажут человеку, помогающему вам что вы уже пытались сделать. <span class="tlid-translation translation" lang="ru"><span title="">Это может дать вам достаточно информации для поиска возможных проблем и обходных путей.</span></span></p> + +<p>If you are still struggling to fix the problem then having a reduced test case gives you something to ask for help with, by posting to a forum, or showing to a co-worker. You are much more likely to get help if you can show that you have done the work of reducing the problem and identifying exactly where it happens, before asking for help. A more experienced developer might be able to quickly spot the problem and point you in the right direction, and even if not, your reduced test case will enable them to have a quick look and hopefully be able to offer at least some help.</p> + +<p>In the instance that your problem is actually a bug in a browser, then a reduced test case can also be used to file a bug report with the relevant browser vendor (e.g. on Mozilla's <a href="https://bugzilla.mozilla.org">bugzilla site</a>).</p> + +<p>As you become more experienced with CSS, you will find that you get faster at figuring out issues. However even the most experienced of us sometimes find ourselves wondering what on earth is going on. Taking a methodical approach, making a reduced test case, and explaining the issue to someone else will usually result in a fix being found.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Styling_tables", "Learn/CSS/Building_blocks/Organizing", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS selectors</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class, and ID selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Combinators</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Backgrounds and borders</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Handling different text directions</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">Overflowing content</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">Values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Images, media, and form elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">Styling tables</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">Organizing your CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/handling_different_text_directions/index.html b/files/ru/learn/css/building_blocks/handling_different_text_directions/index.html new file mode 100644 index 0000000000..708c8a9d39 --- /dev/null +++ b/files/ru/learn/css/building_blocks/handling_different_text_directions/index.html @@ -0,0 +1,147 @@ +--- +title: Изменение направления текста +slug: Learn/CSS/Building_blocks/Handling_different_text_directions +translation_of: Learn/CSS/Building_blocks/Handling_different_text_directions +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Backgrounds_and_borders", "Learn/CSS/Building_blocks/Overflowing_content", "Learn/CSS/Building_blocks")}}</div> + +<p>Many of the properties and values that we have encountered so far in our CSS learning have been tied to the physical dimensions of our screen. We create borders on the top, right, bottom, and left of a box, for example. These physical dimensions map very neatly to content that is viewed horizontally, and by default the web tends to support left-to-right languages (e.g. English or French) better than right-to-left languages (such as Arabic).</p> + +<p>In recent years however, CSS has evolved in order to better support different directionality of content, including right-to-left but also top-to-bottom content (such as Japanese) — these different directionalities are called <strong>writing modes</strong>. As you progress in your study and begin to work with layout, an understanding of writing modes will be very helpful to you, therefore we will introduce them now.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">basic software installed</a>, basic knowledge of <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">working with files</a>, HTML basics (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), and an idea of how CSS works (study <a href="/en-US/docs/Learn/CSS/First_steps">CSS first steps</a>.)</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand the importance of writing modes to modern CSS.</td> + </tr> + </tbody> +</table> + +<h2 id="What_are_writing_modes">What are writing modes?</h2> + +<p>A writing mode in CSS refers to whether the text is running horizontally or vertically. The {{cssxref("writing-mode")}} property lets us switch from one writing mode to another. You don't need to be working in a language which uses a vertical writing mode to want to do this — you could also change the writing mode of parts of your layout for creative purposes.</p> + +<p>In the example below we have a heading displayed using <code>writing-mode: vertical-rl</code>. The text now runs vertically. Vertical text is common in graphic design, and can be a way to add a more interesting look and feel to your web design.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/simple-vertical.html", '100%', 800)}}</p> + +<p>The three possible values for the <code><a href="/en-US/docs/Web/CSS/writing-mode">writing-mode</a></code> property are:</p> + +<ul> + <li><code>horizontal-tb</code>: Top-to-bottom block flow direction. Sentences run horizontally.</li> + <li><code>vertical-rl</code>: Right-to-left block flow direction. Sentences run vertically.</li> + <li><code>vertical-lr</code>: Left-to-right block flow direction. Sentences run vertically.</li> +</ul> + +<p>So the <code>writing-mode</code> property is in reality setting the direction in which block-level elements are displayed on the page — either from top-to-bottom, right-to-left, or left-to-right. This then dictates the direction text flows in sentences.</p> + +<h2 id="Writing_modes_and_block_and_inline_layout">Writing modes and block and inline layout</h2> + +<p>We have already discussed <a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model#Block_and_inline_boxes">block and inline layout</a>, and the fact that some things display as block elements and others as inline elements. As we have seen described above, block and inline is tied to the writing mode of the document, and not the physical screen. Blocks are only displayed from the top to the bottom of the page if you are using a writing mode that displays text horizontally, such as English.</p> + +<p>If we look at an example this will become clearer. In this next example I have two boxes that contain a heading and a paragraph. The first uses <code>writing-mode: horizontal-tb</code>, a writing mode that is written horizontally and from the top of the page to the bottom. The second uses <code>writing-mode: vertical-rl</code>; this is a writing mode that is written vertically and from right to left.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/block-inline.html", '100%', 1200)}}</p> + +<p>When we switch the writing mode, we are changing which direction is block and which is inline. In a <code>horizontal-tb</code> writing mode the block direction runs from top to bottom; in a <code>vertical-rl</code> writing mode the block direction runs right-to-left horizontally. So the <strong>block dimension</strong> is always the direction blocks are displayed on the page in the writing mode in use. The <strong>inline dimension</strong> is always the direction a sentence flows.</p> + +<p>This figure shows the two dimensions when in a horizontal writing mode.<img alt="Showing the block and inline axis for a horizontal writing mode." src="https://mdn.mozillademos.org/files/16574/horizontal-tb.png" style="height: 353px; width: 634px;"></p> + +<p>This figure shows the two dimensions in a vertical writing mode.</p> + +<p><img alt="Showing the block and inline axis for a vertical writing mode." src="https://mdn.mozillademos.org/files/16575/vertical.png" style="height: 472px; width: 406px;"></p> + +<p>Once you start to look at CSS layout, and in particular the newer layout methods, this idea of block and inline becomes very important. We will revisit it later on.</p> + +<h3 id="Direction">Direction</h3> + +<p>In addition to writing mode we also have text direction. As mentioned above, some languages such as Arabic are written horizontally, but right-to-left. This is not something you are likely to use in a creative sense — if you simply want to line something up on the right there are other ways to do so — however it is important to understand this as part of the nature of CSS. The web is not just for languages that are displayed left-to-right!</p> + +<p>Due to the fact that writing mode and direction of text can change, newer CSS layout methods do not refer to left and right, and top and bottom. Instead they will talk about <em>start</em> and <em>end</em> along with this idea of inline and block. Don't worry too much about that right now, but keep these ideas in mind as you start to look at layout; you will find it really helpful in your understanding of CSS.</p> + +<h2 id="Logical_properties_and_values">Logical properties and values</h2> + +<p>The reason to talk about writing modes and direction at this point in your learning however, is because of the fact we have already looked at a lot of properties which are tied to the physical dimensions of the screen, and make most sense when in a horizontal writing mode.</p> + +<p>Let's take a look at our two boxes again — one with a <code>horizontal-tb</code> writing mode and one with <code>vertical-rl</code>. I have given both of these boxes a {{cssxref("width")}}. You can see that when the box is in the vertical writing mode, it still has a width, and this is causing the text to overflow.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/width.html", '100%', 1200)}}</p> + +<p>What we really want in this scenario, is to essentially swap height and width along with the writing mode. When we're in a vertical writing mode we want the box to expand in the block dimension just like it does in the horizontal mode.</p> + +<p>To make this easier, CSS has recently developed a set of mapped properties. These essentially replace physical properties — things like <code>width</code> and <code>height</code> — with <strong>logical</strong>, or <strong>flow relative</strong> versions.</p> + +<p>The property mapped to <code>width</code> when in a horizontal writing mode is called {{cssxref("inline-size")}} — it refers to the size in the inline dimension. The property for <code>height</code> is named {{cssxref("block-size")}} and is the size in the block dimension. You can see how this works in the example below where we have replaced <code>width</code> with <code>inline-size</code>.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/inline-size.html", '100%', 1200)}}</p> + +<h3 id="Logical_margin_border_and_padding_properties">Logical margin, border, and padding properties</h3> + +<p>In the last two lessons we have learned about the CSS box model, and CSS borders. In the margin, border, and padding properties you will find many instances of physical properties, for example {{cssxref("margin-top")}}, {{cssxref("padding-left")}}, and {{cssxref("border-bottom")}}. In the same way that we have mappings for width and height there are mappings for these properties.</p> + +<p>The <code>margin-top</code> property is mapped to {{cssxref("margin-block-start")}} — this will always refer to the margin at the start of the block dimension.</p> + +<p>The {{cssxref("padding-left")}} property maps to {{cssxref("padding-inline-start")}}, the padding that is applied to the start of the inline direction. This will be where sentences start in that writing mode. The {{cssxref("border-bottom")}} property maps to {{cssxref("border-block-end")}}, which is the border at the end of the block dimension.</p> + +<p>You can see a comparison between physical and logical properties below.</p> + +<p><strong>If you change the writing mode of the boxes by switching the <code>writing-mode</code> property on <code>.box</code> to <code>vertical-rl</code>, you will see how the physical properties stay tied to their physical direction, whereas the logical properties switch with the writing mode.</strong></p> + +<p><strong>You can also see that the {{htmlelement("h2")}} has a black <code>border-bottom</code>. Can you work out how to make that bottom border always go below the text in both writing modes?</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/logical-mbp.html", '100%', 1200)}}</p> + +<p>There are a huge number of properties when you consider all of the individual border longhands, and you can see all of the mapped properties on the MDN page for <a href="/en-US/docs/Web/CSS/CSS_Logical_Properties">Logical Properties and Values</a>.</p> + +<h3 id="Logical_values">Logical values</h3> + +<p>We have so far looked at logical property names. There are also some properties that take physical values of <code>top</code>, <code>right</code>, <code>bottom</code>, and <code>left</code>. These values also have mappings, to logical values — <code>block-start</code>, <code>inline-end</code>, <code>block-end</code>, and <code>inline-start</code>.</p> + +<p>For example, you can float an image left to cause text to wrap round the image. You could replace <code>left</code> with <code>inline-start</code> as shown in the example below.</p> + +<p><strong>Change the writing mode on this example to <code>vertical-rl</code> to see what happens to the image. Change <code>inline-start</code> to <code>inline-end</code> to change the float.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/float.html", '100%', 1200)}}</p> + +<p>Here we are also using logical margin values to ensure the margin is in the correct place no matter what the writing mode is.</p> + +<h3 id="Should_you_use_physical_or_logical_properties">Should you use physical or logical properties?</h3> + +<p>The logical properties and values are newer than their physical equivalents, and therefore have only recently been implemented in browsers. You can check any property page on MDN to see how far back the browser support goes. If you are not using multiple writing modes then for now you might prefer to use the physical versions. However, ultimately we expect that people will transition to the logical versions for most things, as they make a lot of sense once you start also dealing with layout methods such as flexbox and grid.</p> + +<h2 id="Summary">Summary</h2> + +<p>The concepts explained in this lesson are becoming increasingly important in CSS. An understanding of the block and inline direction — and how text flow changes with a change in writing mode — will be very useful going forward. It will help you in understanding CSS even if you never use a writing mode other than a horizontal one.</p> + +<p>In the next module we will take a good look at overflow in CSS.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Backgrounds_and_borders", "Learn/CSS/Building_blocks/Overflowing_content", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS selectors</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class, and ID selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Combinators</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Backgrounds and borders</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Handling different text directions</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">Overflowing content</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">Values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Images, media, and form elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">Styling tables</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">Organizing your CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/images_media_form_elements/index.html b/files/ru/learn/css/building_blocks/images_media_form_elements/index.html new file mode 100644 index 0000000000..481cd28b58 --- /dev/null +++ b/files/ru/learn/css/building_blocks/images_media_form_elements/index.html @@ -0,0 +1,193 @@ +--- +title: 'Элементы изображений, форм и медиа-элементы' +slug: Learn/CSS/Building_blocks/Images_media_form_elements +translation_of: Learn/CSS/Building_blocks/Images_media_form_elements +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Sizing_items_in_CSS", "Learn/CSS/Building_blocks/Styling_tables", "Learn/CSS/Building_blocks")}}</div> + +<p>В этом уроке мы рассмотрим, как обрабатываются определенные специальные элементы в CSS. Элементы изображений, других медиа и форм ведут себя иначе при их стилизации в CSS чем обычные блоки. Понимание того, что возможно, а что нет спасут вас от лишних разочарований и этот урок прольет свет на некоторые из этих основных вещей, которые вам нужно знать.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">basic software installed</a>, basic knowledge of <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">working with files</a>, HTML basics (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), and an idea of how CSS works (study <a href="/en-US/docs/Learn/CSS/First_steps">CSS first steps</a>.)</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand the way that some elements behave unusually when styled with CSS.</td> + </tr> + </tbody> +</table> + +<h2 id="Замещаемые_элементы">Замещаемые элементы</h2> + +<p>Изображения и видео описываются как <strong><a href="/en-US/docs/Web/CSS/Replaced_element">Замещаемые элементы</a></strong>. Это значит, что CSS не может влиять на внутреннюю планировку этих элементов — только на их позицию на странице среди других элементов. Однако, как мы увидим, существуют различные вещи, которые CSS может сделать с изображением.</p> + +<p>Конкретные замещаемые элементы, такие как изображения и видео, можно также описать, как элементы имеющие <strong>соотношение сторон</strong>. Это значит, что такой элемент имеет размер как по горизонтали (x) так и по вертикали (y) и будет отображаться используя "родные" размеры файла по умолчанию.</p> + +<h2 id="Размер_изображений_калибровка">Размер изображений (калибровка)</h2> + +<p>Как вы уже знаете из этих уроков, всё в CSS генерирует блоки. Если вы поместите файл изображения внутрь блока, который больше или меньше исходного размера файла изображения в обоих направлениях, то он отобразиться либо в меньшем размере чем блок, либо перекроет его. Вам нужно принять решение с тем, что произойдет с перекрытием.</p> + +<p>В примере ниже у нас два блока, оба имеют размер по 200px:</p> + +<ul> + <li>Один содержит изображение, которое 200px — оно меньше, чем блок и не растягивается что бы заполнить его.</li> + <li>Второй больше 200px и перекрывает блок.</li> +</ul> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/size.html", '100%', 1000)}}</p> + +<p>Так что же мы можем сделать с проблемой перекрывания?</p> + +<p>Как мы учили в <a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">нашем предыдущем уроке</a>, распространенная техника — это сделать {{cssxref("max-width")}} изображения - 100%. <span class="tlid-translation translation" lang="ru"><span title="">Это позволит уменьшить размер изображения по отношению к блоку, но не увеличит его.</span></span> Такой метод будет работать и с другими замещаемыми элементами такими как <code><a href="/en-US/docs/Web/HTML/Element/video"><video></a></code> или <code><a href="/en-US/docs/Web/HTML/Element/iframe"><iframe></a></code>.</p> + +<p><strong>Попробуйте добавить <code>max-width: 100%</code> к элементу <code><img></code> в примере выше. Вы увидите, что меньшее изображение останется неизмененным, а большее изображение станет меньше, чтобы заполнить блок.</strong></p> + +<p>Вы можете сделать другие варианты изображений внутри контейнеров. Например, вы можете захотеть дать изображению такие размеры, чтоб оно полностью покрывало блок.</p> + +<p>Здесь вам может помочь свойство {{cssxref("object-fit")}}. Используя <code>object-fit</code>, можно определять размеры замещаемого элемента для заполнения блока различными способами.</p> + +<p>Ниже мы использовали значение <code>cover</code>, которое уменьшает изображение, сохраняя соотношение сторон так, что он аккуратно заполняет блок. Поскольку соотношения сторон сохраняются, некоторые части изображения будут обрезаны блоком.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/object-fit.html", '100%', 1000)}}</p> + +<p>Если мы используем <code>contain</code> в качестве значения, изображение будет уменьшаться до тех пор, пока не станет достаточно маленьким чтобы заполнить блок. Это приведет к "почтовой упаковке", если оно не будет иметь такого же соотношения сторон, как блок.</p> + +<p>Вы также можете попробовать значение <code>fill</code>, которое будет заполнять блок, но при этом не сохранять соотношение сторон.</p> + +<h2 id="Замещаемые_элемнты_в_верстке">Замещаемые элемнты в верстке</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">При использовании различных методов верстки CSS на замещаемых элементах, вы можете обнаружить, что они ведут себя немного иначе, чем другие элементы. Например</span></span>, во flex или grid layout элементы растягиваются по умолчанию чтобы заполнить всю площадь. Изображения растягиваться не будут, вместо этого они будут выравнены на начало площади flex- или grig-контейнера.</p> + +<p>Вы можете увидеть, как это происходит в примере ниже, где мы имеем grid-контейнер из двух столбцов и двух строк, который содержит 4 объекта. Все <code><div></code> элементы имеют цвет фона и растягиваются чтобы заполнить строки и столбцы. Однако, изображение не растягивается.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/layout.html", '100%', 1000)}}</p> + +<p>Если вы изучаете эти уроки по порядку, тогда вы, возможно, еще не рассматривали layout. Просто держите в уме, что замещаемые элементы, становясь частью grid- или flex-разметки, ведут себя иначе по умолчанию, главным образом, чтобы избежать их странного растяжения по разметке.</p> + +<p>Для того чтобы заставить изображение растянуться чтобы заполнить grid-ячейку, вы должны сделать что-то наподобие следующего:</p> + +<pre class="brush: css">img { + width: 100%; + height: 100%; +}</pre> + +<p>Это, однако, растянет изображение, и скорее всего это не то чего бы вам хотелось делать.</p> + +<h2 id="Элементы_форм">Элементы форм</h2> + +<p>Элементы форм могут быть сложной проблемой когда дело касается их стилизации в CSS, и <a href="/en-US/docs/Learn/Forms">Web Forms module</a> содержит детальные руководства по хитрым аспектам стилизации элементов форм, которые я не буду представлять здесь в полном объеме. <span class="tlid-translation translation" lang="ru"><span title="">В этом разделе статьи стоит выделить несколько ключевых моментов.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Многие элементы управления форм добавляются на вашу страницу с помощью элемента</span></span> <code><a href="/en-US/docs/Web/HTML/Element/input"><input></a></code> — <span class="tlid-translation translation" lang="ru"><span title="">он определяет простые поля формы, такие как ввод текста, и более сложные поля, добавленные в HTML5, такие как средства выбора цвета и даты. Существуют некоторые дополнительные элементы, такие как </span></span><code><a href="/en-US/docs/Web/HTML/Element/textarea"><textarea></a></code> для ввода многострочного текста, а также элементы которые содержали части маркировки форм, такие как <code><a href="/en-US/docs/Web/HTML/Element/fieldset"><fieldset></a></code> и <code><a href="/en-US/docs/Web/HTML/Element/legend"><legend></a></code>.</p> + +<p>HTML5 также содержит атрибуты, которые позволяют веб-разработчикам указывать какие поля являются обязательными и даже тип контента, который необходимо вводить. Если пользователь вводит неожидаемые данные или оставляет обязательные поля пустыми, браузер может выдать сообщение об ошибке. Разные браузеры <span class="tlid-translation translation" lang="ru"><span title="">несовместимы в том, сколько стилей и настроек они допускают для таких элементов.</span></span></p> + +<h3 id="Стилизация_элементов_ввода_текста">Стилизация элементов ввода текста</h3> + +<p>Элементы, позволяющие вводить текст, такие как <code><input type="text"></code>, конкретные типы вроде <code><input type="email"></code>, и элемент <code><textarea></code>, являются довольно простыми в стилизации и как правило ведут себя также, как и другие блоки на вашей странице. Однако, стилизация по умолчанию таких элементов будет отличаться в зависимости от операционной системы и браузера которые использует пользователь, посещая сайт.</p> + +<p>В примере ниже мы стилизовали несколько вводов текста используя CSS — вы можете увидеть, что такие вещи как borders, margins и padding, все применяются так как вы бы ожидали. Мы используем селекторы атрибутов для выборов различных типов ввода. Попробуйте изменить то, как эти формы выглядят, регулируя границы, добавляя цвет фона полям и изменяя шрифты padding.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/form.html", '100%', 1000)}}</p> + +<div class="blockIndicator warning"> +<p><strong>Важно: </strong> <span class="tlid-translation translation" lang="ru"><span title="">При изменении стиля элементов формы следует соблюдать осторожность, чтобы убедиться, что для пользователя все еще очевидно, что они являются элементами форм. Вы можете создать форму ввода без границ и фона, которая практически неотличима от окружающего контента и это может сделать очень сложно распознаваемой, чтобы заполнить ее.</span></span></p> +</div> + +<p>Как объяснено в уроке <a href="/en-US/docs/Learn/Forms/Styling_web_forms">стилизация форм</a> в части HTML этого курса, <span class="tlid-translation translation" lang="ru"><span title="">многие из более сложных типов ввода определяются операционной системой и не доступны для стилизации. </span></span><span class="tlid-translation translation" lang="ru"><span title="">Поэтому вы всегда должны предполагать, что формы будут выглядеть по-разному для разных пользователей и тестировать сложные формы во многих браузерах.</span></span></p> + +<h3 id="Наследование_и_элементы_форм">Наследование и элементы форм</h3> + +<p>В некоторых браузерах, элементы форм не наследуют стиль шрифтов по умолчанию. Поэтому если вы хотите быть уверенными что ваши поля форм используют шрифт определенный в body или родительском элементе, вы должны добавить это правило в ваш CSS.</p> + +<pre class="brush: css"><code>button, +input, +select, +textarea { + font-family : inherit; + font-size : 100%; +} </code></pre> + +<h3 id="Элементы_форм_и_box-sizing">Элементы форм и box-sizing</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В разных браузерах элементы формы используют разные правила определения размеров блоков для разных виджетов.</span></span> Вы изучали свойство <code>box-sizing</code> в <a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">нашем уроке Блоки в CSS</a> и можете использовать эти знания при стилизации форм для обеспечения единообразия при настройке ширины и высоты элементов форм.</p> + +<p>Для единообразия рекомендуется устанавливать margin и padding на <code>0</code> для всех элементов, а затем добавлять их (margin и padding) при стилизации отдельных элементов.</p> + +<pre class="brush: css"><code>button, +input, +select, +textarea { + box-sizing: border-box; + padding: 0; + margin: 0; +}</code></pre> + +<h3 id="Другие_полезные_настройки">Другие полезные настройки</h3> + +<p>В дополние к правилам отмеченых выше, вы должны также установить <code>overflow: auto</code> для <code><textarea></code> чтобы IE не отображал полосу прокрутки, когда в этом нет необходимости:</p> + +<pre class="brush: css">textarea { + overflow: auto; +}</pre> + +<h3 id="Собираем_все_вместе_в_перезагрузку">Собираем все вместе в "перезагрузку"</h3> + +<p>В качестве последнего шага, мы можем обернуть различные свойства, обсуждаемые<span class="tlid-translation translation" lang="ru"><span title=""> выше, в следующую «форму перезагрузки», чтобы обеспечить согласованную основу для работы. Это включает все элементы упомянутые в последних трех разделах:</span></span></p> + +<pre class="brush: css"><code>button, +input, +select, +textarea { + font-family: inherit; + font-size: 100%; + box-sizing: border-box; + padding: 0; margin: 0; +} + +textarea { + overflow: auto; +} </code></pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Normalizing stylesheets are used by many developers to create a set of baseline styles to use on all projects. Typically these do similar things to those described above, making sure that anything different across browsers is set to a consistent default before you do your own work on the CSS. They are not as important as they once were, as browsers are typically more consistent than in the past. However if you want to take a look at one example, check out <a href="http://necolas.github.io/normalize.css/">Normalize.css</a>, which is a very popular stylesheet used as a base by many projects.</p> +</div> + +<p>Для дополнительной информации по стилизации форм, посмотрите две статьи в разделе HTML этого руководства.</p> + +<ul> + <li><a href="/en-US/docs/Learn/Forms/Styling_web_forms">Styling web forms</a></li> + <li><a href="/en-US/docs/Learn/Forms/Advanced_form_styling">Advanced form styling</a></li> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>This lesson has highlighted some of the differences you will encounter when working with images, media, and other unusual elements in CSS. In the next article we'll look over a few tips you'll find useful when you have to style HTML tables.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Sizing_items_in_CSS", "Learn/CSS/Building_blocks/Styling_tables", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS selectors</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class, and ID selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Combinators</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Backgrounds and borders</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Handling different text directions</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">Overflowing content</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">Values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Images, media, and form elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">Styling tables</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">Organizing your CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/index.html b/files/ru/learn/css/building_blocks/index.html new file mode 100644 index 0000000000..8f071e3f62 --- /dev/null +++ b/files/ru/learn/css/building_blocks/index.html @@ -0,0 +1,80 @@ +--- +title: Устройство CSS +slug: Learn/CSS/Building_blocks +tags: + - Beginner + - CSS + - Landing + - Learn + - Начинающий + - Обучение + - Опции + - Функции + - состоит +translation_of: Learn/CSS/Building_blocks +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Этот модуль — продолжение раздела <a href="/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>: Вы уже знакомы с синтаксисом языка и опробовали основные функции; пришло время углубиться в CSS. В этом модуле рассматриваются каскады и наследование, все доступные типы селекторов, блоков, изменений размеров, фонов, границ, а также отладка и многое другое.</p> + +<p class="summary">Наша цель в этом модуле — обеспечить Вас необходимым набором инструментов для написания хорошего CSS-кода, а также помочь Вам понять необходимую теорию для перехода к особым дисциплинам, таким как <a href="/ru/docs/Learn/CSS/Styling_text">стилизация текста</a> и <a href="/ru/docs/Learn/CSS/CSS_layout">размещение элементов с помощью CSS</a>.</p> + +<h2 id="Необходимые_умения">Необходимые умения</h2> + +<p>Перед изучением этого раздела Вы должны иметь:</p> + +<ol> + <li>Стандартную рабочую среду (<a href="/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установке базового программного обеспечения</a>), а также понимание того, как создавать файлы и работать с ними (<a href="/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a>).</li> + <li>Общее представление о HTML (модуль <a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>).</li> + <li>Общее представление о CSS (модуль <a href="/ru/docs/Learn/CSS/First_steps/Getting_started">Начало работы с CSS</a>).</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Если Вы работаете на компьютере/планшете/другом устройстве, где нет возможности создавать файлы, Вы можете опробовать примеры (большую часть) на таких онлайн-программах, как <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<p>В этом модуле содержатся следующие статьи, в которых рассказывается об основных составляющих языка. По мере обучения Вы встретите упражнения, позволяющие Вам усвоить пройденный материал.</p> + +<dl> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование</a></dt> + <dd>Цель данного урока — углубить Ваше понимание основных концепций CSS — каскадов, спецификаций и наследования, — которые контролируют, как CSS добавляется в HTML и как разрешаются конфликты.</dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы">CSS-селекторы</a></dt> + <dd>Существует широкий выбор CSS-селекторов, позволяющий максимально точно отбирать элементы для стилизации. В этой статье и её подстатьях мы рассмотрим разные типы в мельчайших подробностях и увидим как они работают. Подстатьи по порядку: + <ul> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Type_Class_and_ID_Selectors">Селекторы типа, класса и ID</a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Attribute_selectors">Селекторы атрибутов</a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">Псевдоклассы, псевдоэлементы</a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Combinators">Комбинации селекторов</a></li> + </ul> + </dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/The_box_model">Блоки в CSS</a></dt> + <dd>Всё в CSS имеет форму блока, и понимание блоков позволяет Вам размещать элементы с помощью CSS или согласовывать их друг с другом. В этом уроке мы как следует рассмотрим <em>CSS-блоки.</em></dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Фон и границы</a></dt> + <dd>В этом уроке мы рассмотрим всякие интересные вещи, котроые Вы можете делать благодаря CSS-фонам и границам, — от добавления градиетнов и фоновых изображений до скругления углов, фонов и границ.</dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Изменение направления текста</a></dt> + <dd>Раньше CSS развивался, чтобы лучше поддерживать разные <strong>режимы написания</strong>, включая <em>справа налево</em> или <em>сверху вниз</em> (как в японском языке). Мы рассмотрим их в этой статье.</dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Overflowing_content">Перекрытие содержимого</a></dt> + <dd>В этом уроке мы рассмотрим ещё одну важную концепцию CSS — <strong>overflow</strong>. Переполнение происходит, когда слишком много информации находится в пределах ограниченного блока. В этой статье мы рассмотрим, как это исправить.</dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Values_and_units">Значения свойств CSS</a></dt> + <dd>У каждого CSS-свойства есть значения. В этом уроке мы рассмотрим основные значения и их единицы.</dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Изменение размеров в CSS</a></dt> + <dd>В предыдущих уроках Вы встречались с различными способами изменения размеров элементов с использованием CSS. В этой статье мы собрали разные способы изменить размер через CSS.</dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Элементы изображений, форм и медиа-элементы</a></dt> + <dd>Мы рассмотрим, как некоторые элементы относятся к CSS. Изображения, формы и другие медиа-элементы ведут себя по-другому, когда Вы стилизуете их через CSS. Некоторые функции могут не работать, поэтому в этой статье мы рассмотрим то, что Вам нужно знать про эти элементы.</dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Styling_tables">Стилизация таблиц</a></dt> + <dd>Стилизация HTML таблиц — это не самая гламурная работа в мире, но иногда нам нужно это делать. Эта статья описывает, как сделать, чтобы Ваши HTML-таблицы выглядели хорошо, и некоторые свойства, подробно рассмотренные в предыдущих статьях.</dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS</a></dt> + <dt></dt> + <dd>При написании CSS Вы можете столкнуться с тем, что Ваш CSS-код работает не так, как Вы того хотели. Вы узнаете, как отлаживать CSS и как с помощью инструментов разработчика понять, где неполадка.</dd> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Organizing">Организация CSS-кода</a></dt> + <dd>Как только Вы начнёте работать над большими проектами и таблицами стилей, Вы поймёте, что обслуживать такие таблицы не так-то и легко. В статье мы рассмотрим, как лучше писать CSS, чтобы его было легче обслуживать.</dd> +</dl> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<dl> + <dt><a href="/ru/docs/Learn/CSS/Building_blocks/Advanced_styling_effects">Узконаправленные функции CSS</a></dt> + <dd>В этой статье описаны некоторые хитрости, которые познакомят Вас с такими узкоспециализированными свойствами, как box-shadow, режимы смешивания и фильтры.</dd> +</dl> diff --git a/files/ru/learn/css/building_blocks/organizing/index.html b/files/ru/learn/css/building_blocks/organizing/index.html new file mode 100644 index 0000000000..9c35d136f0 --- /dev/null +++ b/files/ru/learn/css/building_blocks/organizing/index.html @@ -0,0 +1,350 @@ +--- +title: Организация CSS-кода +slug: Learn/CSS/Building_blocks/Organizing +translation_of: Learn/CSS/Building_blocks/Organizing +--- +<div>{{LearnSidebar}}{{PreviousMenu("Learn/CSS/Building_blocks/Debugging_CSS", "Learn/CSS/Building_blocks")}}</div> + +<p>As you start to work on larger stylesheets and big projects you will discover that maintaining a huge CSS file can be challenging. In this article we will take a brief look at some best practices for writing your CSS to make it easily maintainable, and some of the solutions you will find in use by others to help improve maintainability.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">basic software installed</a>, basic knowledge of <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">working with files</a>, HTML basics (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), and an idea of how CSS works (study <a href="/en-US/docs/Learn/CSS/First_steps">CSS first steps</a>.)</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To learn some tips and best practices for organizing stylesheets, and find out about some of the naming conventions and tools in common usage to help with CSS organization and team working.</td> + </tr> + </tbody> +</table> + +<h2 id="Tips_to_keep_your_CSS_tidy">Tips to keep your CSS tidy</h2> + +<p>Here are some general suggestions for ways to keep your stylesheets organised and tidy.</p> + +<h3 id="Does_your_project_have_a_coding_style_guide">Does your project have a coding style guide?</h3> + +<p>If you are working with a team on an existing project, the first thing to check is whether the project has an existing style guide for CSS. The team style guide should always win over your own personal preferences. There often isn't a right or wrong way to do things, but consistency is important.</p> + +<p>For example, have a look at the <a href="/en-US/docs/MDN/Contribute/Guidelines/Code_guidelines/CSS">CSS guidelines for MDN code examples</a>.</p> + +<h3 id="Keep_it_consistent">Keep it consistent</h3> + +<p>If you get to set the rules for the project or are working alone, then the most important thing to do is to keep things consistent. Consistency can be applied in all sorts of ways, such as using the same naming conventions for classes, choosing one method of describing color, or maintaining consistent formatting (for example will you use tabs or spaces to indent your code? If spaces, how many spaces?)</p> + +<p>Having a set of rules you always follow reduces the amount of mental overhead needed when writing CSS, as some of the decisions are already made.</p> + +<h3 id="Formatting_readable_CSS">Formatting readable CSS</h3> + +<p>There are a couple of ways you will see CSS formatted. Some developers put all of the rules onto a single line, like so:</p> + +<pre class="brush: css">.box { background-color: #567895; } +h2 { background-color: black; color: white; }</pre> + +<p>Other developers prefer to break everything onto a new line:</p> + +<pre class="brush: css">.box { + background-color: #567895; +} + +h2 { + background-color: black; + color: white; +}</pre> + +<p>CSS doesn't mind which one you use. We personally find it is more readable to have each property and value pair on a new line.</p> + +<h3 id="Comment_your_CSS">Comment your CSS</h3> + +<p>Adding comments to your CSS will help any future developer work with your CSS file, but will also help you when you come back to the project after a break.</p> + +<pre class="brush: css">/* This is a CSS comment +It can be broken onto multiple lines. */</pre> + +<p>A good tip is to add a block of comments between logical sections in your stylesheet too, to help locate different sections quickly when scanning through, or even give you something to search for to jump right into that part of the CSS. If you use a string which won't appear in the code you can jump from section to section by searching for it — below we have used <code>||</code>.</p> + +<pre class="brush: css">/* || General styles */ + +... + +/* || Typography */ + +... + +/* || Header and Main Navigation */ + +... + +</pre> + +<p>You don't need to comment every single thing in your CSS, as much of it will be self-explanatory. What you should comment are the things where you made a particular decision for a reason.</p> + +<p>You may have used a CSS property in a specific way to get around older browser incompatibilities, for example:</p> + +<pre class="brush: css">.box { + background-color: red; /* fallback for older browsers that don't support gradients */ + background-image: linear-gradient(to right, #ff0000, #aa0000); +} +</pre> + +<p>Perhaps you followed a tutorial to achieve something, and the CSS is a little non-obvious. In that case you could add the URL of the tutorial to the comments. You will thank yourself when you come back to this project in a year or so, and can vaguely remember there was a great tutorial about that thing, but where is it?</p> + +<h3 id="Create_logical_sections_in_your_stylesheet">Create logical sections in your stylesheet</h3> + +<p>It is a good idea to have all of the common styling first in the stylesheet. This means all of the styles which will generally apply unless you do something special with that element. You will typically have rules set up for:</p> + +<ul> + <li><code>body</code></li> + <li><code>p</code></li> + <li><code>h1</code>, <code>h2</code>, <code>h3</code>, <code>h4</code>, <code>h5</code></li> + <li><code>ul</code> and <code>ol</code></li> + <li>The <code>table</code> properties</li> + <li>Links</li> +</ul> + +<p>In this section of the stylesheet we are providing default styling for the type on the site, setting up a default style for data tables and lists and so on.</p> + +<pre class="brush: css">/* || GENERAL STYLES */ + +body { ... } + +h1, h2, h3, h4 { ... } + +ul { ... } + +blockquote { ... } +</pre> + +<p>After this section we could define a few utility classes, for example a class that removes the default list style for lists we're going to display as flex items or in some other way. If you have a few things you know you will want to apply to lots of different elements, they can come in this section.</p> + +<pre class="brush: css">/* || UTILITIES */ + +.nobullets { + list-style: none; + margin: 0; + padding: 0; +} + +... + +</pre> + +<p>Then we can add everything that is used sitewide. That might be things like the basic page layout, the header, navigation styling, and so on.</p> + +<pre class="brush: css">/* || SITEWIDE */ + +.main-nav { ... } + +.logo { ... } +</pre> + +<p>Finally we will include CSS for specific things, broken down by the context, page or even component in which they are used.</p> + +<pre class="brush: css">/* || STORE PAGES */ + +.product-listing { ... } + +.product-box { ... } +</pre> + +<p>By ordering things in this way, we at least have an idea in which part of the stylesheet we will be looking for something that we want to change.</p> + +<h3 id="Avoid_overly-specific_selectors">Avoid overly-specific selectors</h3> + +<p>If you create very specific selectors you will often find that you need to duplicate chunks of your CSS to apply the same rules to another element. For example, you might have something like the below selector, which applies the rule to a <code><p></code> with a class of <code>box</code> inside an <code><article></code> with a class of <code>main</code>.</p> + +<pre class="brush: css">article.main p.box { + border: 1px solid #ccc; +}</pre> + +<p>If you then wanted to apply the same rules to something outside of <code>main</code>, or to something other than a <code><p></code>, you would have to add another selector to these rules or create a whole new ruleset. Instead, you could create a class called <code>box</code> and apply that anywhere.</p> + +<pre class="brush: css">.box { + border: 1px solid #ccc; +}</pre> + +<p>There will be times when making something more specific makes sense, however this will generally be an exception rather than usual practice.</p> + +<h3 id="Break_large_stylesheets_into_multiple_smaller_ones">Break large stylesheets into multiple smaller ones</h3> + +<p>In particular in cases where you have very different styles for distinct parts of the site, you might want to have a stylesheet that includes all the global rules and then smaller ones that include the specific rules needed for those sections. You can link to multiple stylesheets from one page, and the normal rules of the cascade apply, with rules in stylesheets linked later coming after rules in stylesheets linked earlier.</p> + +<p>For example, we might have an online store as part of the site, with a lot of CSS used only for styling the product listings and forms needed for the store. It would make sense to have those things in a different stylesheet, only linked to on store pages.</p> + +<p>This can make it easier to keep your CSS organised, and also means that if multiple people are working on the CSS you will have fewer situations where two people need to work on the same stylesheet at once, leading to conflicts in source control.</p> + +<h2 id="Other_tools_that_can_help">Other tools that can help</h2> + +<p>CSS itself doesn't have much in the way of in-built organisation, therefore you need to do the work to create consistency and rules around how you write CSS. The web community has also developed various tools and approaches that can help you to manage larger CSS projects. As they may be helpful for you to investigate, and you are likely to come across these things when working with other people, we've included a short guide to some of these.</p> + +<h3 id="CSS_methodologies">CSS methodologies</h3> + +<p>Instead of needing to come up with your own rules for writing CSS, you may benefit from adopting one of the approaches already designed by the community and tested across many projects. These methodologies are essentially CSS coding guides that take a very structured approach to writing and organising CSS. Typically they tend to result in more verbose use of CSS than you might have if you wrote and optimised every selector to a custom set of rules for that project.</p> + +<p>However, you do gain a lot of structure by adopting one and, as many of these systems are very widely used, other developers are more likely to understand the approach you are using and be able to write their CSS in the same way, rather than having to work out your own personal methodology from scratch.</p> + +<h4 id="OOCSS">OOCSS</h4> + +<p>Most of the approaches that you will encounter owe something to the concept of Object Oriented CSS (OOCSS), an approach made popular by <a href="https://github.com/stubbornella/oocss/wiki">the work of Nicole Sullivan</a>. The basic idea of OOCSS is to separate your CSS into reusable objects, which can be used anywhere you need on your site. The standard example of OOCSS is the pattern described as <a href="/en-US/docs/Web/CSS/Layout_cookbook/Media_objects">The Media Object</a>. This is a pattern with a fixed size image, video or other element on one side, and flexible content on the other. It's a pattern we see all over websites for comments, listings, and so on.</p> + +<p>If you are not taking an OOCSS approach you might create custom CSS for the different places this pattern is used, for example creating a class called <code>comment</code> with a bunch of rules for the component parts, then a class called <code>list-item</code> with almost the same rules as the <code>comment</code> class except for some tiny differences. The differences between these two components is that the list-item has a bottom border, and images in comments have a border whereas list-item images do not.</p> + +<pre class="brush: css">.comment { + display: grid; + grid-template-columns: 1fr 3fr; +} + +.comment img { + border: 1px solid grey; +} + +.comment .content { + font-size: .8rem; +} + +.list-item { + display: grid; + grid-template-columns: 1fr 3fr; + border-bottom: 1px solid grey; +} + +.list-item .content { + font-size: .8rem; +}</pre> + +<p>In OOCSS, you would create one pattern called <code>media</code> that would have all of the common CSS for both patterns — a base class for things that are generally the shape of the media object. Then we'd add an additional class to deal with those tiny differences, thus extending that styling in specific ways.</p> + +<pre class="brush: css">.media { + display: grid; + grid-template-columns: 1fr 3fr; +} + +.media .content { + font-size: .8rem; +} + +.comment img { + border: 1px solid grey; +} + + .list-item { + border-bottom: 1px solid grey; +} </pre> + +<p>In your HTML the comment would need both the <code>media</code> and <code>comment</code> classes applied:</p> + +<pre class="brush: html"><div class="media comment"> + <img /> + <div class="content"></div> +</div> +</pre> + +<p>The list-item would have <code>media</code> and <code>list-item</code> applied:</p> + +<pre class="brush: html"><ul> + <li class="media list-item"> + <img /> + <div class="content"></div> + </li> +</ul></pre> + +<p>The work that Nicole Sullivan did in describing this approach and promoting it means that even people who are not strictly following an OOCSS approach today will generally be reusing CSS in this way — it has entered our understanding as a good way to approach things in general.</p> + +<h4 id="BEM">BEM</h4> + +<p>BEM stands for Block Element Modifier. In BEM a block is a standalone entity such as a button, menu, or logo. An element is something like a list item or a title that is tied to the block it is in. A modifier is a flag on a block or element that changes the styling or behavior. You will be able to recognise code that uses BEM due to the extensive use of dashes and underscores in the CSS classes. For example, look at the classes applied to this HTML from the page about <a href="http://getbem.com/naming/">BEM Naming conventions</a>:</p> + +<pre class="brush: html"><form class="form form--theme-xmas form--simple"> + <input class="form__input" type="text" /> + <input + class="form__submit form__submit--disabled" + type="submit" /> +</form></pre> + +<p>The additional classes are similar to those used in the OOCSS example, however they use the strict naming conventions of BEM.</p> + +<p>BEM is widely used in larger web projects and many people write their CSS in this way. It is likely that you will come across examples, even in tutorials, that use BEM syntax, without mentioning why the CSS is structured in such a way.</p> + +<p>To read more about the system read <a href="https://css-tricks.com/bem-101/">BEM 101</a> on CSS Tricks.</p> + +<h4 id="Other_common_systems">Other common systems</h4> + +<p>There are a large number of these systems in use. Other popular approaches include <a href="http://smacss.com/">Scalable and Modular Architecture for CSS (SMACSS)</a>, created by Jonathan Snook, <a href="https://itcss.io/">ITCSS</a> from Harry Roberts, and <a href="https://acss.io/">Atomic CSS (ACSS)</a>, originally created by Yahoo!. If you come across a project that uses one of these approaches then the advantage is that you will be able to search and find many articles and guides to help you understand how to code in the same style.</p> + +<p>The disadvantage of using such a system is that they can seem overly complex, especially for smaller projects.</p> + +<h3 id="Build_systems_for_CSS">Build systems for CSS</h3> + +<p>Another way to organise CSS is to take advantage of some of the tooling that is available for front-end developers, which allows you to take a slightly more programmatic approach to writing CSS. There are a number of tools which we refer to as <em>pre-processors</em> and <em>post-processors</em>. A pre-processor runs over your raw files and turns them into a stylesheet, whereas a post-processor takes your finished stylesheet and does something to it — perhaps to optimize it in order that it will load faster.</p> + +<p>Using any of these tools will require that your development environment can run the scripts that do the pre and post-processing. Many code editors can do this for you, or you can install command line tools to help.</p> + +<p>The most popular pre-processor is <a href="https://sass-lang.com/">Sass</a>. This is not a Sass tutorial, so I will briefly explain a couple of the things that Sass can do, which are really helpful in terms of organisation, even if you don't use any of the other Sass features.</p> + +<h4 id="Defining_variables">Defining variables</h4> + +<p>CSS now has native <a href="/en-US/docs/Web/CSS/Using_CSS_custom_properties">custom properties</a>, making this feature increasingly less important, however one of the reasons you might use Sass is to be able to define all of the colors and fonts used in a project as settings, then use that variable around the project. This means that if you realise you have used the wrong shade of blue, you only need change it in one place.</p> + +<p>If we created a variable called <code>$base-color</code> as in the first line below, we could then use it through the stylesheet anywhere that required that color.</p> + +<pre class="brush: css"><code>$base-color: #c6538c; + +.alert { + border: 1px solid $base-color; +}</code></pre> + +<p>Once compiled to CSS, you would end up with the following CSS in the final stylesheet.</p> + +<pre class="brush: css"><code>.alert { + border: 1px solid #c6538c; +}</code></pre> + +<h4 id="Compiling_component_stylesheets">Compiling component stylesheets</h4> + +<p>I mentioned above that one way to organise CSS is to break down stylesheets into smaller stylesheets. When using Sass you can take this to another level and have lots of very small stylesheets — even going as far as having a separate stylesheet for each component. By using the include functionality in Sass these can then all be compiled together into one, or a small number of stylesheets to actually link into your website.</p> + +<p>You can see how one developer approaches the problem in <a href="https://www.lauraleeflores.com/blog/how-to-organize-your-css-files">this blog post</a>.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: A simple way to try out Sass is to use <a href="https://codepen.io">CodePen</a> — you can enable Sass for your CSS in the Settings for a Pen, and CodePen will then run the Sass parser for you, in order that you can see the resulting webpage with regular CSS applied. Sometimes you will find that CSS tutorials have used Sass rather than plain CSS in their CodePen demos, so it is handy to know a little bit about it.</p> +</div> + +<h4 id="Post-processing_for_optimization">Post-processing for optimization</h4> + +<p>If you are concerned about adding size to your stylesheets by adding a lot of additional comments and whitespace for example, then a post-processing step could be to optimize the CSS by stripping out anything unneccessary in the production version. An example of a post-processor solution for doing this would be <a href="https://cssnano.co/">cssnano</a>.</p> + +<h2 id="Wrapping_up">Wrapping up</h2> + +<p>This is the final part of our Learning CSS Guide, and as you can see there are many ways in which your exploration of CSS can continue from this point.</p> + +<p>To learn more about layout in CSS, see the <a href="/en-US/docs/Learn/CSS/CSS_layout">Learn CSS Layout</a> section.</p> + +<p>You should also now have the skills to explore the rest of the <a href="/en-US/docs/Web/CSS">MDN CSS</a> material. You can look up properties and values, explore our <a href="/en-US/docs/Web/CSS/Layout_cookbook">CSS Cookbook</a> for patterns to use, and read more in some of the specific guides such as our <a href="/en-US/docs/Web/CSS/CSS_Grid_Layout">Guide to CSS Grid Layout</a>.</p> + +<p>{{PreviousMenu("Learn/CSS/Building_blocks/Debugging_CSS", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS selectors</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class, and ID selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Combinators</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Backgrounds and borders</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Handling different text directions</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">Overflowing content</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">Values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Images, media, and form elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">Styling tables</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">Organizing your CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/overflowing_content/index.html b/files/ru/learn/css/building_blocks/overflowing_content/index.html new file mode 100644 index 0000000000..919bed3501 --- /dev/null +++ b/files/ru/learn/css/building_blocks/overflowing_content/index.html @@ -0,0 +1,119 @@ +--- +title: Перекрытие содержимого +slug: Learn/CSS/Building_blocks/Overflowing_content +translation_of: Learn/CSS/Building_blocks/Overflowing_content +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Handling_different_text_directions", "Learn/CSS/Building_blocks/Values_and_units", "Learn/CSS/Building_blocks")}}</div> + +<p>В этом уроке мы рассмотрим другую важную концепцию в CSS — <strong>overflow</strong>. Overflow это то что случается, когда слишком много контента содержится внутри блока. В этом гайде вы изучите что это и как этим управлять.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">basic software installed</a>, basic knowledge of <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">working with files</a>, HTML basics (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), and an idea of how CSS works (study <a href="/en-US/docs/Learn/CSS/First_steps">CSS first steps</a>.)</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand overflow and how to manage it.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_overflow">Что такое overflow?</h2> + +<p>Мы уже знаем что все в CSS - блоки, и что мы можем ограничивать размер этих блоков присваивая им определенное значение посредством {{cssxref("width")}} и {{cssxref("height")}} (или {{cssxref("inline-size")}} и {{cssxref("block-size")}}). Overflow это то что случается, когда у вас слишком много контента в блоке, так что он не помещается в данный ограниченный блок. CSS дает нам различные инструменты для управления этим overflow, и это также полезная концепция для понимания на этой ранней стадии. Вы будете встречаться с overflow достаточно часто когда пишите CSS, особенно когда глубже погрузитесь в CSS макет.</p> + +<h2 id="CSS_пытается_избежать_потери_данных">CSS пытается избежать "потери данных"</h2> + +<p>Давайте начнем с рассмотрения двух примеров, которые демонстрируют как CSS ведет себя когда у вас overflow.</p> + +<p>The first is a box that has been restricted in the block dimension by giving it a <code>height</code>. We have then added more content than there is space for in this box. The content is overflowing the box and laying itself rather messily over the paragraph below the box.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/block-overflow.html", '100%', 600)}}</p> + +<p>The second is a word in a box that is restricted in the inline dimension. The box has been made too small for that word to fit and so it breaks out of the box.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/inline-overflow.html", '100%', 500)}}</p> + +<p>You might wonder why CSS has by default taken the rather untidy approach of causing the content to overflow messily? Why not hide the additional content, or cause the box to grow?</p> + +<p>Wherever possible CSS does not hide your content; to do so would cause data loss, which is usually a problem. In CSS terms, this means some content vanishing. The problem with content vanishing is that you might not notice it has vanished. Your visitors may not notice it has vanished. If it is the submit button on a form that disappears, and no-one can complete the form, that's a big problem! So instead, CSS tends to overflow in a visible way. It is likely you will see the mess, or at worst a visitor to your site will let you know that some content is overlapping so it needs fixing.</p> + +<p>If you have restricted a box with a <code>width</code> or a <code>height</code>, CSS assumes you know what you are doing, and that you are managing the potential for overflow. In general, restricting the block dimension is problematic when text is going to be put in a box, as there may be more text than you expected when designing the site or the text may be bigger — for example if the user has increased their font size.</p> + +<p>In the next couple of lessons we will look at different ways to control sizing that might be less prone to overflow. However, if you need a fixed size you can also control how the overflow behaves. Let's read on!</p> + +<h2 id="The_overflow_property">The overflow property</h2> + +<p>The {{cssxref("overflow")}} property is how you take control of an element's overflow and tell the browser how you want it to behave. The default value of overflow is <code>visible</code>, which is why by default we can see our content when it overflows.</p> + +<p>If you want to crop the content when it overflows you can set <code>overflow: hidden</code> on your box. This will do exactly what it says — hide the overflow. This may well cause things to vanish so you should only ever do this if hiding content is not going to cause a problem.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/hidden.html", '100%', 600)}}</p> + +<p>Perhaps you would instead like to add scrollbars when content overflows? If you use <code>overflow: scroll</code> then your browser will always display scrollbars — even if there is not enough content to overflow. You may want this, as it prevents scrollbars appearing and disappearing depending on content.</p> + +<p><strong>If you remove some of the content from the box below, you'll see that the scrollbars still remain even with nothing to scroll (or at least just the scrollbar tracks).</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/scroll.html", '100%', 600)}}</p> + +<p>In the above example we only need to scroll on the <code>y</code> axis, however we get scrollbars in both axes. You could instead use the {{cssxref("overflow-y")}} property, setting <code>overflow-y: scroll</code> to only scroll on the <code>y</code> axis.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/scroll-y.html", '100%', 600)}}</p> + +<p>You could also scroll on the x axis using {{cssxref("overflow-x")}}, although this is not a recommended way to deal with long words! If you do need to deal with a long word in a small box then you could look at the {{cssxref("word-break")}} or {{cssxref("overflow-wrap")}} properties. In addition some of the methods discussed in the <a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a> lesson may help you to create boxes that cope better with varying amounts of content.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/scroll-x.html", '100%', 500)}}</p> + +<p>As with <code>scroll</code>, you will get a scrollbar in the scrolling dimension whether or not there is enough content to cause a scrollbar.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: that you can specify x and y scrolling using the <code>overflow</code> property and passing in two values. If two keywords are specified, the first applies to <code>overflow-x</code> and the second to <code>overflow-y</code>. Otherwise, both <code>overflow-x</code> and <code>overflow-y</code> are set to the same value. For example, <code>overflow: scroll hidden</code> would set <code>overflow-x</code> to <code>scroll</code> and <code>overflow-y</code> to <code>hidden</code>.</p> +</div> + +<p>If you only want scrollbars to appear if there is more content than can fit in the box, then use <code>overflow: auto</code>. In this case it is left up to the browser to decide whether to display scrollbars. Desktop browsers will typically only do so once there is enough content to cause overflow.</p> + +<p><strong>In the below example, remove some of the content until it fits into the box and you should see the scrollbars disappear.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/auto.html", '100%', 600)}}</p> + +<h2 id="Overflow_establishes_a_Block_Formatting_Context">Overflow establishes a Block Formatting Context</h2> + +<p>There is a concept in CSS of the <strong>Block Formatting Context</strong> (BFC). This isn't something you need to worry too much about right now, but it is useful to know that when you use a value of overflow such as <code>scroll</code> or <code>auto</code> you create a BFC. The result is that the content of the box you have changed the value of <code>overflow</code> for becomes a mini layout of its own. Things outside the container cannot poke into the container, and nothing can poke out of that box into the surrounding layout. This is to enable the scrolling behavior, as all content of your box will need to be contained and not overlap other items on the page, in order to create a consistent scrolling experience.</p> + +<h2 id="Unwanted_overflow_in_web_design">Unwanted overflow in web design</h2> + +<p>Modern layout methods (as covered in the <a href="/en-US/docs/Learn/CSS/CSS_layout">CSS layout</a> module) manage overflow very well. They have been designed to cope with the fact that we tend not to be able to predict how much content we have on the web. In the past however, developers would often use fixed heights to try to line up the bottoms of boxes that really had no relationship to each other. This was fragile, and in a legacy application you may occasionally come across a box where the content is overlaying other content on the page. If you see this you now know that what is happening is overflow; ideally you would refactor the layout to not rely on fixing the box size.</p> + +<p>When developing a site you should always keep overflow issues in mind. You should test designs with large and small amounts of content, increase the font size of text and ensure that your CSS can cope in a robust way. Changing the value of overflow to hide content or add scrollbars is likely to be something you reserve only for a few special cases — where you really do want a scrolling box for example.</p> + +<h2 id="Summary">Summary</h2> + +<p>This short lesson has introduced the concept of overflow; you now understand that CSS tries not to make overflowing content invisible as this will cause data loss. You have discovered that you can manage potential overflow, and also that you should test your work to make sure you do not accidentally cause problematic overflow.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Handling_different_text_directions", "Learn/CSS/Building_blocks/Values_and_units", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS selectors</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class, and ID selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Combinators</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Backgrounds and borders</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Handling different text directions</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">Overflowing content</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">Values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Images, media, and form elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">Styling tables</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">Organizing your CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/sizing_items_in_css/index.html b/files/ru/learn/css/building_blocks/sizing_items_in_css/index.html new file mode 100644 index 0000000000..198f9f6ecc --- /dev/null +++ b/files/ru/learn/css/building_blocks/sizing_items_in_css/index.html @@ -0,0 +1,129 @@ +--- +title: Изменение размеров в CSS +slug: Learn/CSS/Building_blocks/Sizing_items_in_CSS +translation_of: Learn/CSS/Building_blocks/Sizing_items_in_CSS +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Values_and_units", "Learn/CSS/Building_blocks/Images_media_form_elements", "Learn/CSS/Building_blocks")}}</div> + +<p>In the various lessons so far you have come across a number of ways to size items on a web page using CSS. Understanding how big the different features in your design will be is important, and in this lesson we will summarize the various ways elements get a size via CSS and define a few terms around sizing that will help you in the future.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">basic software installed</a>, basic knowledge of <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">working with files</a>, HTML basics (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), and an idea of how CSS works (study <a href="/en-US/docs/Learn/CSS/First_steps">CSS first steps</a>.)</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand the different ways we can size things in CSS.</td> + </tr> + </tbody> +</table> + +<h2 id="The_natural_or_intrinsic_size_of_things">The natural or intrinsic size of things</h2> + +<p>HTML Elements have a natural size, set before they are affected by any CSS. A straightforward example is an image. An image has a width and a height defined in the image file it is embedding into the page. This size is described as the <strong>intrinsic size</strong> — which comes from the image itself.</p> + +<p>If you place an image on a page and do not change its height and width, either using attributes on the <code><img></code> tag or CSS, it will be displayed using that intrinsic size. We have given the image in the example below a border so that you can see the extent of the file.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/intrinsic-image.html", '100%', 600)}}</p> + +<p>An empty {{htmlelement("div")}} however, has no size of its own. If you add a {{htmlelement("div")}} to your HTML with no content, then give it a border as we did with the image, you will see a line on the page. This is the collapsed border on the element — there is no content to hold it open. In our example below, that border stretches to the width of the container, because it is a block level element, a behavior that should be starting to become familiar to you. It has no height (or size in the block dimension) because there is no content.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/intrinsic-text.html", '100%', 500)}}</p> + +<p>In the example above, try adding some text inside the empty element. The border now contains that text because the height of the element is defined by the content. Therefore the size of this <code><div></code> in the block dimension comes from the size of the content. Again, this is the intrinsic size of the element — its size is defined by its content.</p> + +<h2 id="Setting_a_specific_size">Setting a specific size</h2> + +<p>We can of course give elements in our design a specific size. When a size is given to an element (and the content of which then needs to fit into that size) we refer to it as an <strong>extrinsic size</strong>. Take our <code><div></code> from the example above — we can give it specific {{cssxref("width")}} and {{cssxref("height")}} values, and it will now have that size no matter what content is placed into it. As we discovered in <a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">our previous lesson on overflow</a>, a set height can cause content to overflow if there is more content than the element has space to fit inside it.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/height.html", '100%', 600)}}</p> + +<p>Due to this problem of overflow, fixing the height of elements with lengths or percentages is something we need to do very carefully on the web.</p> + +<h3 id="Using_percentages">Using percentages</h3> + +<p>In many ways percentages act like length units, and as we <a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#Percentages">discussed in the lesson on values and units</a>, they can often be used interchangeably with lengths. When using a percentage you need to be aware what it is a percentage <em>of</em>. In the case of a box inside another container, if you give the child box a percentage width it will be a percentage of the width of the parent container.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/percent-width.html", '100%', 600)}}</p> + +<p>This is because percentages resolve against the size of the containing block. With no percentage applied our <code><div></code> would take up 100% of the available space, as it is a block level element. If we give it a percentage width, this becomes a percentage of the space it would normally fill.</p> + +<h3 id="Percentage_margins_and_padding">Percentage margins and padding</h3> + +<p>If you set <code>margins</code> and <code>padding</code> as a percentage you may notice some strange behavior. In the below example we have a box. We have given the inner box a {{cssxref("margin")}} of 10% and a {{cssxref("padding")}} of 10%. The padding and margin on the top and bottom of the box are the same size as the margin on the left and right.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/percent-mp.html", '100%', 700)}}</p> + +<p>You might expect for example the percentage top and bottom margins to be a percentage of the element's height, and the percentage left and right margins to be a percentage of the element's width. However, this is not the case!</p> + +<p>When you use margin and padding set in percentages, the value is calculated from the<strong> inline size</strong> — therefore the width when working in a horizontal language. In our example, all of the margins and padding are 10% of the width. This means you can have equal sized margins and padding all round the box. This is a fact worth remembering if you do use percentages in this way.</p> + +<h2 id="min-_and_max-_sizes">min- and max- sizes</h2> + +<p>In addition to giving things a fixed size, we can ask CSS to give an element a minimum or a maximum size. If you have a box that might contain a variable amount of content, and you always want it to be <em>at least</em> a certain height, you could set the {{cssxref("min-height")}} property on it. The box will always be at least this height, but will then grow taller if there is more content than the box has space for at its minimum height.</p> + +<p>In the example below you can see two boxes, both with a defined height of 150 pixels. The box on the left is 150 pixels tall; the box on the right has content that needs more room, and so it has grown taller than 150 pixels.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/min-height.html", '100%', 800)}}</p> + +<p>This is very useful for dealing with variable amounts of content while avoiding overflow.</p> + +<p>A common use of {{cssxref("max-width")}} is to cause images to scale down if there is not enough space to display them at their intrinsic width, while making sure they don't become larger than that width.</p> + +<p>As an example, if you were to set <code>width: 100%</code> on an image, and its intrinsic width was smaller than its container, the image would be forced to stretch and become larger, causing it to look pixellated. If its intrinsic width were larger than its container, it would overflow it. Neither case is likely to be what you want to happen.</p> + +<p>If you instead use <code>max-width: 100%</code>, the image is able to become smaller than its intrinsic size, but will stop at 100% of its size.</p> + +<p>In the example below we have used the same image twice. The first image has been given <code>width: 100%</code> and is in a container which is larger than it, therefore it stretches to the container width. The second image has <code>max-width: 100%</code> set on it and therefore does not stretch to fill the container. The third box contains the same image again, also with <code>max-width: 100%</code> set; in this case you can see how it has scaled down to fit into the box.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/max-width.html", '100%', 800)}}</p> + +<p>This technique is used to make images <em>responsive</em>, so that when viewed on a smaller device they scale down appropriately. You should however not use this technique to load in really large images and then scale them down in the browser. Images should be appropriately sized to be no larger than they need to be for the largest size they are displayed in the design. Downloading overly large images will cause your site to become slow, and it can cost users more money if they are on a metered connection.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Find out more about <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">responsive image techniques</a>.</p> +</div> + +<h2 id="Viewport_units">Viewport units</h2> + +<p>The viewport — which is the visible area of your page in the browser you are using to view a site — also has a size. In CSS we have units which relate to the size of the viewport — the <code>vw</code> unit for viewport width, and <code>vh</code> for viewport height. Using these units you can size something relative to the viewport of the user.</p> + +<p><code>1vh</code> is equal to 1% of the viewport height, and <code>1vw</code> is equal to 1% of the viewport width. You can use these units to size boxes, but also text. In the example below we have a box which is sized as 20vh and 20vw. The box contains a letter <code>A</code>, which has been given a {{cssxref("font-size")}} of 10vh.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/vw-vh.html", '100%', 600)}}</p> + +<p><strong>If you change the <code>vh</code> and <code>vw</code> values this will change the size of the box or font; changing the viewport size will also change their sizes because they are sized relative to the viewport. To see the example change when you change the viewport size you will need to load the example in a new browser window that you can resize (as the embedded <code><iframe></code> that contains the example shown above is its viewport). <a href="https://mdn.github.io/css-examples/learn/sizing/vw-vh.html">Open the example</a>, resize the browser window, and observe what happens to the size of the box and text.</strong></p> + +<p>Sizing things according to the viewport can be useful in your designs. For example, if you want a full page hero section to show before the rest of your content, making that part of your page 100vh high will push the rest of the content below the viewport, meaning that it will only appear once the document is scrolled.</p> + +<h2 id="Summary">Summary</h2> + +<p>This lesson has given you a rundown of some key issues that you might run into when sizing things on the web. When you move onto <a href="/en-US/docs/Learn/CSS/CSS_layout">CSS Layout</a>, sizing will become very important in mastering the different layout methods, so it is worth understanding the concepts here before moving on.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Values_and_units", "Learn/CSS/Building_blocks/Images_media_form_elements", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS selectors</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class, and ID selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Combinators</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Backgrounds and borders</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Handling different text directions</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">Overflowing content</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">Values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Images, media, and form elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">Styling tables</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">Organizing your CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/styling_tables/index.html b/files/ru/learn/css/building_blocks/styling_tables/index.html new file mode 100644 index 0000000000..0141bfc6f2 --- /dev/null +++ b/files/ru/learn/css/building_blocks/styling_tables/index.html @@ -0,0 +1,302 @@ +--- +title: Стилизация таблиц +slug: Learn/CSS/Building_blocks/Styling_tables +tags: + - CSS + - Стилизация + - таблицы +translation_of: Learn/CSS/Building_blocks/Styling_tables +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/Styling_boxes/Borders", "Learn/CSS/Styling_boxes/Advanced_box_effects", "Learn/CSS/Styling_boxes")}}</div> + +<p class="summary">Стилизация HTML таблиц это не самая гламурная работа в мире, но иногда нам нужно это делать. Эта статья рукодство как сделать, чтобы ваши HTML таблицы выглядели хорошо, с некоторыми свойствами подробно рассмотренными в предыдущих статьях.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовый HTML (<a href="/ru/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), HTML таблицы (смотрите раздел HTML таблицы (TBD)), и представление о том как работает CSS (<a href="/ru/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Научиться эффективно стилизовать HTML таблицы.</td> + </tr> + </tbody> +</table> + +<h2 id="Типичная_HTML_таблица">Типичная HTML таблица</h2> + +<p>Давайте начнем с рассмотрения типичной HTML таблицы. Когда мы говорим о примерах типичных HTML таблиц обычно речь идет о обуви, погоде или сотрудниках; мы решили сделать этоболее интересным создав таблицу о знаменитых панк группах Великобритании. Разметка выглядит следующим образом:</p> + +<pre class="brush: html"><table> + <caption>A summary of the UK's most famous punk bands</caption> + <thead> + <tr> + <th scope="col">Band</th> + <th scope="col">Year formed</th> + <th scope="col">No. of Albums</th> + <th scope="col">Most famous song</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">Buzzcocks</th> + <td>1976</td> + <td>9</td> + <td>Ever fallen in love (with someone you shouldn't've)</td> + </tr> + <tr> + <th scope="row">The Clash</th> + <td>1976</td> + <td>6</td> + <td>London Calling</td> + </tr> + + ... some rows removed for brevity + + <tr> + <th scope="row">The Stranglers</th> + <td>1974</td> + <td>17</td> + <td>No More Heroes</td> + </tr> + </tbody> + <tfoot> + <tr> + <th scope="row" colspan="2">Total albums</th> + <td colspan="2">77</td> + </tr> + </tfoot> +</table></pre> + +<p>Таблица размечена, немного стилизована и понятна, благодаря использованию таких свойств как {{htmlattrxref("scope","th")}}, {{htmlelement("caption")}}, {{htmlelement("thead")}}, {{htmlelement("tbody")}} и т.д. К сожалению при просмотре в браузере она не очень хорошо выглядит (посмотреть можно здесь <a href="http://mdn.github.io/learning-area/css/styling-boxes/styling-tables/punk-bands-unstyled.html">punk-bands-unstyled.html</a>):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13064/table-unstyled.png" style="display: block; margin: 0 auto;"></p> + +<p>Это выглядит достаточно грубо, трудно читаемо и скучно. Нам нужно использовать немного CSS чтобы все исправить.</p> + +<h2 id="Активное_обучение_Стилизация_таблицы">Активное обучение: Стилизация таблицы</h2> + +<p>В этой части обучения мы будем работать над тем чтобы стилизовать наш пример таблицы.</p> + +<ol> + <li>В начале неоюходимо сделать копию <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/styling-tables/punk-bands-unstyled.html">sample markup</a>, загрузить оба изображения (<a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/styling-tables/noise.png">noise</a> и <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/styling-tables/leopardskin.jpg">leopardskin</a>), и вставить эти файлы в отдельную папку на вашем компьютере.</li> + <li>Следующее, это создать новый файл <code>style.css</code> и сохранить его в той же папке вместе с другими файлами.</li> + <li>Подключить CSS в HTML для этого разместить следующую строку в HTML внутри {{htmlelement("head")}}: + <pre class="brush: html"><link href="style.css" rel="stylesheet" type="text/css"></pre> + </li> +</ol> + +<h3 id="Отступы_и_разметка">Отступы и разметка</h3> + +<p>Первое что нам нужно это разобраться с отступами/разметкой, так как по умолчанию стилизация таблцы выглядит неразборчиво! Сделаем это, добавив CSS в ваш <code>style.css</code> файл:</p> + +<pre class="brush: css">/* spacing */ + +table { + table-layout: fixed; + width: 100%; + border-collapse: collapse; + border: 3px solid purple; +} + +thead th:nth-child(1) { + width: 30%; +} + +thead th:nth-child(2) { + width: 20%; +} + +thead th:nth-child(3) { + width: 15%; +} + +thead th:nth-child(4) { + width: 35%; +} + +th, td { + padding: 20px; +}</pre> + +<p>Наиболее важные части следующие:</p> + +<ul> + <li>Свойство {{cssxref("table-layout")}} со значением <code>fixed</code> как правило полезно использовать для вашей таблицы, это делает поведение таблицы немного более предсказуемым, чем значение по умолчанию. Обычно столбцы таблицы имеют размер в зависимости от того сколько в них контента, что приводит иногда к некоторым странным результатам. Когда <code>table-layout: fixed</code>, размер ваших столбцов определяется шириной их заголовков и делает их контент соответствующего размера. Вот почему вы выбрали четыре разных заголовка с помощью селектора <code>thead th:nth-child(<em>n</em>)</code> ({{cssxref(":nth-child")}}) ("Выберите <em>n-ый</em> дочерний элемент {{htmlelement("th")}} в последовательности, внутри элемента {{htmlelement("thead")}}") и задать им заданную в процентах ширину. Ширина колонки соответствует ширине ее заголовка, это правильное решение при определении размеров колонок таблицы. Крис Койер (Chris Coyier) более подробно рассматиривает эту технику в статье <a href="https://css-tricks.com/fixing-tables-long-strings/">Fixed Table Layouts</a>.<br> + <br> + Мы также использовали {{cssxref("width")}} 100%, что означает, что таблица заполнит любой контейнер и будет озывчивой (хотя для этого потребуется еще некоторая работа для правильного отображнения на экранах небольших размеров).</li> + <li>Свойство {{cssxref("border-collapse")}} со значением <code>collapse</code> это стандартная практика при стилизации любой таблицы. По умолчанию, когда вы задали рамки для элементов таблицы, все они будут иметь пробелы между собой, как показано на рисунке ниже: <img alt="" src="https://mdn.mozillademos.org/files/13068/no-border-collapse.png" style="display: block; margin: 0 auto;">Это не очень хорошо выглядит (хотя может это то что вам нужно, кто знает?). Если установить <code>border-collapse: collapse;</code> рамки схлопываются в одну и так выглядит намного лучше: <img alt="" src="https://mdn.mozillademos.org/files/13066/border-collapse.png" style="display: block; margin: 0 auto;"></li> + <li>Мы установили {{cssxref("border")}} вокруг всей таблицы, это понадобится когда чуть позже мы будет устанавливать рамки вокруг header и footer таблицы — когда по периметру всей таблицы нет рамки и граница заканчивается просто отступом, таблица выглядит странно и разрозненно.</li> + <li>Мы установили {{cssxref("padding")}} на элементах {{htmlelement("th")}} и {{htmlelement("td")}} — это создает в талице воздух, который позволяет ей дышать, делая ее более понятной.</li> +</ul> + +<p>На этом этапе наша таблица выглядит уже гораздо лучше:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13070/table-with-spacing.png" style="display: block; margin: 0 auto;"></p> + +<h3 id="Немного_простой_типографики">Немного простой типографики</h3> + +<p>Теперь мы еще кое-что изменим.</p> + +<p>Во-первых, мы пойдем и найдем на <a href="https://www.google.com/fonts">Google Fonts</a> шрифт который подходит в нашей ситуации с таблицей о панк группах. Вы можете можете выбрать для себя другой шрифт если захотит, тогда вам понадобится заменить представленный {{htmlelement("link")}} элемент и изменить объявление {{cssxref("font-family")}} на выбраный вами Google Fonts шрифт.</p> + +<p>Добавьте элемент {{htmlelement("link")}} в блок head вашего HTML, на строчку выше существующего элемента <code><link></code>:</p> + +<pre class="brush: html"><link href='https://fonts.googleapis.com/css?family=Rock+Salt' rel='stylesheet' type='text/css'></pre> + +<p>Затем добавьте следующий CSS в ваш <code>style.css</code> файл, ниже предыдущего кода:</p> + +<pre class="brush: css">/* typography */ + +html { + font-family: 'helvetica neue', helvetica, arial, sans-serif; +} + +thead th, tfoot th { + font-family: 'Rock Salt', cursive; +} + +th { + letter-spacing: 2px; +} + +td { + letter-spacing: 1px; +} + +tbody td { + text-align: center; +} + +tfoot th { + text-align: right; +}</pre> + +<p>Здесь нет ничего специально для таблиц, мы просто настраиваем стилизацию шрифтов, чтобы упростить чтение:</p> + +<ul> + <li>Мы установили доступный глобально шрифт sans-serif; это вполне стандартный стилистический выбор. Мы установили выбранный нами шрифт для заголовков внутри элементов {{htmlelement("thead")}} и {{htmlelement("tfoot")}}, который подходит нам по тематике панков.</li> + <li>Мы добавили немного {{cssxref("letter-spacing")}} в заголовках и ячейках которым необходимо добавить читаемости. Опять же это основной стилистический прием.</li> + <li>Мы выравниваем по центру текст ячейках внутри {{htmlelement("tbody")}} чтобы они совпадали с заголовками. По умолчанию у ячеек свойство {{cssxref("text-align")}} имеет значение <code>left</code>, а заголовки значение <code>center</code>, но обычно выглядит лучше если они выравниваются в одном стиле. По умолчанию, чтобы внешний вид заголовков отличался у них задан жирный шрифт.</li> + <li>Мы выровняли заголовок справа внутри {{htmlelement("tfoot")}} так чтобы он визуально ассоциировался с соответствующими ему данными.</li> +</ul> + +<p>В результате таблица выглядит немного аккуратнее:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13072/table-with-typography.png" style="display: block; margin: 0 auto;"></p> + +<h3 id="Графика_и_цвета">Графика и цвета</h3> + +<p>И наконец-то графика и цвета! Наша таблица заполнена тем что имеет отношение к панкам, поэтому нам нужно придать ей яркий впечатляющий вид. Не беспокойтесь, вам не обязательно делать таблицу слишком кричащей — вы можете выбрать что-то более утонченное и со вкусом.</p> + +<p>Следующий шаг это добавить следующий CSS в ваш <code>style.css</code> файл в самом низу:</p> + +<pre>thead, tfoot { + background: url(leopardskin.jpg); + color: white; + text-shadow: 1px 1px 1px black; +} + +thead th, tfoot th, tfoot td { + background: linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.5)); + border: 3px solid purple; +} +</pre> + +<p>Опять же здесь нет ничего конкретно для таблиц, но стоит отметить несколько вещей.</p> + +<p>Мы добавили {{cssxref("background-image")}} в {{htmlelement("thead")}}, {{htmlelement("tfoot")}} и изменили {{cssxref("color")}} для всего текста внутри header и footer на белый (и еще {{cssxref("text-shadow")}}) для лучшей читаемости. Вы должны всегда быть уверены что ваш текст хорошо контрастирует с фоном, для обеспечения читаемости.</p> + +<p>Также мы добавили линейный градиент для {{htmlelement("th")}} и {{htmlelement("td")}} элементов внутри header и footer для придания легкой приятной текстуры, а также установили этим элементамяркие пурпурные границы. Полезно иметь несколько вложенных элементов, это позволяет накладывать несколько стилей друг на друга. Да, мы могли бы установить и фоновое изображение, и линейный градиент на {{htmlelement("thead")}} и {{htmlelement("tfoot")}} элементы используя множественные фоновые изображения, но мы решили сделать это отдельно для старых браузеров, которые не поддерживают <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Backgrounds_and_Borders/Using_multiple_backgrounds">несколько фоновых изображений</a> и <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient">линейные градиенты</a>.</p> + +<h4 id="Полосатая_зебра">Полосатая зебра</h4> + +<p>Мы хотели бы посвятить целый раздел, чтобы показать вам как реализовать <strong>полосы зебры</strong> — чередующиеся цветные строки которые упрощают чтение разных строк в вашей таблице. Добавим следующий CSS в ваш <code>style.css</code> файл:</p> + +<pre class="brush: css">tbody tr:nth-child(odd) { + background-color: #ff33cc; +} + +tbody tr:nth-child(even) { + background-color: #e495e4; +} + +tbody tr { + background-image: url(noise.png); +} + +table { + background-color: #ff33cc; +}</pre> + +<ul> + <li>Ранее вы видели как {{cssxref(":nth-child")}} селектор использовался для выбора специфичных дочерних элементов. В качестве параметра также может быть передана формула, тогда он будет выбирать последовательноость элементов. Так формула <code>2n-1</code> выберет все нечетные дочерние элементы (1, 3, 5 и т.д.), а формула <code>2n</code> выберет все четные (2, 4, 6 и т.д.). Мы использовали в нашем коде ключевые слова <code>odd</code> и <code>even</code>, которые делают тоже самое что и формулы выше. В данном случае мы устанавливаем четным и нечетным строкам разные (яркие) цвета.</li> + <li>Еще мы добавили повторяющийся плиткой фон ко всем строкам тела таблицы, который добавляет немного шума (полупрозрачный <code>.png</code> с небольшим количеством визуальных искажений на нем), чтобы получилась некоторая текстура.</li> + <li>И наконец мы установили для таблицы сплошной цвет фона, котрый обеспечит фон строкам таблицы в том случае если браузер не поддерживает селектор <code>:nth-child</code>.</li> +</ul> + +<p>Этот взрыв цвета выглядит следующим образом:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13074/table-with-color.png" style="display: block; margin: 0 auto;"></p> + +<p>То что получилось может быть не в вашем вкусе, но основная идея была в том, что мы попытались сделать таблицу которая не будет скучной и акдемической.</p> + +<h3 id="Стилизация_заголовка">Стилизация заголовка</h3> + +<p>Последнее что мы сделаем с нашей таблицей это стилизация заголовка. Для этого добавим следующие строки в наш файл <code>style.css</code>:</p> + +<pre class="brush: css">caption { + font-family: 'Rock Salt', cursive; + padding: 20px; + font-style: italic; + caption-side: bottom; + color: #666; + text-align: right; + letter-spacing: 1px; +}</pre> + +<p>Здесь нет ничего особенного, кроме свойства {{cssxref("caption-side")}}, которое имеет значение <code>bottom</code>. В этом случае заголовок будет размещен внизу таблицы и это вместе со всем остальным обеспечивает нашей таблице окончательный вид (можно посмотреть по ссылке <a href="http://mdn.github.io/learning-area/css/styling-boxes/styling-tables/punk-bands-complete.html">punk-bands-complete.html</a>):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13076/table-with-caption.png" style="display: block; height: 357px; margin: 0px auto; width: 723px;"></p> + +<h2 id="Активное_обучение_Стилизация_вашей_собственной_таблицы">Активное обучение: Стилизация вашей собственной таблицы</h2> + +<p>Теперь мы хотим, чтобы вы взяли наш пример таблицы (или использовали собственный!) и сделали что-то зачительно более стильное и менее безвкусное чем наша таблица.</p> + +<h2 id="Стилизация_таблицы_быстрые_советы">Стилизация таблицы быстрые советы</h2> + +<p>Короткий список наиболее полезных вещей рассмотренных выше:</p> + +<ul> + <li>Сделайте свою разметку простой и гибкой, например, используя для этого проценты, что сделает дизайн более отзывчивым.</li> + <li>Используйте {{cssxref("table-layout")}}<code>: fixed</code> для более понятного поведения разметки, при этомлегко установить ширину столбцов, установив ширину {{cssxref("width")}} для заголовков таблицы ({{htmlelement("th")}}).</li> + <li>Используйте {{cssxref("border-collapse")}}<code>: collapse</code>, которое схлопнет границы элементов таблицы, что обеспечит аккуратный внешний вид.</li> + <li>Используйте {{htmlelement("thead")}}, {{htmlelement("tbody")}} и {{htmlelement("tfoot")}} чтобы разбить вашу таблицу на логические фрагменты и предоставив таким образом дополнительные точки для применения CSS, это дает возможность накладывать стили друг на друга, если это необходимо.</li> + <li>Используйте полоски зебры, чтобы облегчить чтение между строк.</li> + <li>Используйте {{cssxref("text-align")}} чтобы выровнять текст в {{htmlelement("th")}} и {{htmlelement("td")}} для более аккуратного и удобного оформления.</li> +</ul> + +<h2 id="Заключение">Заключение</h2> + +<p>Несмотря на головокружительные успехи достигнутые в стилизации таблиц, у нас есть еще кое-что чем мы можем занять наше время. В следующей главе мы рассмотрим некоторые продвинутые эффекты, уже устоявшиеся (например, тени box shadows) и те которые только недавно появились в браузерах, такие как режимы наложения blend-mode и фильтры.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Styling_boxes/Borders", "Learn/CSS/Styling_boxes/Advanced_box_effects", "Learn/CSS/Styling_boxes")}}</p> + +<p> </p> + +<h2 id="В_этом_блоке">В этом блоке</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Styling_boxes/Box_model_recap">Box model recap</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_boxes/Backgrounds">Backgrounds</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_boxes/Borders">Borders</a></li> + <li><a href="/ru/docs/Learn/CSS/Styling_boxes/Styling_tables">Стилизация таблиц</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_boxes/Advanced_box_effects">Advanced box effects</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_boxes/Creating_fancy_letterheaded_paper">Creating fancy letterheaded paper</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_boxes/A_cool_looking_box">A cool looking box</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/css/building_blocks/the_box_model/index.html b/files/ru/learn/css/building_blocks/the_box_model/index.html new file mode 100644 index 0000000000..f0a09df9f5 --- /dev/null +++ b/files/ru/learn/css/building_blocks/the_box_model/index.html @@ -0,0 +1,372 @@ +--- +title: Модель коробки +slug: Learn/CSS/Building_blocks/The_box_model +tags: + - Границы + - Новичку +translation_of: Learn/CSS/Building_blocks/The_box_model +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Combinators", "Learn/CSS/Building_blocks/Backgrounds_and_borders", "Learn/CSS/Building_blocks")}}</div> + +<div>Каждый элемент в CSS заключён в коробку (английское "<em>box</em>") и понимание поведения этих коробок — это ключ к умению создавать макеты с помощью CSS, то есть выстраивать одни элементы относительно других элементов. В этом уроке мы рассмотрим надлежащим образом <em>коробочную модель</em> CSS, так, чтобы вы могли решать более сложные здачи построения макетов, понимая, как она работает, и терминологию, которая к ней относится.</div> + +<div></div> + +<table class="learn-box standard-table" style="height: 364px; width: 510px;"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td> + <p>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">установка базового ПО</a>, базовые знания о <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работе с файлами</a>, основы HTML (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>) и понимание работы CSS (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>.)</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Узнать как работает коробочная модель CSS, из чего она состоит и как переключиться на альтернативную модель.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Блочные_и_строчные_коробки">Блочные и строчные коробки</h2> + +<p>В CSS мы, говоря упрощённо, имеем два типа коробок — <strong>блочные</strong> и <strong>строчные</strong>. Эти характеристики относятся к поведению коробки в терминах потока страницы и относительно других коробок на странице.</p> + +<p>Если коробка определена как блочная, то она будет вести себя следующим образом:</p> + +<ul> + <li>Начнётся с новой строки.</li> + <li>Будет расширяться вдоль строки таким образом, чтобы заполнить всё пространство, доступное в её контейнере. В большинстве случаев это означает, что коробка станет такой же ширины, как и её контейнер, заполняя 100% доступного пространства.</li> + <li>Будет признавать свойства {{cssxref("width")}} и {{cssxref("height")}}.</li> + <li>Внешние и внутренние отступы, граница будут отодвигать от неё другие элементы.</li> +</ul> + +<p>Если не изменить намеренно тип отображения на строчный, то такие элементы, как заголовки (например, <code><h1></code>) и <code><p></code>, все используют <code>block</code> как свой внешний тип отображения по умолчанию.</p> + +<p>Если коробка имеет внешний тип отображения <code>inline</code>, то:</p> + +<ul> + <li>Она не будет занимать новую строку.</li> + <li>Свойства {{cssxref("width")}} и {{cssxref("height")}} не будут применяться.</li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Вертикальные внешние и внутренние отступы, границы будут применяться, но не </span></span>будут отодвигать другие строчные коробки<span class="tlid-translation translation" lang="ru"><span title="">.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Горизонтальные внешние и внутренние отступы, границы будут применяться и </span></span>будут отодвигать другие строчные коробки<span class="tlid-translation translation" lang="ru"><span title="">.</span></span></li> +</ul> + +<p>Элемент <code><a></code>, используемый для ссылок, <code><span></code>, <code><em></code> и <code><strong></code> — всё это примеры элементов, которые будут отображаться в линию по умолчанию.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Тип коробки, применяемый к элементу, определяется значениями свойства</span></span> {{cssxref("display")}}, такими как <code>block</code> и <code>inline</code>, и относится к <strong>внешнему</strong> значению <code>display</code>.</p> + +<h2 id="Экскурс_внутренний_и_внешний_типы_отображения">Экскурс: внутренний и внешний типы отображения</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Здесь следует объяснить, что такое <strong>внутренние</strong> и <strong>внешние</strong> типы отображения.</span> <span title="">Как уже говорилось выше, коробки в CSS имеют <em>внешний</em> тип отображения, который определяет, блочная она или строчная.</span></span></p> + +<p>Коробки также имеют <em>внутренний</em> тип отображения, который определяет расположение элементов внутри неё. По умолчанию, элементы внутри коробки располагаются в <strong><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/CSS_layout/%D0%9D%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA">нормальном потоке</a></strong>, что означает, что они ведут себя так же, как и любые другие блочные или строчные элементы (как описано выше).</p> + +<p>Однако, мы можем изменить внутренний тип отображения, используя такие значения <code>display</code> как <code>flex</code>. Если мы установим <code>display: flex;</code> для элемента, внешний тип отображения примет значение <code>block</code>, но внутренний тип изменится на <code>flex</code>. Любые прямые дочерние элементы этой коробки станут <em>гибкими</em> (flex) объектами и будут размещены в соответствии с правилами, изложенными в спецификации <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a>, о которой вы узнаете позже.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Чтобы узнать больше о значениях display, и о том, как работают коробки при блочном или строчном расположении, посмотрите руководство MDN <a href="https://wiki.developer.mozilla.org/ru/docs/Web/CSS/CSS_Flow_Layout/%D0%91%D0%BB%D0%BE%D1%87%D0%BD%D0%BE%D0%B5_%D0%B8_%D1%81%D1%82%D1%80%D0%BE%D1%87%D0%BD%D0%BE%D0%B5_%D1%80%D0%B0%D0%B7%D0%BC%D0%B5%D1%89%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_%D0%BD%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%BC_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B5">Блочное и cтрочное расположение</a>.</p> +</div> + +<p>Когда вы перейдёте к более подробному изучению CSS вёрстки, вы встретите <code>flex</code>, и другие внутренние значения, которые могут иметь ваши элементы, например <code><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/CSS_layout/Grids">grid</a></code>.</p> + +<p>Тем не менее, блочное и строчное расположение, это поведение web-элементов по умолчанию — как было сказано выше, это иногда называют <em>нормальным потоком (normal flow)</em>, потому что при отсутствии какой-либо другой инструкций коробки имеют блочное или строчное расположение.</p> + +<h2 id="Примеры_разных_типов_отображения">Примеры разных типов отображения</h2> + +<p>Давайте продолжим и рассмотрим некоторые примеры. Ниже мы имеем три разных элемента HTML, каждый из которых имеет внешний тип отображения <code>block</code>. Первый — это абзац, который имеет обрамление, указанное в CSS. Браузер отображает его как блочный элемент, поэтому абзац начинается на новой строке, и расширяется на всю доступную ему ширину.</p> + +<p>Второй — это список, который свёрстан с использованием <code>display: flex</code>. Это устанавливает гибкое (flex) расположение для элементов внутри контейнера, однако, список сам по себе — блочный элемент и — как и абзац — расширяется на всю ширину контейнера и начинается с новой строки.</p> + +<p>Ниже у нас есть абзац блочного типа, внутри которого есть два элемента <code><span></code>. Эти элементы по умолчанию имеют тип <code>inline</code>, однако один из элементов имеет класс block, для которого мы установили <code>display: block</code>.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/block.html", '100%', 1000)}} </p> + +<p>Мы можем видеть, как строчные элементы (<code>inline)</code> ведут себя в следующем примере. Элементы <code><span></code> в первом абзаце строчные по умолчанию и поэтому не приводят к разрыву строки.</p> + +<p>Мы также имеем элемент <code><ul></code>, для которого установлено <code>display: inline-flex</code>, что создаёт строчную коробку вокруг нескольких flex-объектов.</p> + +<p>Наконец, у нас есть два абзаца, для которых установлено <code>display: inline</code>. И строчный f<span class="tlid-translation translation" lang="ru"><span title="">lex-контейнер, и абзацы располагаются вместе на одной строке, а не начинаются каждый с новой строки, как они отображались бы, будучи элементами блочного уровня.</span></span></p> + +<p><strong>В примере вы можете заменить <code>display: inline</code> на <code>display: block</code> или <code>display: inline-flex</code> на <code>display: flex</code> для переключения между этими двумя режимами отображения.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/inline.html", '100%', 1000)}} </p> + +<p>Позже в этих уроках вы встретите такое понятие как гибкая (flex) вёрстка; главное, что нужно запомнить сейчас, это то, что изменение значения свойства <code>display</code> может изменить внешний тип отображения элемента на блочный или строчный, что меняет способ его отображения относительно других элементов в макете. </p> + +<p>В оставшейся части урока мы сосредоточимся на внешнем типе отображения.</p> + +<h2 id="Что_такое_модель_коробки_CSS">Что такое модель коробки CSS?</h2> + +<p>Полностью блочная модель в CSS применяется к блочным элементам, строчные элементы используют не все свойства, определенные блочной моделью. Модель определяет, как разные части элемента — поля, границы, отступы и содержимое — работают вместе, чтобы создать объект, который вы можете увидеть на странице. Чтобы добавить дополнительную сложность элементу, используются стандартные и альтернативные блочные модели.</p> + +<h3 id="Составляющие_элемента">Составляющие элемента</h3> + +<p>Составляя блочный элемент в CSS мы имеем:</p> + +<ul> + <li><strong>Поле содержимого</strong>: Область где отображается ваш контент, размер которой можно изменить с помощью таких свойств, как {{cssxref("width")}} и {{cssxref("height")}}.</li> + <li><strong>Поле внутреннего отступа</strong>: отступы располагаются вокруг содержимого, как пустое пространство; их размер контролируется с помощью {{cssxref("padding")}} и связанных свойств.</li> + <li><strong>Рамка границы</strong>: рамка оборачивает содержимое и внутренние отступы. Её размер и стиль можно контролировать с помощью {{cssxref("border")}} и связанных свойств.</li> + <li><strong>Поле внешнего отступа</strong>: внешний слой, включающий в себя содержимое, внутренний отступ и границы, представляет собой пространство между текущим и другими элементами. Размер его контролируется с помощью {{cssxref("margin")}} и связанных свойств.</li> +</ul> + +<p>Рисунок ниже показывает эти области:</p> + +<p><img alt="Diagram of the box model" src="https://mdn.mozillademos.org/files/16558/box-model.png" style="height: 300px; width: 544px;"></p> + +<h3 id="Стандартная_блочная_модель_CSS">Стандартная блочная модель CSS</h3> + +<p>В стандартной блочной модели, если указать элементу атрибуты <code>width</code> и <code>height</code>, это определит ширину и высоту <em>содержимого элемента</em>. Любые отступы и границы затем добавляются к этой ширине и высоте, для получения общего размера элемента. Это показано на изображении ниже.</p> + +<p>Предположим, что в элементе есть следующий CSS определяющий <code>width</code>, <code>height</code>, <code>margin</code>, <code>border</code>, и <code>padding</code>:</p> + +<pre class="brush: css notranslate">.box { + width: 350px; + height: 150px; + margin: 10px; + padding: 25px; + border: 5px solid black; +} +</pre> + +<p>Пространство, занимаемое нашим объектом с использованием стандартной блочной модели, на самом деле будет равно по ширине 410px (350 + 25 + 25 + 5 + 5), и по высоте 210px (150 + 25 + 25 + 5 + 5), поскольку отступы и границы добавляются к размерам поля содержимого.</p> + +<p><img alt="Showing the size of the box when the standard box model is being used." src="https://mdn.mozillademos.org/files/16559/standard-box-model.png" style="height: 300px; width: 500px;"></p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Внешний отступ не считается в фактическом размере объекта. Конечно, он влияет на общее пространство, занимаемое объектом на странице, но только на внешнее пространство. Область элемента заканчивается на границах — она не распространяется за них.</p> +</div> + +<h3 id="Альтернативная_блочная_модель_CSS">Альтернативная блочная модель CSS</h3> + +<p>Вы можете подумать, что довольно неудобно добавлять границы и отступы, чтобы получить реальный размер элемента, и окажетесь правы! По этой причине, спустя некоторое время после стандартной блочной модели, в CSS была введена альтернативная блочная модель. При использовании альтернативной модели, любая ширина – это ширина видимой части элемента на странице, поэтому ширина области содержимого будет равна общей ширине минус ширина границы и внутреннего отступа. Тот же CSS, который использовался выше, даст следующий результат (ширина = 350px, высота = 150px).</p> + +<p><img alt="Showing the size of the box when the alternate box model is being used." src="https://mdn.mozillademos.org/files/16557/alternate-box-model.png" style="height: 240px; width: 440px;"></p> + +<p>По умолчанию браузеры используют стандартную блочную модель. Если вы хотите использовать альтернативную блочную модель для элемента, установивите для него свойство <code>box-sizing: border-box</code>. С помощь этого вы говорите браузеру о том, что граница элемента определяется любыми размерами которые вы устанавливаете.</p> + +<pre class="brush: css notranslate"><code>.box { + box-sizing: border-box; +} </code></pre> + +<p>Если вы хотите, чтобы все ваши элементы использовали альтернативную блочную модель, что является распространенным выбором среди разработчиков, установите свойство <code>box-sizing</code> для элемента <code><html></code>, затем настройте все элементы для наследования этого значения (inherit), как показано на фрагменте ниже. Если вы хотите понять, что стоит за этим, смотрите статью <a href="https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/">the CSS Tricks article on box-sizing</a>.</p> + +<pre class="brush: css notranslate"><code class="language-css"><span class="selector token">html</span> <span class="punctuation token">{</span> + <span class="property token">box-sizing</span><span class="punctuation token">:</span> border-box<span class="punctuation token">;</span> +<span class="punctuation token">}</span> +<span class="selector token">*, *<span class="pseudo-element token">::before</span>, *<span class="pseudo-element token">::after</span></span> <span class="punctuation token">{</span> + <span class="property token">box-sizing</span><span class="punctuation token">:</span> inherit<span class="punctuation token">;</span> +<span class="punctuation token">}</span></code></pre> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: <span class="tlid-translation translation" lang="ru"><span title="">Интересный факт - Internet Explorer по умолчанию использовал альтернативную блочную модель без доступного механизма для переключения.</span></span></p> +</div> + +<h2 id="Играем_с_блочными_моделями">Играем с блочными моделями</h2> + +<p>В примере ниже, вы можете видеть 2 объекта. Оба имеют класс <code>.box</code>, который дает им одинаковые параметры <code>width</code>, <code>height</code>, <code>margin</code>, <code>border</code>, и <code>padding</code>. Единственное различие в том, что второй объект объявлен по альтернативной блочной модели.</p> + +<p><strong>Можете ли вы изменить размер второго объекта (добавляя CSS в класс <code>.alternate)</code> чтобы ишрина и высота совпали с первым блоком?</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/box-models.html", '100%', 1000)}} </p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Вы можете найти решение этой задачи <a href="https://github.com/mdn/css-examples/blob/master/learn/solutions.md#the-box-model">здесь</a>.</p> +</div> + +<h3 id="Использование_инструментов_разработчика_в_браузере_для_просмотра_блочных_моделей">Использование инструментов разработчика в браузере для просмотра блочных моделей</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Инструменты разработчика вашего браузера могут значительно облегчить понимание блочной модели.</span> <span title="">Если вы проверяете элемент в инструментах разработчика Firefox, вы можете увидеть размер элемента, а также его поле, отступы и границу.</span> <span title="">Проверка элемента таким способом </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> отличный способ выяснить, действительно ли размер вашего блока такой, какой вы думаете!</span></span></p> + +<p><img alt="Inspecting the box model of an element using Firefox DevTools" src="https://mdn.mozillademos.org/files/16560/box-model-devtools.png" style="height: 683px; width: 1150px;"></p> + +<div class="blockIndicator note"> +<p><strong>Примечание: </strong>Информацию об инструментах разработчика вы можете получить по <a href="https://developer.mozilla.org/ru/docs/Tools">этой ссылке.</a></p> +</div> + +<h2 id="Поля_отступы_и_границы"><span class="tlid-translation translation" lang="ru"><span title="">Поля, отступы и границы</span></span></h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы уже видели свойства {{cssxref ("margin")}}, {{cssxref ("padding")}} и {{cssxref ("border")}} в работе в приведенном выше примере.</span> <span title="">Свойства, используемые в этом примере, являются общими и позволяют нам устанавливать все четыре стороны поля одновременно.</span> <span title="">Эти параметры также имеют эквивалентные свойства, которые позволяют индивидуально управлять разными сторонами поля.</span><br> + <br> + <span title="">Давайте рассмотрим эти свойства более подробно.</span></span></p> + +<h3 id="Поле_внешнего_отступа_margin">Поле внешнего отступа (margin)</h3> + +<p>Margin это невидимое пространство вокруг вашего элемента. Оно отталкивает другие элементы от него. Margin может быть как положительным, так и отрицательным. Негативное значение для внешнего отступа может привести к перекрытию некоторых элементов страницы. Независимо от того, используете ли вы стандартную или альтернативную блочную модель, мargin всегда добавляется после расчета размера видимого бокса.</p> + +<p>Мы можем контролировать все поля элемента сразу, используя свойство {{cssxref ("margin")}}, или каждую сторону индивидуально, используя эквивалентные полные свойства:</p> + +<ul> + <li>{{cssxref("margin-top")}}</li> + <li>{{cssxref("margin-right")}}</li> + <li>{{cssxref("margin-bottom")}}</li> + <li>{{cssxref("margin-left")}}</li> +</ul> + +<p><strong>В примере ниже, попробуйте изменить значение margin чтобы увидеть как блок смещается, создавая или удаляя пространство (если вводить отрицательные значения margin) между этим элементом и элементом его содержащим.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/margin.html", '100%', 1000)}} </p> + +<h4 id="Cхлопывание_margin"> Cхлопывание margin </h4> + +<p>Ключевой момент, который нужно понимать в отношении внешних отступов (margin), это концепция схлопывания полей. Если у вас есть два элемента, поля которых соприкасаются, и оба значения margin положительные, то эти значения будут объединены в одно, равное большему из двух значений. А если одно или оба зничения негативны, то сумма отрицательнных значений будет вычтена из общей суммы.</p> + +<p>В примере ниже имеется два абзаца. Первый абзац имеет ширину <code>margin-bottom</code> 50 пикселей. Ширина второго параграфа — <code>margin-top</code> 30 пикселей. Поля схлопываются так, что в результате margin между двумя блоками составляет 50 пикселей, а не сумму значений отдельных значений margin.</p> + +<p><strong>Вы можете проверить это устанавливая значения <code>margin-top</code> . Видимая граница между двумя параграфами не изменится — если сохранять значение в 50 пикселей в <code>bottom-margin</code> первого параграфа. Если вы установите значение -10px, то увидите, что margin становится 40px — происходит вычитание из положительного значения первого параграфа.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/margin-collapse.html", '100%', 1000)}} </p> + +<p>Существует ряд правил, которые определяют, когда поля уменьшаются, а когда нет. Для получения подробной информации см. <a href="/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing">margin collapsing</a>. Главное, что нужно сейчас помнить, — это то, что происходит схлопывание полей. Если вы создаете пространство с полями и не получаете ожидаемого результата, вероятно, именно это и происходит. </p> + +<h3 id="Границы">Границы</h3> + +<p>Граница распологается между margin и padding блочного элемента. Если вы используете стандартную блочную модель, размер границы прибавляется к значениям <code>width</code> и <code>height</code> бокса. Если вы используете альтернативную блочную модель, то размер границы уменьшает поле контента данного блока, так как значения границы входит в значения <code>width</code> и <code>height</code>.</p> + +<p>Для слилизации границ существует большое количество различных свойств — имеется четыре границы, и каждая из них имеет свой стиль, ширину и цвет, которыми мы можем манипулировать.</p> + +<p>Вы можете установить ширину, стиль или цвет всех четырех границ сразу используя {{cssxref("border")}} свойства.</p> + +<p>Чтобы установить индивидуальные свойства для каждой из четырех сторон вы можете использовать:</p> + +<ul> + <li>{{cssxref("border-top")}}</li> + <li>{{cssxref("border-right")}}</li> + <li>{{cssxref("border-bottom")}}</li> + <li>{{cssxref("border-left")}}</li> +</ul> + +<p>Для утановки ширины, стиля или цвета всех границ используйте:</p> + +<ul> + <li>{{cssxref("border-width")}}</li> + <li>{{cssxref("border-style")}}</li> + <li>{{cssxref("border-color")}}</li> +</ul> + +<p>Чтобы установить ширину, стиль или цвет для каждой границы индивидуально, вы можете использовать следующие свойства:</p> + +<ul> + <li>{{cssxref("border-top-width")}}</li> + <li>{{cssxref("border-top-style")}}</li> + <li>{{cssxref("border-top-color")}}</li> + <li>{{cssxref("border-right-width")}}</li> + <li>{{cssxref("border-right-style")}}</li> + <li>{{cssxref("border-right-color")}}</li> + <li>{{cssxref("border-bottom-width")}}</li> + <li>{{cssxref("border-bottom-style")}}</li> + <li>{{cssxref("border-bottom-color")}}</li> + <li>{{cssxref("border-left-width")}}</li> + <li>{{cssxref("border-left-style")}}</li> + <li>{{cssxref("border-left-color")}}</li> +</ul> + +<p><strong>В примере ниже мы использовали различные сокращенные и длинные способы создания границ. Поиграйте с различными свойствами чтобы проверить как вы поняли принципы их работы. MDN страницы свойств границ дадут вам информацию о различных стилях, которые вы можете использовать.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/border.html", '100%', 1000)}} </p> + +<h3 id="Padding">Padding</h3> + +<p>Padding расположен между границей и областью контента блока. В отличии от внешних отступов (margin), вы не можете использовать отрицательные значения для padding, поэтому значения должны быть положительными или равными 0. Любой, примененный к вашим элементам фон, будет отображаться под областью padding, и поэтому он обычно используется чтобы отодвинуть контент от границы.</p> + +<p>Вы можете контролировать значение padding для всех сторон элемента, используя {{cssxref("padding")}} свойство, или для каждой стороны индивидуально, используя используя следующие свойства:</p> + +<ul> + <li>{{cssxref("padding-top")}}</li> + <li>{{cssxref("padding-right")}}</li> + <li>{{cssxref("padding-bottom")}}</li> + <li>{{cssxref("padding-left")}}</li> +</ul> + +<p><strong>Если вы измените значения padding в классе <code>.box</code> в примере ниже, вы можете увидеть что это изменяет положение текста относительно поля.</strong></p> + +<p><strong>Вы также можете изменить padding в классе <code>.container,</code> который создает пространство между контейнером и боксом. Padding может быть изменен для любого элемента, и создать пространство между этой и любой другой границей внутри элемента.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/padding.html", '100%', 800)}} </p> + +<h2 id="Блочная_модель_и_строчные_элементы">Блочная модель и строчные элементы</h2> + +<p>Всё, сказанное ранее, полностью применимо к блочным элементам. Некоторые из свойств могут быть также применены и к строчным (inline) элементам, например, элемент, создаваемый с помощью <code><span></code>.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В приведенном ниже примере у нас есть <span> внутри абзаца, и мы применили к нему </span></span><code>width</code>, <code>height</code>, <code>margin</code>, <code>border</code> и <code>padding</code><span class="tlid-translation translation" lang="ru"><span title="">.</span> <span title="">Вы можете видеть, что ширина и высота игнорируются.</span> <span title="">Вертикальные поля, отступы и границы соблюдаются, но они не изменяют отношения другого содержимого к нашему строчному элементу, и поэтому отступ и граница перекрывают другие слова в абзаце.</span> <span title="">Горизонтальные отступы, поля и границы соблюдаются и заставят другой контент отодвинуться от нашего элемента.</span></span></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/inline-box-model.html", '100%', 800)}} </p> + +<h2 id="Использование_display_inline-block">Использование display: inline-block</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Существует особое значение <code>display</code>, которое обеспечивает золотую середину между </span></span><code>inline</code><span class="tlid-translation translation" lang="ru"><span title=""> и </span></span><code>block</code><span class="tlid-translation translation" lang="ru"><span title="">.</span> <span title="">Это полезно в ситуациях, когда вы не хотите, чтобы элемент разбивался на новую строку, но нужно, чтобы он использовал </span></span><code>width</code><span class="tlid-translation translation" lang="ru"><span title=""> и </span></span><code>height</code><span class="tlid-translation translation" lang="ru"><span title=""> и избегал перекрытия, показанного выше.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Элемент с <code>display: inline-block</code> содержит ряд свойств блочного элемента, о которых мы уже знаем:</span></span></p> + +<ul> + <li><span class="tlid-translation translation" lang="ru"><span title="">Применяются свойства </span></span><code>width</code><span class="tlid-translation translation" lang="ru"><span title=""> и </span></span><code>height</code><span class="tlid-translation translation" lang="ru"><span title="">.</span></span></li> + <li>Использование <code>padding</code><span class="tlid-translation translation" lang="ru"><span title="">, </span></span><code>margin</code><span class="tlid-translation translation" lang="ru"><span title=""> и </span></span><code>border</code><span class="tlid-translation translation" lang="ru"><span title=""> приведёт к тому, что другие элементы будут отодвинуты от нашего элемена.</span></span></li> +</ul> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Он не прервётся на новую строку и станет больше, чем его содержимое, только если вы явно не укажите свойства </span></span><code>width</code><span class="tlid-translation translation" lang="ru"><span title=""> и </span></span><code>height</code><span class="tlid-translation translation" lang="ru"><span title="">.</span></span></p> + +<p><strong><span class="tlid-translation translation" lang="ru"><span title="">В следующем примере мы добавили <code>display: inline-block</code> к нашему элементу <code><span></code>.</span> <span title="">Попробуйте изменить это на <code>display: block</code> или полностью удалить строку, чтобы увидеть разницу.</span></span></strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/inline-block.html", '100%', 800)}} </p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Это может быть полезно, когда вы хотите создать ссылку с большой областью попадания, добавив </span></span><code>padding</code><span class="tlid-translation translation" lang="ru"><span title="">.</span> </span><code><a></code><span class="tlid-translation translation" lang="ru"><span title=""> - это строчный элемент, такой же как <code><span></code>;</span> <span title="">вы можете использовать <code>display: inline-block</code>, чтобы разрешить установку отступов, что упростит пользователю переход по ссылке.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы довольно часто видите это на панели навигации.</span> <span title="">Приведенная ниже навигация отображается в виде строки с использованием flexbox, и мы добавили отступы к элементу <code><a></code>, также мы хотим чтобы изменялся </span></span><code>background-color</code><span class="tlid-translation translation" lang="ru"><span title=""> при наведении курсора на <code><a></code>.</span> <span title="">Отступы перекрывают границу элемента <code><ul></code>.</span> <span title="">Это потому, что <code><a></code> является строчным элементом.</span></span></p> + +<p><strong><span class="tlid-translation translation" lang="ru"><span title="">Добавьте в правило <code>display: inline-block</code> с помощью селектора <code>.links-list a</code>, и вы увидите, как он решает эту проблему, заставляя другие элементы соблюдать отступы.</span></span></strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/inline-block-nav.html", '100%', 600)}} </p> + +<h2 id="Проверьте_свои_навыки!"><span class="tlid-translation translation" lang="ru"><span title="">Проверьте свои навыки!</span></span></h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В этой статье мы рассмотрели многое, но можете ли вы вспомнить самую важную информацию?</span> <span title="">Вы можете найти дополнительные тесты, чтобы убедиться, что вы усвоили эту информацию, прежде чем двигаться дальше - см. <a href="/ru/docs/Learn/CSS/Building_blocks/Selectors/Box_Model_Tasks">Проверка своих навыков: блочная модель</a>.</span></span></p> + +<h2 id="Заключение">Заключение</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Это большая часть того, что вам нужно знать о блочной модели.</span> <span title="">Возможно, вы захотите вернуться к этому уроку в будущем, если когда-нибудь обнаружите, что не понимаете, насколько большие блоки в вашем макете.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В следующем уроке мы рассмотрим, как можно использовать <a href="/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">фон и границы</a>, чтобы сделать ваши простые блоки более интересными.</span></span></p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Combinators", "Learn/CSS/Building_blocks/Backgrounds_and_borders", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B">Селекторы CSS</a> + <ul> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Type_Class_and_ID_Selectors">Селекторы типа, класса и ID</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Attribute_selectors">Селекторы атрибута</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">Псевдоклассы и псевдоэлементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Combinators">Комбинаторы</a></li> + </ul> + </li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/The_box_model">Модель коробки</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Фон и границы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Обработка разных направлений текста</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Overflowing_content">Переполнение содержимого</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Values_and_units">Значения и единицы измерения</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Изменение размеров в CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Элементы изображений, форм и медиа-элементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Styling_tables">Стилизация таблиц</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Organizing">Организация вашей CSS</a><a href="/ru/docs/Learn/CSS/Building_blocks/Organizing"> </a></li> +</ol> + +<div id="gtx-anchor" style="position: absolute; left: 20px; top: 9989px; width: 532.385px; height: 68.667px;"></div> + +<div class="jfk-bubble gtx-bubble"> +<div class="jfk-bubble-content-id" id="bubble-11"> +<div id="gtx-host" style="max-width: 400px;"></div> +</div> + +<div class="jfk-bubble-closebtn-id jfk-bubble-closebtn"></div> + +<div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowdown" style="left: 246.5px;"> +<div class="jfk-bubble-arrowimplbefore"></div> + +<div class="jfk-bubble-arrowimplafter"></div> +</div> +</div> diff --git a/files/ru/learn/css/building_blocks/values_and_units/index.html b/files/ru/learn/css/building_blocks/values_and_units/index.html new file mode 100644 index 0000000000..7aa0744ad9 --- /dev/null +++ b/files/ru/learn/css/building_blocks/values_and_units/index.html @@ -0,0 +1,394 @@ +--- +title: Значения свойств CSS +slug: Learn/CSS/Building_blocks/Values_and_units +translation_of: Learn/CSS/Building_blocks/Values_and_units +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Overflowing_content", "Learn/CSS/Building_blocks/Sizing_items_in_CSS", "Learn/CSS/Building_blocks")}}</div> + +<p>Каждое свойство используемое в CSS имеет значение или набор значений которые допустимы для этого свойства, и изучение страниц MDN со свойствами поможет вам понять какие значения валидны для того или иного свойства. В этом уроке мы рассмотрим некоторые наиболее общие значения и единицы в использовании.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">basic software installed</a>, basic knowledge of <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">working with files</a>, HTML basics (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), and an idea of how CSS works (study <a href="/en-US/docs/Learn/CSS/First_steps">CSS first steps</a>.)</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To learn about the different types of values and units used in CSS properties.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_значение_CSS">Что такое значение CSS?</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В спецификациях CSS и на страницах свойств здесь в MDN вы сможете определять (узнавать) значения, потому как они будут заключены в угловые скобки, например </span></span><code><a href="/en-US/docs/Web/CSS/color_value"><color></a></code> или <code><a href="/en-US/docs/Web/CSS/length"><length></a></code><a href="/en-US/docs/Web/CSS/length">. </a>Если вы видите значение <code><color></code> как действительное для определенного свойства это значит что вы можете использовать любой валидный цвет в качестве значение для этого свойства, как перечисленно на странице <code><a href="/en-US/docs/Web/CSS/color_value"><color></a></code><a href="/en-US/docs/Web/CSS/color_value">.</a></p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You'll also see CSS values referred to as <em>data types</em>. The terms are basically interchangeable — when you see something in CSS referred to as a data type, it is really just a fancy way of saying value.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Yes, CSS values tend to be denoted using angle brackets, to differentiate them from CSS properties (e.g. the {{cssxref("color")}} property, versus the <a href="/en-US/docs/Web/CSS/color_value"><color></a> data type). You might get confused between CSS data types and HTML elements too, as they both use angle brackets, but this is unlikely — they are used in very different contexts.</p> +</div> + +<p>В следующем примере мы установили цвет нашего заголовка используя ключевое слово и фон используя функцию <code>rgb()</code>:</p> + +<pre class="brush: css notranslate"><code>h1 { + color: black; + background-color: rgb(197,93,161); +} </code> +</pre> + +<p>Значение в CSS это путь определения коллекции допустимых под-значений. То есть если вы видите <code><color></code> как примененный, то вам не надо озадачиваться какой из разных типов значения цвета может быть использован — ключевое слово, hex значение, функция <code>rgb()</code> и т.д. Вы можете воспользоваться <em>любым </em>доступным значением <code><color></code> при условии, что они поддерживаются вашим браузером. Страницы для всех значений на MDN дадут вам информацию о поддержке браузеров. Например, если вы посмотрите на страницу <code><a href="/en-US/docs/Web/CSS/color_value"><color></a></code> то вы увидите раздел совместимости браузеров в котором перечислены различные типы значений цвета и их поддержка.</p> + +<p>Давайте посмотрим на некоторые типы значений и единиц с примерами чтобы вы могли опробовать различные возможные значения, с которыми вы можете часто сталкиваться.</p> + +<h2 id="Числа_длины_и_проценты">Числа, длины и проценты</h2> + +<p>Существуют различные типы числовых данных, которые вы можете использовать в CSS. Следующие типы классифицируются как числовые:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Тип данных</th> + <th scope="col">Описание</th> + </tr> + </thead> + <tbody> + <tr> + <td><code><a href="/en-US/docs/Web/CSS/integer"><integer></a></code></td> + <td><code><integer></code> (целое число) — целое число такое как <code>1024</code> или <code>-55</code>.</td> + </tr> + <tr> + <td><code><a href="/en-US/docs/Web/CSS/number"><number></a></code></td> + <td> + <p><code><number></code> (число) представляет десятичное число — оно может иметь, а может и не иметь десятичную точку с факториальным компонентом, например <code>0.255</code>, <code>128</code>, или <code>-1.2</code>.</p> + </td> + </tr> + <tr> + <td><code><dimension></code></td> + <td> + <p><code><dimension></code> (измерение) это — <code><number></code> (число) с единицей измерения, прикрепленной к нему, например <code>45deg</code>, <code>5s</code>, или <code>10px</code>. <code><dimension></code> — это зонт категорий, включающих в себя типы <code><a href="/en-US/docs/Web/CSS/length"><length></a></code>, <code><a href="/en-US/docs/Web/CSS/angle"><angle></a></code>, <code><a href="/en-US/docs/Web/CSS/time"><time></a></code>, и <code><a href="/en-US/docs/Web/CSS/resolution"><resolution></a></code><a href="/en-US/docs/Web/CSS/resolution"> </a>(длина, угол, время и разрешение)<a href="/en-US/docs/Web/CSS/resolution">. </a></p> + </td> + </tr> + <tr> + <td><code><a href="/en-US/docs/Web/CSS/percentage"><percentage></a></code></td> + <td> + <p><code><percentage></code> (проценты) представляют собой долю некоторого другого значения, например <code>50%</code>. Процентные значения всегда относительны по отношению к другому количеству, например длина элемента относительна к длине ее родительского элемента.</p> + </td> + </tr> + </tbody> +</table> + +<h3 id="Длины">Длины</h3> + +<p>Числовой тип, с которым вы будете сталкиваться чаще всего это <code><length></code> (длина), например <code>10px</code> (пиксели) или <code>30em</code>. Существует два типа длин используемых в CSS — относительные и абсолютные. Важно знать разницу для того, чтобы понимать, насколько большими станут вещи.</p> + +<h4 id="Абсолютные_единицы_длины">Абсолютные единицы длины</h4> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Ниже приведены все единицы абсолютной длины </span></span>— они не являются относительными к чему-либо и обычно считаются всегда одинакового размера.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Единицы</th> + <th scope="col">Название</th> + <th scope="col">Эквивалент</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>cm</code></td> + <td>Centimeters/Сантиметры</td> + <td>1cm = 96px/2.54</td> + </tr> + <tr> + <td><code>mm</code></td> + <td>Millimeters/Миллиметры</td> + <td>1mm = 1/10th of 1cm</td> + </tr> + <tr> + <td><code>Q</code></td> + <td>Quarter-millimeters/Четверть-мм</td> + <td>1Q = 1/40th of 1cm</td> + </tr> + <tr> + <td><code>in</code></td> + <td>Inches/Дюймы</td> + <td>1in = 2.54cm = 96px</td> + </tr> + <tr> + <td><code>pc</code></td> + <td>Picas/Пики</td> + <td>1pc = 1/16th of 1in</td> + </tr> + <tr> + <td><code>pt</code></td> + <td>Points/Точки</td> + <td>1pt = 1/72th of 1in</td> + </tr> + <tr> + <td><code>px</code></td> + <td>Pixels/Пиксели</td> + <td>1px = 1/96th of 1in</td> + </tr> + </tbody> +</table> + +<p>Большинство из этих значений больше полезны при использовании печати, чем для вывода на экран. Например, мы обычно не используем <code>cm</code> (сантиметры) на экране. Единственное значение которое вы в основном будете использовать это <code>px</code> (пиксели).</p> + +<h4 id="Единицы_относительной_длины">Единицы относительной длины</h4> + +<p>Относительные единицы длин являются относительными к чему-то еще, возможно к размеру родительского шрифта или к размеру окна просмотра. Преимущество использования относительных единиц состоит в том, что при тщательном планировании вы можете сделать так, чтобы размер текста или других элементов масштабировался <span class="tlid-translation translation" lang="ru"><span title="">относительно всего остального на странице.</span></span> Некоторые наиболее используемые единицы веб-разработки перечислены в таблице ниже.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Единица</th> + <th scope="col">Отосительна к</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>em</code></td> + <td>Размер шрифта родительского элемента.</td> + </tr> + <tr> + <td><code>ex</code></td> + <td>x-высота шрифта элемента.</td> + </tr> + <tr> + <td><code>ch</code></td> + <td><span class="tlid-translation translation" lang="ru"><span title="">Предварительная мера (ширина) глифа "0" шрифта элемента.</span></span></td> + </tr> + <tr> + <td><code>rem</code></td> + <td>Размер шрифта корневого элемента.</td> + </tr> + <tr> + <td><code>lh</code></td> + <td><span class="tlid-translation translation" lang="ru"><span title="">Высота строки элемента.</span></span></td> + </tr> + <tr> + <td><code>vw</code></td> + <td>1% от ширины окна просмотра.</td> + </tr> + <tr> + <td><code>vh</code></td> + <td>1% от высоты окна просмотра.</td> + </tr> + <tr> + <td><code>vmin</code></td> + <td>1% от меньшего измерения ширины окна просмотра.</td> + </tr> + <tr> + <td><code>vmax</code></td> + <td>1% от большего измерения ширины окна просмотра.</td> + </tr> + </tbody> +</table> + +<h4 id="Изучение_на_примере">Изучение на примере</h4> + +<p>В примере ниже вы можете увидеть, как некоторые относительные и абсолютные единицы длин ведут себя. Первый блок имеет {{cssxref("width")}} (ширину) установленную в пикселях. Как абсолютная единица эта ширина будет оставаться такой же неважно что еще измениться.</p> + +<p>Второй блок имеет ширину, установленную в единицах <code>vw</code> (ширина окна просмотра). Это значение относительно к ширине окна просмотра и таким образом 10vw это 10 процентов от ширины окна просмотра. Если вы измените ширину окна вашего браузера, размер блока должен измениться, однако этот пример встроен в страницу с использованием <code><a href="/en-US/docs/Web/HTML/Element/iframe"><iframe></a></code>, поэтому это не сработает. Для того чтобы увидеть это в действии вы должны <a href="https://mdn.github.io/css-examples/learn/values-units/length.html">открыть этот пример в отдельной вкладке браузера</a>.</p> + +<p>Третий блок использует единицы <code>em</code>. Они относительны к размеру шрифта. Я установил размер шрифта <code>1em</code> для содержимого {{htmlelement("div")}}, который имеет класс <code>.wrapper</code>. Измените это значение на <code>1.5em</code> и вы увидите что, размер шрифта всех этих элементов увеличится, но только последний объект станет шире, поскольку его ширина относительна к тому размера шрифта.</p> + +<p>После выполнения инструкция выше, попробуйте поиграть со значениями и посмотрите, что у вас получится.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/length.html", '100%', 820)}}</p> + +<h4 id="em_и_rem">em и rem</h4> + +<p><code>em</code> и <code>rem</code> — две относительные длины, с которыми вы вероятное всего сталкиваетесь чаще при разметке чего-либо от блоков до текста. Стоит понимать как они работают, понимать различия между ними, особенно когда вы начинаете переходить к более сложным темам как <a href="/en-US/docs/Learn/CSS/Styling_text">стилизация текста</a> или <a href="/en-US/docs/Learn/CSS/CSS_layout">разметка CSS</a>. Приведенный ниже пример показывает это.</p> + +<p>HTML это набор вложенных списков — у нас имеется три списка в общей сложности и оба примера имеют одинаковый HTML. Единственное различие в том, что первый имеет класс <em>ems, </em>а второй класс <em>rems</em>.</p> + +<p>Чтобы начать, мы установили 16px для размера шрифта элемента <code><html></code>.</p> + +<p><strong>Повторим, единица em означает "размер шрифта родительского элемента"</strong>. Элементы {{htmlelement("li")}} внутри {{htmlelement("ul")}} с классом <code>ems</code> получают свои размеры от своего родителя. Так, каждый последующий уровень вложения становится прогрессивно больше, так как каждый имеет свой размер шрифта установленный на <code>1.3em</code> — 1.3 раза от размера шрифта родителя.</p> + +<p><strong>Повторим, единица rem означает "размер шрифта корневого элемента"</strong> (rem значит "root em". (root - корень)). Элементы {{htmlelement("li")}} внутри {{htmlelement("ul")}} с классом <code>rems</code> получают свои размеры от корневого элемента (<code><html></code>). Это значит, что каждый последующий уровень вложения не продолжает увеличиваться.</p> + +<p>Однако, если вы измените <code>font-size</code> (размер шрифта) <code><html></code> в CSS, вы увидите что все остальное изменится относительно ему — и <code>rem</code>- и <code>em</code>-размеры текста</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/em-rem.html", '100%', 1000)}} </p> + +<h3 id="Проценты">Проценты</h3> + +<p>Во многих случаях проценты обрабатываются таким же образом, как и длина. С процентами фишка в том, что они всегда устанавливаются относительно некоторого другого значения. Например, если вы установите <code>font-size</code> элемента как проценты, то это будет процент от <code>font-size</code> родительского элемента. Если вы используете процент для значения <code>width </code>(ширина), то это будет процент от <code>width</code> родителя.</p> + +<p>В примере ниже два блока с размерами в процентах и два с размерами в пикселях имеющих одинаковые имена классов. Оба набора имеют ширину 200px и 40% соответственно.</p> + +<p>Различие в том, что второй набор блоков находится внутри обертки которая имеет ширину 400 пикселей. Второй блок шириной в 200px имеет ту же ширину что и первый, но второй 40 процентный блок теперь имеет 40% от 400px — намного уже чем первый.</p> + +<p><strong>Попробуйте изменить ширину обертки (.wrapper) или процентное значение чтобы увидеть, как это работает.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/percentage.html", '100%', 850)}} </p> + +<p>В следующем примере размер шрифта установлен в процентах. Каждый <code><li></code> имеет <code>font-size</code> 80%, поэтому элементы вложенного списка становятся прогрессивно меньше так как они наследуют свои размеры от родителя.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/percentage-fonts.html", '100%', 650)}} </p> + +<p>Обратите внимание, в то время как многие значения принимают как длину, так и проценты, существуют те, которые принимают только длину. Вы можете посмотреть какие значения допустимы на справочной странице свойств MDN. Если допустимые значения включают <code><a href="/en-US/docs/Web/CSS/length-percentage"><length-percentage></a></code>, тогда вы можете использовать и длину, и проценты. Если же допустимые значения включают только <code><length></code>, то использование процентов невозможно.</p> + +<h3 id="Числа">Числа</h3> + +<p>Некоторые значения принимают числа без каких-либо единиц измерения. Примером свойства принимающего числа без единиц измерения может служить свойство <code>opacity</code>, которое контролирует мутность элемента (настолько он прозрачен). Это свойство принимает числа между <code>0</code> (полностью прозрачное) и <code>1</code> (полностью мутное).</p> + +<p><strong>В примере ниже, попробуйте изменить значение </strong><code><strong>opacity</strong></code><strong> на различные десятичные значения между </strong><code><strong>0</strong></code><strong> и </strong><code><strong>1</strong></code><strong> и посмотрите, как блок и его содержимое становится более и/или менее мутными.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/opacity.html", '100%', 500)}} </p> + +<div class="blockIndicator note"> +<p><strong>Внимание</strong>: Когда вы используете числа в CSS в качестве значений, они не должны быть заключены в кавычки.</p> +</div> + +<h2 id="Цвет">Цвет</h2> + +<p>Существует много способов определения цвета в CSS, некоторые из которых реализованы довольно-таки недавно по сравнению с другими. Одинаковые значения цвета могут использоваться везде в CSS, определяете ли вы при этом цвет текста, цвет фона или цвет чего-либо еще.</p> + +<p>Стандартная система цветов доступная в современных компьютерах — это 24-битная система, которая позволяет отображать около 16.7 миллионов отдельных цветов через комбинацию различных красных, зеленых и синих каналов с 256 различными значениями каждого канала (256 x 256 x 256 = 16,777,216). Давайте взглянем на некоторые способы, с помощью которых мы можем определять цвет в CSS.</p> + +<div class="blockIndicator note"> +<p><strong>Внимание</strong>: В этом руководстве мы рассмотрим общие методы определения цвета, которые имеют хорошую поддержку браузерами; существуют и другие методы, но они не имеют столь же хорошей поддержки и являются менее общими.</p> +</div> + +<h3 id="Ключевые_слова_цвета">Ключевые слова цвета</h3> + +<p>Довольно часто в примерах как здесь, так и на других страницах в MDN вы будете видеть использование ключевых слов цвета, поскольку это простой и понятный способ определения цвета. Существует определенное количество этих ключевых слов и некоторые их них имеют довольно занимательные имена! Полный список вы можете посмотреть на странице значений <code><a href="/en-US/docs/Web/CSS/color_value"><color></a></code> .</p> + +<p><strong>Попробуйте поиграть с разными значениями цвета на живом примере ниже, чтобы понять больше об идее как они работают.</strong></p> + +<h3 id="Шестнадцатеричные_RGB_значения"><span class="tlid-translation translation" lang="ru"><span title="">Шестнадцатеричные</span></span> RGB значения</h3> + +<p>Следующий тип значения цвета, с которым вы сталкиваетесь вероятнее всего — это шестнадцатеричные коды. Каждое hex-значение состоит из символа решетки (#) за которым следуют 6 шестнадцатеричных чисел, каждое из которых может принимать одно из 16 значений от 0 до f (представляющая 15) — то есть <code>0123456789abcdef</code>. Каждая пара значений представляет один из каналов — красного, зеленого или синего цветов — и позволяет нам определять любой из 256 доступных значений для каждого (16 x 16 = 256).</p> + +<p>Эти значения являются немного более сложными и менее простыми для понимания, но они намного более универсальны чем ключевые слова — вы можете использовать hex-значения чтобы отобразить любой цвет, который вы хотите использовать в своей цветовой схеме.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-hex.html", '100%', 700)}} </p> + +<p><strong>И снова, попробуйте изменить значения, чтобы посмотреть, как варьируют цвета.</strong></p> + +<h3 id="RGB_и_RGBA_зачения">RGB и RGBA зачения</h3> + +<p>Третья схема, о которой мы здесь поговорим это RGB. Значения RGB это функция — <code>rgb()</code> — которой дается три параметра представляющих каналы красного, зеленого и синего значений цветов, во многом так же, как hex-значения. Отличие с RGB является то, что каждый канал представлен не двумя hex-цифрами, а десятичным числом между 0 и 255 — что отчасти проще в понимании.</p> + +<p>Давайте перепишем наш последний пример используя RGB цвета:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-rgb.html", '100%', 700)}} </p> + +<p>А также вы можете использовать цвета RGBA — что работает в точности, как и цвета RGB и то есть вы можете использовать любое значение RGB, однако существует четвертое значение, которое представляет альфа канал цвета, которое контролирует мутность. Если вы установите это значение на <code>0</code>, то это сделает цвет полностью прозрачным, тогда как <code>1</code> сделает его полностью мутным. Значения между дают вам разные уровни прозрачности.</p> + +<div class="blockIndicator note"> +<p><strong>Внимание</strong>: Настройка альфа канала в цвете имеет одно ключевое различие в использовании свойства {{cssxref("opacity")}} которое мы рассматривали ранее. когда вы используете мутность вы делаете элемент и все внутри него мутным, тогда как при использовании цвета RGBA вы делаете мутным только тот цвет который вы специфицируете.</p> +</div> + +<p>In the example below I have added a background image to the containing block of our colored boxes. I have then set the boxes to have different opacity values — notice how the background shows through more when the alpha channel value is smaller.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-rgba.html", '100%', 770)}}</p> + +<p><strong>In this example, try changing the alpha channel values to see how it affects the color output. </strong></p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: At some point modern browsers were updated so that <code>rgba()</code> and <code>rgb()</code>, and <code>hsl()</code> and <code>hsla()</code> (see below), became pure aliases of each other and started to behave exactly the same. So for example both <code>rgba()</code> and <code>rgb()</code> accept colors with and without alpha channel values. Try changing the above example's <code>rgba()</code> functions to <code>rgb()</code> and see if the colors still work! Which style you use is up to you, but separating out non-transparent and transparent color definitions to use the different functions gives (very) slightly better browser support and can act as a visual indicator of where transparent colors are being defined in your code.</p> +</div> + +<h3 id="HSL_and_HSLA_values">HSL and HSLA values</h3> + +<p>Slightly less well-supported than RGB is the HSL color model (not supported on old versions of IE), which was implemented after much interest from designers. Instead of red, green, and blue values, the <code>hsl()</code> function accepts hue, saturation, and lightness values, which are used to distinguish between the 16.7 million colors, but in a different way:</p> + +<ul> + <li><strong>Hue</strong>: The base shade of the color. This takes a value between 0 and 360, representing the angles round a color wheel.</li> + <li><strong>Saturation</strong>: How saturated is the color? This takes a value from 0–100%, where 0 is no color (it will appear as a shade of grey), and 100% is full color saturation</li> + <li><strong>Lightness</strong>: How light or bright is the color? This takes a value from 0–100%, where 0 is no light (it will appear completely black) and 100% is full light (it will appear completely white)</li> +</ul> + +<p>We can update the RGB example to use HSL colors like this:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-hsl.html", '100%', 700)}} </p> + +<p>Just as RGB has RGBA, HSL has an HSLA equivalent, which gives you the same ability to specify the alpha channel. I've demonstrated this below by changing my RGBA example to use HSLA colors.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-hsla.html", '100%', 770)}} </p> + +<p>You can use any of these color values in your projects. It is likely that for most projects you will decide on a color palette and then use those colors — and your chosen method of specifying color — throughout the whole project. You can mix and match color models, however for consistency it is usually best if your entire project uses the same one!</p> + +<h2 id="Images">Images</h2> + +<p>The <code><a href="/en-US/docs/Web/CSS/image"><image></a></code> data type is used wherever an image is a valid value. This can be an actual image file pointed to via a <code>url()</code> function, or a gradient.</p> + +<p>In the example below we have demonstrated an image and a gradient in use as a value for the CSS <code>background-image</code> property.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/image.html", '100%', 740)}} </p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: there are some other possible values for <code><image></code>, however these are newer and currently have poor browser support. Check out the page on MDN for the <code><a href="/en-US/docs/Web/CSS/image"><image></a></code> data type if you want to read about them.</p> +</div> + +<h2 id="Position">Position</h2> + +<p>The <code><a href="/en-US/docs/Web/CSS/position_value"><position></a></code> data type represents a set of 2D coordinates, used to position an item such as a background image (via <code><a href="/en-US/docs/Web/CSS/background-position">background-position</a></code>). It can take keywords such as <code>top</code>, <code>left</code>, <code>bottom</code>, <code>right</code>, and <code>center</code> to align items with specific bounds of a 2D box, along with lengths, which represent offsets from the top and left-hand edges of the box.</p> + +<p>A typical position value consists of two values — the first sets the position horizontally, the second vertically. If you only specify values for one axis the other will default to <code>center</code>.</p> + +<p>In the following example we have positioned a background image 40px from the top and to the right of the container using a keyword.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/position.html", '100%', 720)}} </p> + +<p><strong>Play around with these values to see how you can push the image around.</strong></p> + +<h2 id="Strings_and_identifiers">Strings and identifiers</h2> + +<p>Throughout the examples above, we've seen places where keywords are used as a value (for example <code><color></code> keywords like <code>red</code>, <code>black</code>, <code>rebeccapurple</code>, and <code>goldenrod</code>). These keywords are more accurately described as <em>identifiers</em>, a special value that CSS understands. As such they are not quoted — they are not treated as strings.</p> + +<p>There are places where you use strings in CSS, for example <a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements#Generating_content_with_before_and_after">when specifying generated content</a>. In this case the value is quoted to demonstrate that it is a string. In the below example we use unquoted color keywords along with a quoted generated content string.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/strings-idents.html", '100%', 550)}} </p> + +<h2 id="Functions">Functions</h2> + +<p>The final type of value we will take a look at is the group of values known as functions. In programming, a function is a reusable section of code that can be run multiple times to complete a repetitive task with minimum effort on the part of both the developer and the computer. Functions are usually associated with languages like JavaScript, Python, or C++, but they do exist in CSS too, as property values. We've already seen functions in action in the Colors section — <code>rgb()</code>, <code>hsl()</code>, etc. The value used to return an image from a file — <code>url()</code> — is also a function.</p> + +<p>A value that behaves more like something you might find in a traditional programming language is the <code>calc()</code> CSS function. This function gives you the ability to do simple calculations inside your CSS. It's particularly useful if you want to work out values that you can't define when writing the CSS for your project, and need the browser to work out for you at runtime.</p> + +<p>For example, below we are using <code>calc()</code> to make the box <code>20% + 100px</code> wide. The 20% is calculated from the width of the parent container <code>.wrapper</code> and so will change if that width changes. We can't do this calculation beforehand because we don't know what 20% of the parent will be, so we use <code>calc()</code> to tell the browser to do it for us.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/calc.html", '100%', 450)}}</p> + +<h2 id="Summary">Summary</h2> + +<p>This has been a quick run through of the most common types of values and units you might encounter. You can have a look at all of the different types on the <a href="/en-US/docs/Web/CSS/CSS_Values_and_Units">CSS Values and units</a> reference page; you will encounter many of these in use as you work through these lessons.</p> + +<p>The key thing to remember is that each property has a defined list of allowed values, and each value has a definition explaining what the sub-values are. You can then look up the specifics here on MDN.</p> + +<p>For example, understanding that <code><a href="/en-US/docs/Web/CSS/image"><image></a></code> also allows you to create a color gradient is useful but perhaps non-obvious knowledge to have!</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Overflowing_content", "Learn/CSS/Building_blocks/Sizing_items_in_CSS", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS selectors</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class, and ID selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Combinators</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Backgrounds and borders</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Handling different text directions</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">Overflowing content</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">Values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Images, media, and form elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">Styling tables</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">Organizing your CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/каскад_задачи/index.html b/files/ru/learn/css/building_blocks/каскад_задачи/index.html new file mode 100644 index 0000000000..b6524f9ed3 --- /dev/null +++ b/files/ru/learn/css/building_blocks/каскад_задачи/index.html @@ -0,0 +1,51 @@ +--- +title: 'Проверьте ваши навыки: Каскад' +slug: Learn/CSS/Building_blocks/Каскад_задачи +tags: + - CSS + - Начинающий +translation_of: Learn/CSS/Building_blocks/Cascade_tasks +--- +<div>{{LearnSidebar}}</div> + +<div></div> + +<p>Цель этого задания — помочь вам проверить ваше понимание некоторых значений и элементов, которые мы рассмотрели в уроке <a href="/ru-RU/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование</a>.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Вы можете проверять решения в интерактивном редакторе, расположенном ниже, но, возможно, вам будут полезны онлайн-инструменты, такие как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a> или <a href="https://glitch.com/">Glitch</a>, которые можно использовать для работы над заданием, предварительно загрузив в них код.<br> + <br> + Если вы зашли в тупик, обратитесь к нам за помощью — смотрите раздел {{anch("Оценка или дальнейшая помощь")}} внизу этой страницы.</p> +</div> + +<h2 id="Задание_1">Задание 1</h2> + +<p>В этом задании вам надо использовать одно из специальных значений, рассмотренных нами в разделе <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance#%D0%9A%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D1%8C_%D0%BD%D0%B0%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F">Контроль наследования</a>, чтобы написать в новом правиле объявление, которое восстановит белый цвет фона без использования фактического значения цвета.</p> + +<p><img alt="Barely visible yellow links on a white background." src="https://mdn.mozillademos.org/files/17146/mdn-cascade.png" style="height: 234px; width: 1244px;"></p> + +<p>Посмотрите, сможете ли вы повторить эту картинку в примере ниже.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/cascade/cascade.html", '100%', 700)}}</p> + +<div class="blockIndicator note"> +<p>Для получения оценки или для дальнейшей работы <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/cascade/cascade-download.html">загрузите исходный код для этого задания</a> в ваш собственный редактор или в онлайн-редактор.</p> +</div> + +<h2 id="Оценка_или_дальнейшая_помощь">Оценка или дальнейшая помощь</h2> + +<p>Вы можете упражняться на этих примерах в интерактивных редакторах, упомянутых выше.</p> + +<p>Если вы хотите, чтобы вашу работу оценили, или вы зашли в тупик и хотите попросить о помощи:</p> + +<ol> + <li>Поместите вашу работу в онлайн-редактор с возможностью совместного редактирования, например, <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a> или <a href="https://glitch.com/">Glitch</a>. Вы можете сами написать код или использвать файлы с исходным кодом, расположенные по ссылке в предыдущем разделе.</li> + <li>Напишите сообщение с просьбой оценить и/или помочь на форуме в категории "Обучение": <a class="external external-icon" href="https://discourse.mozilla.org/c/mdn/learn" rel="noopener">MDN Discourse forum Learning category</a>. Ваше сообщение должно включать: + <ul> + <li>Описательный заголовок, например, "Необходима оценка для теста 1 Каскад" ("Assessment wanted for Cascade skill test 1").</li> + <li>Подробности того, что вы уже попытались сделать, и чего бы вы хотели от нас, т.е. или вы в тупике и нуждаетесь в помощи, или хотите оценки.</li> + <li>Ссылка на пример, который вы просите оценить или который вызвал затруднения, в онлайн-редакторе с возможностью совместного редактирования (как указано в шаге 1 выше). Это принятая<span class="Translate-ValuesContent"> практика</span> погружения в вопрос — очень трудно помочь кому-либо решить проблему кодирования, если вы не видите его код.</li> + <li>Ссылка на страницу с заданием, чтобы мы могли найти вопрос, на который вы затрудняетесь ответить.</li> + </ul> + </li> +</ol> diff --git a/files/ru/learn/css/building_blocks/селекторы/attribute_selectors/index.html b/files/ru/learn/css/building_blocks/селекторы/attribute_selectors/index.html new file mode 100644 index 0000000000..9a6a2c4c07 --- /dev/null +++ b/files/ru/learn/css/building_blocks/селекторы/attribute_selectors/index.html @@ -0,0 +1,160 @@ +--- +title: Селекторы атрибута +slug: Learn/CSS/Building_blocks/Селекторы/Attribute_selectors +tags: + - CSS + - Атрибут + - Начинающий + - Обучение + - Селекторы +translation_of: Learn/CSS/Building_blocks/Selectors/Attribute_selectors +--- +<p>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors", "Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements", "Learn/CSS/Building_blocks")}}</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Как вы знаете из курса о HTML, элементы могут иметь атрибуты, которые дают дополнительную информацию о размечаемом элементе.</span></span> <span class="tlid-translation translation" lang="ru"><span title="">В CSS вы можете использовать селекторы атрибута</span></span> <span class="tlid-translation translation" lang="ru"><span title="">для стилизации элементов с определенными атрибутами</span></span>. <span class="tlid-translation translation" lang="ru"><span title="">Этот урок покажет вам, как использовать эти очень полезные селекторы.</span></span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">установка базового ПО</a>, базовые знания о <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работе с файлами</a>, основы HTML (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>) и понимание работы CSS (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>.)</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Узнать, что такое селекторы атрибута и как их использовать.</td> + </tr> + </tbody> +</table> + +<h2 id="Селекторы_наличия_и_значения"><span class="tlid-translation translation" lang="ru"><span title="">Селекторы наличия и значения</span></span></h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Эти селекторы делают возможным выбор элемента, основанный только на наличии атрибута (например,</span></span> <code>href</code>) <span class="tlid-translation translation" lang="ru"><span title="">или на всевозможных разного рода сочетаниях со значением атрибута</span></span>.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Селектор</th> + <th scope="col">Пример</th> + <th scope="col">Описание</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>[<em>attr</em>]</code></td> + <td><code>a[title]</code></td> + <td><span class="tlid-translation translation" lang="ru"><span title="">Выбирает элементы с атрибутом <em>attr</em> (имя которого </span></span> — <span class="tlid-translation translation" lang="ru"><span title=""> это значение в квадратных скобках).</span></span></td> + </tr> + <tr> + <td><code>[<em>attr</em>=<em>value</em>]</code></td> + <td><code>a[href="https://example.com"]</code></td> + <td><span class="tlid-translation translation" lang="ru"><span title="">Выбирает элементы с атрибутом <em>attr</em>, значение которого в точности равно <em>value</em> </span></span> — <span class="tlid-translation translation" lang="ru"><span title="">строке внутри кавычек.</span></span></td> + </tr> + <tr> + <td><code>[<em>attr</em>~=<em>value</em>]</code></td> + <td><code>p[class~="special"]</code></td> + <td> + <p><span class="tlid-translation translation" lang="ru"><span title="">Выбирает</span></span> элементы с атрибутом <em>attr,</em> значение которого в точности равно <em>value</em> или содержит <em>value</em> в своём (разделённом пробелами) списке значений.</p> + </td> + </tr> + <tr> + <td><code>[<em>attr</em>|=<em>value</em>]</code></td> + <td><code>div[lang|="zh"]</code></td> + <td><span class="tlid-translation translation" lang="ru"><span title="">Выбирает</span></span> элементы с атрибутом <em>attr</em>, значение которого в точности равно <em>value </em>или начинается с <em>value</em>, за которым сразу следует дефис.</td> + </tr> + </tbody> +</table> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В приведённом ниже примере вы можете увидеть использование этих селекторов.</span></span></p> + +<ul> + <li>Используя <code>li[class],</code> мы можем выбрать каждый селектор с атрибутом класса. Это соответствует всем пунктам списка, за исключением первого.</li> + <li><code>li[class="a"]</code> выбирает селектор с классом <code>a</code>, но не селектор с классом <code>a</code> в сочетании с другим, отделённым запятой, классом как частью зачения. Он выбирает второй пункт списка.</li> + <li><code>li[class~="a"]</code> выберет класс <code>a</code>, а также значение, которое содержит класс <code>a</code> как часть разделённого пробелом списка. Он выберет второй и третий пункты списка.</li> +</ul> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/attribute.html", '100%', 800)}}</p> + +<h2 id="Селекторы_вхождения_подстроки"><span class="tlid-translation translation" lang="ru"><span title="">Селекторы вхождения подстроки</span></span></h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Эти селекторы предоставляют более широкие возможности для выявления вхождения подстроки в значение атрибута</span></span>. Например, если у вас есть классы <code>box-warning</code> и <code>box-error</code> и вы хотите выбрать всё, что начинается со стороки "box-", вы можете использовать <code>[class^="box-"]</code>, чтобы выбрать оба класса (или <code>[class|="box"]</code> как описано в предыдущем разделе).</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Селектор</th> + <th scope="col">Пример</th> + <th scope="col">Описание</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>[<em>attr</em>^=<em>value</em>]</code></td> + <td><code>li[class^="box-"]</code></td> + <td>Выбирает элементы с атрибутом <em>attr</em> (<span class="tlid-translation translation" lang="ru"><span title="">его имя </span></span> — <span class="tlid-translation translation" lang="ru"><span title=""> это значение в квадратных скобках</span></span>), значение которого начинается с <em>value</em>.</td> + </tr> + <tr> + <td><code>[<em>attr</em>$=<em>value</em>]</code></td> + <td><code>li[class$="-box"]</code></td> + <td>Выбирает элементы с атрибутом <em>attr</em>, значение которого заканчивается на <em>value</em>.</td> + </tr> + <tr> + <td><code>[<em>attr</em>*=<em> </em>]</code></td> + <td><code>li[class*="box"]</code></td> + <td>Выбирает элементы с атрибутом <em>attr</em>, значение которого содержит <em>value</em>, независимо от его положения внутри строки.</td> + </tr> + </tbody> +</table> + +<p>(Отступление: возможно, будет полезным заметить, что <code>^</code> и <code>$</code> давно используются как <em>якоря </em>в так называемых <em>регулярных выражениях</em> и обозначают <em>начинается с </em>и <em>заканчивается на</em>.)</p> + +<p>Следующий пример показывает, как используются эти селекторы:</p> + +<ul> + <li><code>li[class^="a"]</code> выбирает все значения атрибута, которые начинаются с <code>a</code>, что соответствует первым двум элементам списка.</li> + <li><code>li[class$="a"]</code> выбирает все значения атрибута, которые заканчиваются на <code>a</code>, что соответствует первому и третьему элементу списка.</li> + <li><code>li[class*="a"]</code> выбирает все значения атрибута, где появляется <code>a</code>, независимо от положения в строке, что соответствует всем элементам нашего списка.</li> +</ul> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/attribute-substring.html", '100%', 800)}}</p> + +<h2 id="Чувствительность_к_регистру">Чувствительность к регистру</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Если вы хотите выбрать значения атрибута без учета регистра</span></span><span class="tlid-translation translation" lang="ru"><span title="">, вы можете использовать значение</span></span> <code>i</code> перед закрывающей скобкой. Этот признак говорит браузеру, что символы ASCII должны сопоставляться без учета регистра. <span class="tlid-translation translation" lang="ru"><span title="">Без этого признака значения будут сопоставлены в соответствии с чувствительностью к регистру языка документа</span></span> — <span class="tlid-translation translation" lang="ru"><span title="">в случае HTML такая чувствительность присутствует</span></span>.</p> + +<p>В примере ниже первый селектор выберет значение, начинающееся с <code>a</code> — <span class="tlid-translation translation" lang="ru"><span title="">это соответствует только первому элементу списка</span></span><span class="tlid-translation translation" lang="ru"><span title="">, потому что два других элемента списка начинаются с заглавной буквы A</span></span>. Второй селектор использует признак нечувствительности к регистру и поэтому выберет все элементы списка.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/attribute-case.html", '100%', 800)}}</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Существует также более новое значение <code>s</code>, <span class="tlid-translation translation" lang="ru"><span title="">которое вызывает сопоставление с учетом регистра в контекстах, где сопоставление обычно не учитывает регистр, однако это не так хорошо поддерживается в браузерах и не очень полезно в контексте HTML.</span></span></p> +</div> + +<h2 id="Следующие_шаги">Следующие шаги</h2> + +<p>Итак, мы рассмотрели селекторы атрибута, и вы можете перейти к следующей статье, в которой рассказывается о <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">псевдоклассах и псевдоэлементах</a>.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors", "Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B">Селекторы CSS</a> + <ul> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Type_Class_and_ID_Selectors">Селекторы типа, класса и ID</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Attribute_selectors">Селекторы атрибута</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">Псевдоклассы и псевдоэлементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Combinators">Комбинаторы</a></li> + </ul> + </li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/The_box_model">Модель коробки (The box model)</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Фон и границы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Обработка разных направлений текста</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Overflowing_content">Переполнение содержимого</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Values_and_units">Значения и единицы измерения</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Изменение размеров в CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Элементы изображений, форм и медиа-элементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Styling_tables">Стилизация таблиц</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Organizing">Организация вашей CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/селекторы/combinators/index.html b/files/ru/learn/css/building_blocks/селекторы/combinators/index.html new file mode 100644 index 0000000000..7a076e05a8 --- /dev/null +++ b/files/ru/learn/css/building_blocks/селекторы/combinators/index.html @@ -0,0 +1,113 @@ +--- +title: Комбинаторы +slug: Learn/CSS/Building_blocks/Селекторы/Combinators +tags: + - CSS + - Селекторы + - комбинаторы +translation_of: Learn/CSS/Building_blocks/Selectors/Combinators +--- +<p>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements", "Learn/CSS/Building_blocks/The_box_model", "Learn/CSS/Building_blocks")}}</p> + +<p>Наконец мы рассмотрим селекторы, которые называются комбинаторами, поскольку они соединяют другие селекторы, создавая полезную связь селекторов друг с другом и расположением содержимого в документе.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">установленное базовое программное обеспечение</a>, базовые знания о <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работе с файлами</a>, основы HTML (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>) и понимание работы CSS (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>.)</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Узнать о различных комбинаторных селекторах, которые могут быть использованы в CSS.</td> + </tr> + </tbody> +</table> + +<h2 id="Комбинатор_потомка">Комбинатор потомка</h2> + +<p><strong>Селектор потомка</strong> — обычно представляется символом пробела (<code> </code>) — соединяет два селектора так, что элементы, соответствующие второму селектору, выбираются, если они имеют предка (родителя, родителя родителя, родителя родителя родителя и т.д.), соответствующего первому селектору. Селекторы, которые используют комбинатор потомка, называются <dfn>селекторами потомка.</dfn></p> + +<pre class="brush: css notranslate">body article p</pre> + +<p>В приведенном ниже примере выбирается только тот элемент <p>, который находится внутри элемента с классом<code>.box</code>.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/descendant.html", '100%', 500)}}</p> + +<h2 id="Дочерний_комбинатор">Дочерний комбинатор</h2> + +<p><strong>Дочерний комбинатор</strong> (<code>></code>) помещается между двумя селекорами CSS. При этом будут выбраны только те элементы, соответствующие второму селектору, которые являются прямыми потомками элементов, соответствующих первому селектору. Все элементы-потомки на более низких уровнях иерархии будут пропущены. Например, чтобы выбрать только те элементы <code><p></code>, которые являются дочерними элементами <code><article></code>, селетор пишется так:</p> + +<pre class="brush: css notranslate">article > p</pre> + +<p>Другой пример. Имеется неупорядоченный список, заключающий в себе другой, упорядоченный список. Дочерний комбинатор используется для того, чтобы выбрать только те элементы <code><li></code>, которые являются прямыми потомками <code><ul></code>, и присвоить им верхнюю границу красного цвета.</p> + +<p>Если вы уберёте символ <code>></code>, указывающий на то, что это селектор с дочерним комбинатором, селетор превратится в селектор всех потомков (комбинатор - пробел) и все элементы <code><li></code> получат верхнюю границу красного цвета.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/child.html", '100%', 600)}}</p> + +<h2 id="Соседний_родственный_комбинатор">Соседний родственный комбинатор</h2> + +<p>Соседний родственный селектор (<code>+</code>) используется для выбора элемента, который непосредственно следует за другим элементом и находится на одном с ним уровне иерархии. Например, чтобы выбрать все элементы <code><img></code> , которые идут сразу после элементов <code><p></code> :</p> + +<pre class="brush: css notranslate">p + img</pre> + +<p>Распространенный вариант использования — сделать что-то с абзацем, который следует за заголовком, как в примере ниже. Здесь мы ищем абзац, который непосредственно примыкает к <code><h1></code>, и стилизуем его.</p> + +<p>Если вы вставите какой-то другой элемент, например <code><h2></code> между <code><h1></code> и <code><p></code>, вы обнаружите, что абзац больше не соответствует селектору и поэтому не получает цвет фона и переднего плана, применяемый, когда элемент является соседним.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/adjacent.html", '100%', 800)}}</p> + +<h2 id="Общий_родственный_комбинатор">Общий родственный комбинатор</h2> + +<p>Если вы хотите выбрать родственные элементы, даже если они не являются непосредственными соседями, то вы можете использовать общий родственный комбинатор (<code>~</code>). Чтобы выбрать все элементы <code><img></code>, которые находятся в <em>любом</em> месте после элементов <code><p></code>, надо указать так:</p> + +<pre class="brush: css notranslate">p ~ img</pre> + +<p>В приведенном ниже примере мы выбираем все элементы <code><p></code>, которые идут после <code><h1></code>, и хотя в документе есть также <code><div></code>, тем не менее <code><p></code>, который идет после него, будет выбран.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/general.html", '100%', 600)}}</p> + +<h2 id="Использование_комбинаторов">Использование комбинаторов</h2> + +<p>Вы можете соединять с помощью комбинаторов любые селекторы, которые мы изучали в предыдущих уроках, чтобы выбрать часть вашего документа. Например, если мы хотим выбрать пункты списка с классом "a", которые являются прямыми потомками <code><ul></code>, можно использовать следующую комбинацию:</p> + +<pre class="brush: css notranslate">ul > li[class="a"] { }</pre> + +<p>Однако будьте осторожны при создании больших списков селекторов, которые выделяют очень конкретные части вашего документа. Будет трудно повторно использовать правила CSS, так как вы сделали селектор очень специфичным для определения местоположения этого элемента в разметке.</p> + +<p>Часто бывает лучше создать простой класс и применить его к рассматриваемому элементу. Тем не менее, ваши знания о комбинаторах будут очень полезны, если вам нужно добраться до чего-то в вашем документе и вы не можете получить доступ к HTML, возможно, из-за того, что он генерируется CMS.</p> + +<h2 id="Проверьте_ваши_навыки!">Проверьте ваши навыки!</h2> + +<p>Мы охватили много тем в этой статье. А вы можете вспомнить наиболее важную информацию? Можете пройти несколько дополнительных тестов для того чтобы убедиться в том, что вы усвоили эту информацию, прежде чем пойдёте дальше — смотрите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B_%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B8">Проверьте ваши навыки: Селекторы</a>.</p> + +<h2 id="Двигаемся_дальше">Двигаемся дальше</h2> + +<p>Это последний раздел в наших уроках по селекторам. Далее мы перейдем к другой важной части CSS — <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/The_box_model">CSS модель коробки</a>.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements", "Learn/CSS/Building_blocks/The_box_model", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B">Селекторы CSS</a> + <ul> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Type_Class_and_ID_Selectors">Селекторы типа, класса и ID</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Attribute_selectors">Селекторы атрибута</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">Псевдоклассы и псевдоэлементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Combinators">Комбинаторы</a></li> + </ul> + </li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/The_box_model">Модель коробки</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Фон и границы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Обработка разных направлений текста</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Overflowing_content">Переполнение содержимого</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Values_and_units">Значения и единицы измерения</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Изменение размеров в CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Элементы изображений, форм и медиа-элементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Styling_tables">Стилизация таблиц</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Organizing">Организация вашей CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/селекторы/index.html b/files/ru/learn/css/building_blocks/селекторы/index.html new file mode 100644 index 0000000000..3819af4207 --- /dev/null +++ b/files/ru/learn/css/building_blocks/селекторы/index.html @@ -0,0 +1,235 @@ +--- +title: Селекторы CSS +slug: Learn/CSS/Building_blocks/Селекторы +tags: + - Attribute + - Beginner + - CSS + - Learn + - Pseudo-class + - Pseudo-element + - id + - Обучение + - Псевдоэлемент + - псевдокласс + - селектор +translation_of: Learn/CSS/Building_blocks/Selectors +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Cascade_and_inheritance", "Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors", "Learn/CSS/Building_blocks")}}</div> + +<p class="summary">В {{Glossary("CSS")}}-селекторы используются для стилизации {{glossary("HTML")}} элементов на веб-странице. Существует широкий выбор CSS-селекторов, позволяющий максимально точно отбирать элементы для стилизации. В этой статье и её подстатьях мы в мельчайших подробностях рассмотрим разные их типы и увидим, как они работают.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, <a href="/ru/docs/Learn/Getting_started_with_the_web/Установка_базового_программного_обеспечения">основное программное обеспечение</a>, понимание <a href="/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работы с файлами</a>, базовые знания HTML (смотрите <a href="/ru/docs/Learn/HTML/Введение_в_HTML">Введение в HTML</a>), и представление о том, как работает CSS (смотрите <a href="/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Узнать, как работают CSS-селекторы.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_селекторы">Что такое селекторы?</h2> + +<p>Вы уже встерчались с селекторами. Это выражения, которые говорят браузеру, к какому элементу HTML нужно применить те или иные свойства CSS, определённые внутри блока объявления стиля.</p> + +<p><img alt="Some code with the h1 highlighted." src="https://mdn.mozillademos.org/files/16550/selector.png" style="border: 1px solid #cccccc; height: 218px; width: 471px;"></p> + +<p>Ранее Вы встречали несколько разных селекторов и узнали, что существуют селекторы, которые по-разному относятся к документу, — например используя элемент <code>h1</code> или класс <code>.special</code>.</p> + +<p>В CSS селекторы определяются в спецификации CSS-селекторов; как и другие части CSS, нужно поддерживать их работу в браузерах. Большинство селекторов, которые Вы встретите, определены в <a href="https://www.w3.org/TR/selectors-3/">Спецификации селекторов 3 уровня</a>, где Вы сможете найти всю информацию о поддержке селекторов в браузерах.</p> + +<h2 id="Несколько_селекторов">Несколько селекторов</h2> + +<p>Несколько селекторов, использующих одни и те же таблицы стилей, можно объединить в <em>лист селекторов</em>: правило будет добавлено к каждому селектору. К примеру, у меня есть одинаковые правила для заголовка <code>h1</code> и класса <code>.special</code>; я могу написать их так:</p> + +<pre class="brush: css notranslate"><code>h1 { + color: blue; +} + +.special { + color: blue; +} </code></pre> + +<p>А могу написать короче — просто отделив селекторы запятыми:</p> + +<pre class="brush: css notranslate"><code>h1, .special { + color: blue; +} </code></pre> + +<p>Пробел можно вставлять до или после запятой. Ещё удобнее писать каждый селектор с новой строки:</p> + +<pre class="brush: css notranslate"><code>h1, +.special { + color: blue; +} </code></pre> + +<p>В упражнении ниже объедините два селектора в одном правиле. Результат должен остаться таким же.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/selector-list.html", '100%', 1000)}} </p> + +<p>При объединении селекторов таким образом, при условии если хоть один селектор будет недействительным, всё правило будет пропущено.</p> + +<p>В примере ниже правило для селектора класса не будет работать, в то время как <code>h1</code> будет стилизован.</p> + +<pre class="brush: css notranslate"><code>h1 { + color: blue; +} + +..special { + color: blue; +} </code></pre> + +<p>Но если мы объединим селекторы, правило не применится ни к <code>h1</code>, ни к классу: оно считается недействительным.</p> + +<pre class="brush: css notranslate"><code>h1, ..special { + color: blue; +} </code></pre> + +<h2 id="Типы_селекторов">Типы селекторов</h2> + +<p>Понимание того, какой именно селектор вам нужен, очень помогает подобрать подходящий элемент. Сейчас мы разберём разные виды селекторов.</p> + +<h3 id="Селекторы_тегов_классов_и_идентификаторов">Селекторы тегов, классов и идентификаторов</h3> + +<p>К этой группе относятся селекторы HTML-элементов, таких как <code><h1></code>.</p> + +<pre class="brush: css notranslate">h1 { }</pre> + +<p>К группе относятся и селекторы классов:</p> + +<pre class="brush: css notranslate">.box { }</pre> + +<p>или селекторы идентификаторов (ID):</p> + +<pre class="brush: css notranslate">#unique { }</pre> + +<h3 id="Селекторы_атрибутов">Селекторы атрибутов</h3> + +<p>Эта группа селекторов позволяет выбирать селекторы, основываясь на <em>наличии</em> у них конкретного атрибута элемента:</p> + +<pre class="brush: css notranslate">a[title] { }</pre> + +<p>или основываясь на <em>значении</em> атрибута:</p> + +<pre class="brush: css notranslate">a[href="https://example.com"] { }</pre> + +<h3 id="Псевдоклассы_псевдоэлементы">Псевдоклассы, псевдоэлементы</h3> + +<p>К этой группе относятся псевдоклассы, которые стилизуют определённое состояние элемента. Псевдокласс <code>:hover</code>, например, применяет правило, только если на элемент наведён курсор мыши</p> + +<pre class="brush: css notranslate">a:hover { }</pre> + +<p>К группе ещё относятся псевдоэлементы, которые выбирают определённую часть элемента (вместо целого элемента). Например, <code>::first-line</code> всегда выбирает первую строку внутри элемента (абзаца <code><p></code> в нашем случае), действуя, как если бы тег <code><span></code> оборачивал первую строку, а затем был стилизован.</p> + +<pre class="brush: css notranslate">p::first-line { }</pre> + +<h3 id="Комбинаторы">Комбинаторы</h3> + +<p>И последняя группа селекторов: она позволяет объединять селекторы, чтобы было легче находить конкретные элементы внутри документа. В следующем примере мы отыскали дочерний элемент <code><article></code> с помощью комбинатора дочерних элементов (<code>></code>):</p> + +<pre class="brush: css notranslate">article > p { }</pre> + +<h2 id="Продолжение">Продолжение</h2> + +<p>Ниже можно просмотреть таблицу различных видов селекторов с соответствующими ссылками, или Вы можете двинуться дальше: нас ждут <a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Type_Class_and_ID_Selectors">селекторы тегов, классов и идентификаторов</a>.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Cascade_and_inheritance", "Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="Справка_о_селекторах">Справка о селекторах</h2> + +<p>В таблице ниже — доступные сейчас селекторы, а также ссылки к страницам, где рассказывается, как использовать каждый из них. Я также добавил ссылки на страницы MDN для каждого селектора, чтобы вы могли проверить, поддерживаются ли они браузерами.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Селектор</th> + <th scope="col">Пример</th> + <th scope="col">Руководство</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/ru/docs/Web/CSS/Type_selectors">Селектор по типу</a></td> + <td><code>h1 { }</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Type_Class_and_ID_Selectors#Селекторы_по_типу">Селектор по типу</a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/Universal_selectors">Универсальный селектор</a></td> + <td><code>* { }</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Type_Class_and_ID_Selectors#Универсальный_селектор">Универсальный селектор</a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/Class_selectors">Селектор класса</a></td> + <td><code>.box { }</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Type_Class_and_ID_Selectors#Селекторы_классов">Селекторы классов</a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/ID_selectors">Селектор ID</a></td> + <td><code>#unique { }</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Type_Class_and_ID_Selectors#Селекторы_по_ID">Селекторы по ID</a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/Attribute_selectors">Селектор атрибутов </a></td> + <td><code>a[title] { }</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Attribute_selectors">Селекторы атрибутов </a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/Псевдо-классы">Селектор псевдоклассов</a></td> + <td><code>p:first-child { }</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Pseudo-classes_and_pseudo-elements#Что_такое_псевдокласс">Псевдоклассы</a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/Pseudo-elements">Селектор псевдоэлементов</a></td> + <td><code>p::first-line { }</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Pseudo-classes_and_pseudo-elements#Что_такое_псевдоэлемент">Псевдоэлементы</a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/Descendant_combinator">Селектор потомков</a></td> + <td><code>article p</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Combinators#Селектор_потомков">Селектор потомков</a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/Child_combinator">Селектор дочерних элементов</a></td> + <td><code>article > p</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Combinators#Комбинатор">Селектор дочерних элементов</a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/Adjacent_sibling_combinator">Смежные селекторы</a></td> + <td><code>h1 + p</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Combinators#Смежные_селекторы">Смежные селекторы </a></td> + </tr> + <tr> + <td><a href="/ru/docs/Web/CSS/General_sibling_combinator">Селектор братских элементов</a></td> + <td><code>h1 ~ p</code></td> + <td><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Combinators#Братские_элементы">Селектор братских элементов</a></td> + </tr> + </tbody> +</table> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы">CSS-селекторы </a> + <ul> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Type_Class_and_ID_Selectors">Селекторы по типу, классу и идентификатору</a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Attribute_selectors">Селекторы атрибутов </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Pseudo-classes_and_pseudo-elements">Псевдоклассы, псевдоэлементы </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Селекторы/Combinators">Комбинации селекторов </a></li> + </ul> + </li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/The_box_model">Блоки в CSS </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Фон и границы </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Изменение направления текста </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Overflowing_content">Перекрытие содержимого</a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Values_and_units">Значения свойств CSS </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Изменение размеров в CSS </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Изображения, формы и прочие медиа-элементы </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Styling_tables">Стилизация таблиц </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS </a></li> + <li><a href="/ru/docs/Learn/CSS/Building_blocks/Organizing">Организация CSS-кода</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/селекторы/pseudo-classes_and_pseudo-elements/index.html b/files/ru/learn/css/building_blocks/селекторы/pseudo-classes_and_pseudo-elements/index.html new file mode 100644 index 0000000000..4fe67b8adb --- /dev/null +++ b/files/ru/learn/css/building_blocks/селекторы/pseudo-classes_and_pseudo-elements/index.html @@ -0,0 +1,415 @@ +--- +title: 'Псевдоклассы, псевдоэлементы' +slug: Learn/CSS/Building_blocks/Селекторы/Pseudo-classes_and_pseudo-elements +tags: + - CSS + - Начинающий + - Обучение + - Псевдо + - Псевдоэлемент + - Селекторы + - псевдокласс +translation_of: Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements +--- +<p>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Attribute_selectors", "Learn/CSS/Building_blocks/Selectors/Combinators", "Learn/CSS/Building_blocks")}}</p> + +<p>Следующий набор селекторов, который мы рассмотрим, относится к псевдоклассам и псевдоэлементам. Их очень много, и они часто служат довольно специфическим целям. После того как вы узнаете порядок их использования, просмотрите список — не найдётся ли в нём что-либо, что поможет решить стоящую перед вами задачу. Кроме того, будет полезным заглянуть на соответствующую каждому селектору страницу MDN, чтобы прояснить, как его обрабатывает браузер.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">установка базового ПО</a>, базовые знания о <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работе с файлами</a>, основы HTML (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>) и понимание работы CSS (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>.)</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Узнать о селекторах псевдокласса и псевдоэлемента.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_псевдокласс">Что такое псевдокласс?</h2> + +<p>Псевдокласс — это селектор, который выбирает элементы, находящиеся в специфическом состоянии, например, они являются первым элементом своего типа, или на них наведён указатель мыши. Они обычно действуют так, как если бы вы применили класс к какой-то части вашего документа, что часто помогает сократить избыточные классы в разметке и даёт более гибкий, удобный в поддержке код.</p> + +<p>Псевдоклассы — это ключевые слова, которые начинаются с двоеточия:</p> + +<pre class="notranslate">:<em>pseudo-class-name</em></pre> + +<h3 id="Простой_пример_псевдокласса">Простой пример псевдокласса</h3> + +<p>Давайте рассмотрим простой пример. Если бы мы хотели сделать шрифт первого абзаца статьи более крупным и жирным, мы могли бы добавить класс к этому абзацу, а затем добавить CSS к этому классу, как показано в первом примере ниже:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/first-child.html", '100%', 800)}}</p> + +<p>Однако поддержка может оказаться утомительной — что если новый абзац будет добавлен в верхнюю часть документа? Тогда нам нужно будет передвинуть класс к новому абзацу. Вместо добавления класса мы могли бы использовать селектор псевдокласса {{cssxref(":first-child")}} — он всегда будет нацелен на первый дочерний элемент в статье, и нам больше не нужно будет редактировать HTML (к тому же это не всегда возможно, например, в случае если он генерируется CMS.)</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/first-child2.html", '100%', 700)}}</p> + +<p>Все псевдоклассы ведут себя подобным образом. Они нацелены на какой-то фрагмент вашего документа, находящийся в определенном состоянии, и ведут себя так, как если бы вы добавили класс в свой HTML. Рассмотрим некоторые другие примеры в MDN:</p> + +<ul> + <li><code><a href="https://wiki.developer.mozilla.org/ru/docs/Web/CSS/:last-child">:last-child</a></code></li> + <li><code><a href="https://wiki.developer.mozilla.org/ru/docs/Web/CSS/:only-child">:only-child</a></code></li> + <li><code><a href="https://wiki.developer.mozilla.org/ru/docs/Web/CSS/:invalid">:invalid</a></code></li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong> : Правильно писать псевдоклассы и элементы без какого бы то ни было предшествующего им селектора элемента. В примере выше вы могли бы написать <code>:first-child</code> и правило было бы применено к <em>любому</em> элементу, оказавшемуся первым дочерним для <code><article></code>, не только к первому дочернему абзацу — <code>:first-child</code> равнозначно <code>*:first-child</code>. Однако обычно вы хотите б<em>о</em>льшего контроля, поэтому вам нужен более специфичный селектор.</p> +</div> + +<h3 id="Псевдоклассы_пользовательского_действия">Псевдоклассы пользовательского действия</h3> + +<p>Некоторые псевдоклассы применяются только тогда, когда пользователь некоторым образом взаимодействует с документом. Эти псевдоклассы действий пользователя, иногда называемые динамическими псевдоклассами, действуют так, как если бы класс был добавлен к элементу в момент взаимодействия с ним пользователя. Примеры даны для:</p> + +<ul> + <li><code><a href="/en-US/docs/Web/CSS/:hover">:hover</a></code> — упоминался выше; он применяется только в том случае, если пользователь наводит указатель мыши на элемент, обычно на ссылку.</li> + <li><code><a href="/en-US/docs/Web/CSS/:focus">:focus</a></code> — применяется только в том случае, если пользователь фокусируется на элементе, используя управление с клавиатуры.</li> +</ul> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/hover.html", '100%', 500)}}</p> + +<h2 id="Что_такое_псевдоэлемент">Что такое псевдоэлемент?</h2> + +<p>Псевдоэлементы ведут себя сходным образом, однако они действуют так, как если бы вы добавили в разметку целый новый HTML-элемент, а не применили класс к существующим элементам. Псевдоэлементы начинаются с двойного двоеточия <code>::</code>.</p> + +<pre class="notranslate"><em>::pseudo-element-name</em></pre> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Некоторые ранние псевдоэлементы использовали синтаксис одинарного двоеточия, которое вы можете иногда видеть в коде или примерах. Современные браузеры поддерживают ранние псевдоэлементы с одинарным или двойным двоеточием синтаксиса для обратной совместимости.</p> +</div> + +<p>Например, если вы хотите выбрать первую строку абзаца, вы могли бы обернуть ее в <code><span></code> и использовать селектор элемента; однако это может не сработать, если количество слов, которые вы обернули, будет больше или меньше ширины родительского элемента. Поскольку мы, как правило, не знаем, сколько слов поместится в строке — т.к. их количество меняется, если меняется ширина экрана или размер шрифта — то надёжного решения при помощи HTML нет.</p> + +<p>Селектор псевдоэлемента <code>::first-line</code> сделает это наверняка — если количество слов увеличивается или уменьшается, он всё равно будет выбирать только первую строку.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/first-line.html", '100%', 800)}}</p> + +<p>Он действует так, как если бы <code><span></code> волшебным образом был обёрнут вокруг этой первой отформатированной строки и обновлялся бы каждый раз при изменении длины строки.</p> + +<p>Вы можете видеть, что селектор выбирает первую строку обоих абзацев.</p> + +<h2 id="Объединение_псевдоклассов_и_псевдоэлементов">Объединение псевдоклассов и псевдоэлементов</h2> + +<p>Если вы хотите сделать шрифт первой строки первого абзаца жирным, вы можете связать вместе селекторы <code>:first-child</code> и <code>::first-line</code>. Попробуйте отредактировать предыдущий живой пример, чтобы использовалась следующая CSS. Мы говорим, что хотим выбрать первую строку первого элемента <code><p>,</code> который находится внутри элемента <code><article></code>.</p> + +<pre class="brush: css notranslate"><code>article p:first-child::first-line { + font-size: 120%; + font-weight: bold; +}</code></pre> + +<h2 id="Генерация_контента_с_помощью_before_и_after">Генерация контента с помощью ::before и ::after</h2> + +<p>Существует пара специальных псевдоэлементов, которые используются вместе со свойством <code><a href="/en-US/docs/Web/CSS/content">content</a></code> для вставки содержимого в документ с помощью CSS.</p> + +<p>Вы можете использовать их для вставки строки текста, как в приведенном ниже живом примере. Попробуйте изменить текстовое значение свойства {{cssxref("content")}} и вы увидите, как изменится результат. Можете также изменить псевдоэлемент <code>::before</code> на <code>::after</code> и увидите, что текст вставлен в конце элемента, а не в начале.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/before.html", '100%', 400)}}</p> + +<p>Однако вставка строк текста из CSS в реальности происходит не слишком часто, поскольку этот текст недоступен для некоторых <span class="extended-text__full">экранных диктор</span>ов и его будет трудно найти и отредактировать в будущем.</p> + +<p>Более корректным использованием этих псевдоэлементов является вставка значка, например маленькой стрелки, добавленной в приведенном ниже примере, которая является визуальным указателем, не предназначенным для зачитывания с помощью <span class="extended-text__full">экранного диктор</span>а:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/after-icon.html", '100%', 400)}}</p> + +<p>Эти псевдоэлементы также часто используются для вставки пустой строки, которая затем может быть стилизована так же, как и любой элемент на странице.</p> + +<p>В следующем примере мы добавили пустую строку, используя псевдоэлемент <code>::before.</code> Мы установили <code>display: block</code>, чтобы стилизовать его по ширине и высоте. Затем мы используем CSS, чтобы стилизовать его так же, как и любой другой элемент. Вы можете поиграть с CSS и изменить его внешний вид и поведение.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/before-styled.html", '100%', 500)}}</p> + +<p>Использование псевдоэлементов <code>::before</code> и <code>::after</code> вместе со свойством <code>content</code> в CSS называется "генерируемым контентом" в CSS, и вы часто будете видеть, как этот метод используется для различных задач. Отличным примером является сайт <a href="http://www.cssarrowplease.com/">CSS Arrow Please</a>, который помогает вам генерировать стрелку с помощью CSS. Посмотрите на CSS, когда вы создадите свою стрелку, и вы увидите использование псевдо-элементов {{cssxref("::before")}} и {{cssxref("::after")}}. Всякий раз, когда вы будете видеть эти селекторы, смотрите на свойство {{cssxref("content")}}, чтобы увидеть, что добавляется в документ..</p> + +<h2 id="Справочный_раздел">Справочный раздел</h2> + +<p>Существует большое количество псевдоклассов и псевдоэлементов, и полезно иметь список, к которому можно обращаться. Ниже приведены таблицы, в которых они перечислены, со ссылками на их справочные страницы в MDN. Используйте эти таблицы как справочник, чтобы видеть массив доступных вам средств для нацеливания на элементы.</p> + +<h3 id="Псевдоклассы">Псевдоклассы</h3> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Селектор</th> + <th scope="col">Описание</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{ Cssxref(":active") }}</td> + <td>Подходит, когда пользователь активирует (например, щелкает мышью) элемент.</td> + </tr> + <tr> + <td>{{ Cssxref(":any-link") }}</td> + <td>Соответствует как состоянию <code>:link,</code> так и состоянию<code>:visited</code> ссылки.</td> + </tr> + <tr> + <td>{{ Cssxref(":blank") }}</td> + <td>Соответствует <a href="https://wiki.developer.mozilla.org/ru/docs/Web/HTML/Element/Input">элементу <code><input></code></a>, для которого значение ввода является пустым.</td> + </tr> + <tr> + <td>{{ Cssxref(":checked") }}</td> + <td>Соответствует переключателю или флажку в выбранном состоянии.</td> + </tr> + <tr> + <td>{{ Cssxref(":current") }}</td> + <td>Соответствует элементу или предку элемента, который в данный момент отображается.</td> + </tr> + <tr> + <td>{{ Cssxref(":default") }}</td> + <td>Соответствует одному или нескольким элементам пользовательского интерфейса, которые являются элементами по умолчанию (<em>обрабатывают нажатие клавиши enter</em>) в наборе сходных элементов.</td> + </tr> + <tr> + <td>{{ Cssxref(":dir") }}</td> + <td>Выбирает элемент на основе его направленности (значение атрибута HTML <code><a href="https://wiki.developer.mozilla.org/ru/docs/Web/HTML/Global_attributes/dir">dir</a></code> или свойства CSS <code><a href="https://wiki.developer.mozilla.org/ru/docs/Web/CSS/direction">direction</a></code> ).</td> + </tr> + <tr> + <td>{{ Cssxref(":disabled") }}</td> + <td>Соответствует элементам пользовательского интерфейса, которые находятся в отключённом состоянии.</td> + </tr> + <tr> + <td>{{ Cssxref(":empty") }}</td> + <td>Соответствует элементу, у которого нет дочерних элементов, кроме необязательного пробела.</td> + </tr> + <tr> + <td>{{ Cssxref(":enabled") }}</td> + <td>Соответствует элементам пользовательского интерфейса, которые находятся во включённом состоянии.</td> + </tr> + <tr> + <td>{{ Cssxref(":first") }}</td> + <td>В <a href="https://wiki.developer.mozilla.org/ru/docs/Web/CSS/Paged_Media">постраничном носителе</a> соответствует первой странице.</td> + </tr> + <tr> + <td>{{ Cssxref(":first-child") }}</td> + <td>Соответствует элементу, который является первым среди других дочерних элементов одного предка.</td> + </tr> + <tr> + <td>{{ Cssxref(":first-of-type") }}</td> + <td>Соответствует элементу, который является первым определенного типа среди других дочерних элементов одного предка.</td> + </tr> + <tr> + <td>{{ Cssxref(":focus") }}</td> + <td>Соответствует элементу, имеющему фокус.</td> + </tr> + <tr> + <td>{{ Cssxref(":focus-visible")}}</td> + <td>Соответствует элементу, имеющему фокус, при этом фокус должен быть виден пользователю.</td> + </tr> + <tr> + <td>{{ Cssxref(":focus-within") }}</td> + <td>Соответствует элементу с фокусом, а также элементу с потомком, который имеет фокус.</td> + </tr> + <tr> + <td>{{ Cssxref(":future") }}</td> + <td>Соответствует элементам после текущего элемента.</td> + </tr> + <tr> + <td>{{ Cssxref(":hover") }}</td> + <td>Соответствует элементу, на который наведён курсор мыши.</td> + </tr> + <tr> + <td>{{ Cssxref(":indeterminate") }}</td> + <td>Соответствует элементам пользовательского интерфейса, значение которых находится в неопределенном состоянии, обычно <a href="https://wiki.developer.mozilla.org/ru/docs/Web/HTML/Element/Input/checkbox">checkboxes</a>.</td> + </tr> + <tr> + <td>{{ Cssxref(":in-range") }}</td> + <td>Соответствует элементу с диапазоном, когда его значение находится в пределах диапазона.</td> + </tr> + <tr> + <td>{{ Cssxref(":invalid") }}</td> + <td>Соответствует элементу, например <code><input></code>, в недопустимом состоянии.</td> + </tr> + <tr> + <td>{{ Cssxref(":lang") }}</td> + <td>Соответствует элементу, основанному на языке (значение атрибута HTML <a href="https://wiki.developer.mozilla.org/ru/docs/Web/HTML/Global_attributes/lang">lang</a>).</td> + </tr> + <tr> + <td>{{ Cssxref(":last-child") }}</td> + <td>Соответствует элементу, который является последним среди других дочерних элементов одного предка.</td> + </tr> + <tr> + <td>{{ Cssxref(":last-of-type") }}</td> + <td>Соответствует элементу, который является последним определённого типа среди других дочерних элементов одного предка.</td> + </tr> + <tr> + <td>{{ Cssxref(":left") }}</td> + <td>В <a href="https://wiki.developer.mozilla.org/ru/docs/Web/CSS/Paged_Media">постраничном носителе</a> соответствует левосторонним страницам.</td> + </tr> + <tr> + <td>{{ Cssxref(":link")}}</td> + <td>Соответствует непосещавшимся ссылкам.</td> + </tr> + <tr> + <td>{{ Cssxref(":local-link")}}</td> + <td>Соответствует ссылкам, указывающим на страницы, которые расположены на том же сайте, что и текущий документ.</td> + </tr> + <tr> + <td>{{ Cssxref(":is", ":is()")}}</td> + <td>Соответствует любому селектору из полученного списка селекторов.</td> + </tr> + <tr> + <td>{{ Cssxref(":not") }}</td> + <td>Соответствует объектам, не входящим в список селекторов, переданный в качестве значения этому селектору.</td> + </tr> + <tr> + <td>{{ Cssxref(":nth-child") }}</td> + <td>Соответствует элементам из списка дочерних элементов одного предка, которые подобраны по формуле вида <em>an+b</em> (например, 2n + 1 будет соответствовать элементам 1, 3, 5, 7 и т. д. Все нечетные числа.)</td> + </tr> + <tr> + <td>{{ Cssxref(":nth-of-type") }}</td> + <td>Соответствует элементам из списка дочерних элементов одного предка, имеющим определенный тип (например, элементы <p>) — дочерние элементы подобраны по формуле вида <em>an+b</em> (например, 2n + 1 будет соответствовать элементам 1, 3, 5, 7 и т. д. Все нечетные числа.)</td> + </tr> + <tr> + <td>{{ Cssxref(":nth-last-child") }}</td> + <td>Соответствует элементам из списка дочерних элементов одного предка, считая в обратном порядке от конца. Дочерние элементы подобраны по формуле вида <em>an+b</em> (например, 2n + 1 будет соответствовать последнему элементу в последовательности, затем на два элемента до него, затем ещё на два элемента назад и т. д. Все нечетные, считая с конца.)</td> + </tr> + <tr> + <td>{{ Cssxref(":nth-last-of-type") }}</td> + <td>Соответствует элементам из списка дочерних элементов одного предка, имеющим определенный тип (например, элементы <p>), считая в обратном порядке от конца. Дочерние элементы подобраны по формуле вида <em>an+b</em> (например, 2n + 1 будет соответствовать последнему элементу этого типа в последовательности, затем на два элемента до него, затем ещё на два элемента назад и т. д. Все нечетные, считая с конца.)</td> + </tr> + <tr> + <td>{{ Cssxref(":only-child") }}</td> + <td>Соответствует элементу, являющемуся единственным дочерним для своего предка.</td> + </tr> + <tr> + <td>{{ Cssxref(":only-of-type") }}</td> + <td>Соответствует элементу, который отличается по типу от всех других дочерних элементов общего предка.</td> + </tr> + <tr> + <td>{{ Cssxref(":optional") }}</td> + <td>Соответствует необязательным элементам формы.</td> + </tr> + <tr> + <td>{{ Cssxref(":out-of-range") }}</td> + <td>Соответствует элементу с диапазоном, когда его значение находится вне диапазона.</td> + </tr> + <tr> + <td>{{ Cssxref(":past") }}</td> + <td>Соответствует элементам перед текущим элементом.</td> + </tr> + <tr> + <td>{{ Cssxref(":placeholder-shown") }}</td> + <td>Соответствует элементу input, который показывает текст-заполнитель.</td> + </tr> + <tr> + <td>{{ Cssxref(":playing") }}</td> + <td>Соответствует элементу, представляющему аудио, видео или подобный ресурс с возможными состояниями “воспроизведён” или “приостановлен”, когда этот элемент “воспроизводится”.</td> + </tr> + <tr> + <td>{{ Cssxref(":paused") }}</td> + <td>Соответствует элементу, представляющему аудио, видео или подобный ресурс с возможными состояниями “воспроизведён” или “приостановлен”, когда этот элемент “приостановлен”.</td> + </tr> + <tr> + <td>{{ Cssxref(":read-only") }}</td> + <td>Соответствует элементу, который не может быть изменён пользователем.</td> + </tr> + <tr> + <td>{{ Cssxref(":read-write") }}</td> + <td>Соответствует элементу, который может быть изменён пользователем.</td> + </tr> + <tr> + <td>{{ Cssxref(":required") }}</td> + <td>Соответствует обязательным элементам формы.</td> + </tr> + <tr> + <td>{{ Cssxref(":right") }}</td> + <td>В <a href="https://wiki.developer.mozilla.org/ru/docs/Web/CSS/Paged_Media">постраничном носителе</a> соответствует правосторонним страницам.</td> + </tr> + <tr> + <td>{{ Cssxref(":root") }}</td> + <td>Соответствует элементу, который является корнем документа.</td> + </tr> + <tr> + <td>{{ Cssxref(":scope") }}</td> + <td>Соответствует любому элементу, который является элементом области видимости.</td> + </tr> + <tr> + <td>{{ Cssxref(":valid") }}</td> + <td>Соответствует элементу, такому как <input>, в допустимом состоянии.</td> + </tr> + <tr> + <td>{{ Cssxref(":target") }}</td> + <td>Соответствует элементу, если он является целью текущего URL (т. е. если у него есть ID, соответствующий текущему <a href="https://en.wikipedia.org/wiki/Fragment_identifier">URL fragment</a>).</td> + </tr> + <tr> + <td>{{ Cssxref(":visited") }}</td> + <td>Соответствует посещённым ссылкам.</td> + </tr> + </tbody> +</table> + +<h3 id="Псевдоэлементы">Псевдоэлементы</h3> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Селектор</th> + <th scope="col">Описание</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{ Cssxref("::after") }}</td> + <td>Соответствует элементу, который допускает стилизацию и появляется после текущего содержимого порождающего элемента.</td> + </tr> + <tr> + <td>{{ Cssxref("::before") }}</td> + <td>Соответствует элементу, который допускает стилизацию и появляется перед текущим содержимым порождающего элемента.</td> + </tr> + <tr> + <td>{{ Cssxref("::first-letter") }}</td> + <td>Соответствует первой букве элемента.</td> + </tr> + <tr> + <td>{{ Cssxref("::first-line") }}</td> + <td>Соответствует первой строке содержимого порождающего элемента.</td> + </tr> + <tr> + <td>{{ Cssxref("::grammar-error") }}</td> + <td> + <p>Соответствует части документа, содержащей грамматическую ошибку, отмеченную браузером.</p> + </td> + </tr> + <tr> + <td>{{ Cssxref("::marker") }}</td> + <td>Соответствует полю маркера пункта списка, которое обычно содержит жирную точку или число.</td> + </tr> + <tr> + <td> + <p>{{ Cssxref("::selection") }}</p> + </td> + <td>Соответствует части документа, которая была выбрана.</td> + </tr> + <tr> + <td>{{ Cssxref("::spelling-error") }}</td> + <td> + <p>Соответствует части документа, содержащей орфографическую ошибку, отмеченную браузером.</p> + </td> + </tr> + </tbody> +</table> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Attribute_selectors", "Learn/CSS/Building_blocks/Selectors/Combinators", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B">Селекторы CSS</a> + <ul> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Type_Class_and_ID_Selectors">Селекторы типа, класса и ID</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Attribute_selectors">Селекторы атрибута</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">Псевдоклассы и псевдоэлементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Combinators">Комбинаторы</a></li> + </ul> + </li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/The_box_model">Модель коробки</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Фон и границы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Обработка разных направлений текста</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Overflowing_content">Переполнение содержимого</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Values_and_units">Значения и единицы измерения</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Изменение размеров в CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Элементы изображений, форм и медиа-элементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Styling_tables">Стилизация таблиц</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Organizing">Организация вашей CSS</a><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing"> </a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/селекторы/type_class_and_id_selectors/index.html b/files/ru/learn/css/building_blocks/селекторы/type_class_and_id_selectors/index.html new file mode 100644 index 0000000000..875899ab41 --- /dev/null +++ b/files/ru/learn/css/building_blocks/селекторы/type_class_and_id_selectors/index.html @@ -0,0 +1,130 @@ +--- +title: 'Селекторы типа, класса и ID' +slug: Learn/CSS/Building_blocks/Селекторы/Type_Class_and_ID_Selectors +tags: + - CSS + - id + - Класс + - Начинающий + - Обучение + - Селекторы +translation_of: Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors +--- +<p>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors", "Learn/CSS/Building_blocks/Selectors/Attribute_selectors", "Learn/CSS/Building_blocks")}}</p> + +<p>В этом уроке мы рассмотрим некоторые из базисных селекторов, которые вы, вероятно, будете чаще всего использовать в вашей работе.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">установка базового ПО</a>, базовые знания о <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работе с файлами</a>, основы HTML (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>) и понимание работы CSS (изучите <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>.)</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td><span class="tlid-translation translation" lang="ru"><span title="">Изучить различные селекторы CSS, которые мы можем использовать, чтобы применить CSS к документу.</span></span></td> + </tr> + </tbody> +</table> + +<h2 id="Селекторы_типа">Селекторы типа</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title=""><strong>Селектор типа</strong> иногда называется <em>селектором имени тега</em> или <em>селектором элемента</em>, поскольку он выбирает тег/элемент HTML в вашем документе.</span></span> В примере ниже мы использовали селекторы span, em и strong.</p> + +<p><strong>Попробуйте добавить CSS-правило, чтобы выбрать элемент <code><h1></code> и изменить его цвет на синий.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/type.html", '100%', 1100)}}</p> + +<h2 id="Универсальный_селектор">Универсальный селектор</h2> + +<p>Универсальный селектор обозначается звездочкой (<code>*</code>). Он выбирает всё в документе (или внутри родительского элемента, если он сцеплен с другим элементом и с комбинатором потомка). В следующем примере мы используем универсальный селектор, чтобы убрать внешние отступы у всех элементов. Несмотря на стилизацию по умолчанию, добавленную браузером, — она раздвигает заголовки и абзацы с помощью отступов, — всё плотно сжато.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/universal.html", '100%', 750)}}</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Такого рода поведение иногда можно увидеть в «таблицах сброса стилей», которые вычищают всю стилизацию браузера.</span></span> Так как <span class="tlid-translation translation" lang="ru"><span title="">универсальный селектор вызывает глобальные изменения, </span></span><span class="tlid-translation translation" lang="ru"><span title="">мы используем его в очень специфических ситуациях, таких как та, что описана ниже.</span></span></p> + +<h3 id="Использование_универсального_селектора_для_облегчения_чтения_ваших_селекторов"><span class="tlid-translation translation" lang="ru"><span title="">Использование универсального селектора для облегчения чтения ваших селекторов</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Одно из применений универсального селектора состоит в том, чтобы облегчить чтение селекторов и сделать их более удобопонятными с точки зрения того, что они делают.</span></span> Например, если мы хотим выбрать элементы-потомки элемента <code><article></code>, которые являются первыми дочерними элементами своего родителя, включая дочерние элементы самого <code><article></code>, и сделать их шрифт жирным, мы могли бы использовать псевдо-класс {{cssxref(":first-child")}}, который мы будем изучать в уроке о <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">псевдо-классах и псевдо-элементах</a>, как селектор-потомок вместе с селектором элемента <code><article></code>: </p> + +<pre class="brush: css notranslate">article :first-child { + font-weight: bold; +}</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Однако этот селектор можно спутать с</span></span> <code>article:first-child</code>, <span class="tlid-translation translation" lang="ru"><span title="">который выберет любой элемент</span></span> <code><article></code><span class="tlid-translation translation" lang="ru"><span title="">, являющийся первым дочерним элементом другого элемента</span></span> .</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Чтобы избежать этой путаницы, мы можем добавить универсальный селектор в псевдо-класс</span></span> <code>:first-child</code> <span class="tlid-translation translation" lang="ru"><span title="">, чтобы было очевидно, что делает селектор.</span> <span title="">Он выбирает <em>любой</em> элемент, который является первым дочерним элементом элемента</span></span> <code><article></code> или <span class="tlid-translation translation" lang="ru"><span title="">первым дочерним элементом любого потомка</span></span> <span class="tlid-translation translation" lang="ru"><span title="">элемента</span></span> <code><article></code>:</p> + +<pre class="brush: css notranslate">article *:first-child { + font-weight: bold; +} </pre> + +<p>Хотя оба делают одно и то же, удобочитаемость значительно улучшилась.</p> + +<h2 id="Селекторы_класса">Селекторы класса</h2> + +<p>Селектор класса начинается с символа точки (<code>.</code>). Он выберет в документе всё, к чему применён этот класс. В живом примере ниже мы создали класс с именем <code>.highlight</code>, и применили его к нескольким местам в документе. <span class="tlid-translation translation" lang="ru"><span title="">Все элементы, к которым применён класс, подсвечиваются</span></span>.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/class.html", '100%', 750)}}</p> + +<h3 id="Нацеливание_классов_на_отдельные_элементы"><span class="tlid-translation translation" lang="ru"><span title="">Нацеливание классов на отдельные элементы</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете создать селектор, нацеленный на конкретные элементы, к которым применён класс</span></span>. В следующем примере мы подсветим <code><span></code> с классом <code>highlight</code> иначе, чем заголовок <code><h1></code> с классом <code>highlight</code>. <span class="tlid-translation translation" lang="ru"><span title="">Мы сделаем это, используя селектор типа для элемента, на который нацелены, с классом, добавленным с помощью точки, без пробела между ними</span></span>.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/class-type.html", '100%', 750)}}</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Этот подход сужает границы правила. Правило будет применяться только к этой конкретной комбинации элемента и класса. Вам нужно будет добавить другой селектор, если вы решили, что правило должно применяться и к другим элементам.</span></span></p> + +<h3 id="Нацеливание_на_элемент_к_которому_применено_более_одного_класса"><span class="tlid-translation translation" lang="ru"><span title="">Нацеливание на элемент, к которому применено более одного класса</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете применить несколько классов к элементу и нацелиться на них по отдельности, или выбрать элемент только если присутствуют все классы селектора.</span> <span title="">Это может быть полезно при создании компонентов, которые могут сочетаться на вашем сайте разными способами.</span></span></p> + +<p>В примере ниже у нас есть <code><div></code>, содержащий примечание. Серая граница применятеся когда блок имеет класс <code>notebox</code>. Если у блока есть также класс <code>warning</code> или <code>danger</code>, мы меняем {{cssxref("border-color")}}.</p> + +<p>Мы можем указать браузеру, что мы хотим подобрать только такой элемент, <span class="tlid-translation translation" lang="ru"><span title="">к которому применены два класса, сцепив их вместе без пробелов между ними. </span></span> <span class="tlid-translation translation" lang="ru"><span title="">Вы увидите, что к последнему </span></span><code><div></code> <span class="tlid-translation translation" lang="ru"><span title=""> не применён ни один стиль, так как он имеет только класс</span></span> <code>danger</code>; <span class="tlid-translation translation" lang="ru"><span title="">ему нужен ещё и класс </span></span> <code>notebox</code><span class="tlid-translation translation" lang="ru"><span title="">, чтобы получить какую-нибудь стилизацию.</span></span></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/class-many.html", '100%', 900)}}</p> + +<h2 id="Селекторы_ID">Селекторы ID</h2> + +<p>Селектор ID начинается с <code>#</code>, а не с точки, но используется так же, как и селектор класса. Однако ID может быть использован единожды на странице, и к элементу может быть применён только один <code>id</code>. Можно выбрать элемент, которому присвоен <code>id</code>, а также вы можете предварить ID селектором типа для нацеливания на элемент, имеющий соответствующее сочетание элемента и ID. Вы можете увидеть оба варианта использования в следующем примере:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/id.html", '100%', 750)}}</p> + +<div class="blockIndicator warning"> +<p><strong>Предупреждение: </strong>Может показаться, что неоднократное использование в документе одного и того же ID выполняет задачи стилизования, но не стоит этого делать. Результатом будет неверный код, который приведёт к многочисленным странностям в поведении.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Примечание:</strong> Как мы знаем из урока по специфичности, ID имеет высокую специфичность. Он будет брать верх над большинством других селекторов. В большинстве случаев предпочтительнее добавить элементу класс, чем ID. Однако, если использование ID это единственный способ нацелиться на элемент — возможно, потому вы не имеете доступа к разметке и, следовательно, возможности её редактировать — это будет работать.</p> +</div> + +<h2 id="В_следующей_статье">В следующей статье</h2> + +<p>Мы продолжим изучение селекторов и рассмотрим <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Attribute_selectors">селекторы атрибута</a>.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors", "Learn/CSS/Building_blocks/Selectors/Attribute_selectors", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B">Селекторы CSS</a> + <ul> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Type_Class_and_ID_Selectors">Селекторы типа, класса и ID</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Attribute_selectors">Селекторы атрибута</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Pseudo-classes_and_pseudo-elements">Псевдоклассы и псевдоэлементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B/Combinators">Комбинаторы</a></li> + </ul> + </li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/The_box_model">Модель коробки (The box model)</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Фон и границы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Обработка разных направлений текста</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Overflowing_content">Переполнение содержимого</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Values_and_units">Значения и единицы измерения</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Изменение размеров в CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Элементы изображений, форм и медиа-элементы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Styling_tables">Стилизация таблиц</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Organizing">Организация вашей CSS</a></li> +</ol> diff --git a/files/ru/learn/css/building_blocks/селекторы/селекторы_задачи/index.html b/files/ru/learn/css/building_blocks/селекторы/селекторы_задачи/index.html new file mode 100644 index 0000000000..b8f36063c2 --- /dev/null +++ b/files/ru/learn/css/building_blocks/селекторы/селекторы_задачи/index.html @@ -0,0 +1,137 @@ +--- +title: 'Проверьте ваши навыки: Селекторы' +slug: Learn/CSS/Building_blocks/Селекторы/Селекторы_Задачи +tags: + - CSS + - Начинающий +translation_of: Learn/CSS/Building_blocks/Selectors/Selectors_Tasks +--- +<div>{{LearnSidebar}}</div> + +<div></div> + +<p>Цель этой задачи — помочь вам проверить ваше понимание селекторов в CSS.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Вы можете проверять решения в интерактивном редакторе, расположенном ниже, но, возможно, вам будут полезны онлайн-инструменты, такие как <a class="external external-icon" href="https://codepen.io/" rel="noopener">CodePen</a>, <a class="external external-icon" href="https://jsfiddle.net/" rel="noopener">jsFiddle</a> или <a class="external external-icon" href="https://glitch.com/" rel="noopener">Glitch</a>, которые можно использовать для работы над заданием, предварительно загрузив в них код.<br> + <br> + Если вы зашли в тупик, обратитесь к нам за помощью — смотрите раздел <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4_%D0%B7%D0%B0%D0%B4%D0%B0%D1%87%D0%B8#Оценка_или_дальнейшая_помощь">Оценка или дальнейшая помощь</a> внизу этой страницы.</p> +</div> + +<h2 id="Selectors_One">Selectors One</h2> + +<p>Without changing the HTML, use CSS to do the following things:</p> + +<ul> + <li>Make h1 headings blue.</li> + <li>Give h2 headings a blue background and white text.</li> + <li>Cause text wrapped in a span to have a font-size of 200%.</li> +</ul> + +<p><img alt="Text with the CSS applied for the solution to task 1." src="https://mdn.mozillademos.org/files/17118/selectors1.jpg" style="height: 781px; width: 1026px;"></p> + +<p>Try updating the live code below to recreate the finished example:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/selectors/type.html", '100%', 700)}}</p> + +<div class="blockIndicator note"> +<p>For assessment or further work purposes, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/selectors/type-download.html">download the starting point for this task</a> to work in your own editor or in an online editor.</p> +</div> + +<h2 id="Selectors_Two">Selectors Two</h2> + +<p>Without changing the HTML, make the following changes to the look of the content in this example:</p> + +<ul> + <li>Give the element with an id of <code>special</code> a yellow background.</li> + <li>Give the element with a class of <code>alert</code> a 1px grey border.</li> + <li>If the element with a class of <code>alert</code> also has a class of <code>stop</code>, make the background red.</li> + <li>If the element with a class of <code>alert</code> also has a class of <code>go</code>, make the background green.</li> +</ul> + +<p><img alt="Text with the CSS applied for the solution to task 2." src="https://mdn.mozillademos.org/files/17119/selectors2.jpg" style="height: 891px; width: 1027px;"></p> + +<p>Try updating the live code below to recreate the finished example:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/selectors/class-id.html", '100%', 800)}}</p> + +<div class="blockIndicator note"> +<p>For assessment or further work purposes, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/selectors/class-id-download.html">download the starting point for this task</a> to work in your own editor or in an online editor.</p> +</div> + +<h2 id="Selectors_Three">Selectors Three</h2> + +<p>In this example, try making the following changes without adding to the HTML.</p> + +<ul> + <li>Style links, making the link-state orange, visited links green, and remove the underline on hover.</li> + <li>Make the first element inside the container font-size: 150% and the first line of that element red.</li> + <li>Stripe every other row in the table by selecting these rows and giving them a background color of #333 and foreground of white.</li> +</ul> + +<p><img alt="Text with the CSS applied for the solution to task 3." src="https://mdn.mozillademos.org/files/17120/selectors3.jpg" style="height: 926px; width: 1227px;"></p> + +<p>Try updating the live code below to recreate the finished example:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/selectors/pseudo.html", '100%', 800)}}</p> + +<div class="blockIndicator note"> +<p>For assessment or further work purposes, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/selectors/pseudo-download.html">download the starting point for this task</a> to work in your own editor or in an online editor.</p> +</div> + +<h2 id="Selectors_Four">Selectors Four</h2> + +<p>In this task try the following:</p> + +<ul> + <li>Make any paragraph that directly follows an h2 element red.</li> + <li>Remove the bullets and add a 1px grey bottom border only to list items that are a direct child of the ul with a class of list.</li> +</ul> + +<p><img alt="Text with the CSS applied for the solution to task 4." src="https://mdn.mozillademos.org/files/17121/selectors4.jpg" style="height: 788px; width: 1222px;"></p> + +<p>Try updating the live code below to recreate the finished example:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/selectors/combinators.html", '100%', 800)}}</p> + +<div class="blockIndicator note"> +<p>For assessment or further work purposes, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/selectors/combinators-download.html">download the starting point for this task</a> to work in your own editor or in an online editor.</p> +</div> + +<h2 id="Selectors_Five">Selectors Five</h2> + +<p>In this final task add CSS using attribute selectors to do the following:</p> + +<ul> + <li>Target the <code><a></code> element with a <code>title</code> attribute and make the border pink (<code>border-color: pink</code>).</li> + <li>Target the <code><a></code> element with an <code>href</code> attribute that contains the word <code>contact</code> somewhere in its value and make the border orange (<code>border-color: orange</code>).</li> + <li>Target the <code><a></code> element with an <code>href</code> value starting with <code>https</code> and give it a green border (<code>border-color: green</code>).</li> +</ul> + +<p><img alt="Four links with different color borders." src="https://mdn.mozillademos.org/files/17147/selectors-attribute.png" style="height: 485px; width: 1264px;"></p> + +<p>Try updating the live code below to recreate the finished example:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/selectors/attribute-links.html", '100%', 800)}}</p> + +<div class="blockIndicator note"> +<p>For assessment or further work purposes, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/selectors/attribute-links-download.html">download the starting point for this task</a> to work in your own editor or in an online editor.</p> +</div> + +<h2 id="Assessment_or_further_help">Assessment or further help</h2> + +<p>You can practice these examples in the Interactive Editors mentioned above.</p> + +<p>If you would like your work assessed, or are stuck and want to ask for help:</p> + +<ol> + <li>Put your work into an online shareable editor such as <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, or <a href="https://glitch.com/">Glitch</a>. You can write the code yourself, or use the starting point files linked to in the above sections.</li> + <li>Write a post asking for assessment and/or help at the <a class="external external-icon" href="https://discourse.mozilla.org/c/mdn/learn" rel="noopener">MDN Discourse forum Learning category</a>. Your post should include: + <ul> + <li>A descriptive title such as "Assessment wanted for Selectors skill test 1".</li> + <li>Details of what you have already tried, and what you would like us to do, e.g. if you are stuck and need help, or want an assessment.</li> + <li>A link to the example you want to be assessed or need help with, in an online shareable editor (as mentioned in step 1 above). This is a good practice to get into — it's very hard to help someone with a coding problem if you can't see their code.</li> + <li>A link to the actual task or assessment page, so we can find the question you want help with.</li> + </ul> + </li> +</ol> diff --git a/files/ru/learn/css/css_layout/flexbox/index.html b/files/ru/learn/css/css_layout/flexbox/index.html new file mode 100644 index 0000000000..fcb1840af7 --- /dev/null +++ b/files/ru/learn/css/css_layout/flexbox/index.html @@ -0,0 +1,314 @@ +--- +title: Flexbox +slug: Learn/CSS/CSS_layout/Flexbox +tags: + - CSS + - Обучение + - Стилизация +translation_of: Learn/CSS/CSS_layout/Flexbox +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Practical_positioning_examples", "Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">Это новая технология, которая уже имеет достаточно широкую поддержку браузеров. Flexbox предоставляет инструменты для быстрого создания сложных, гибких макетов, и функции, которые были сложны в традиционных методах CSS. В этой статье объясняются все основы данной технологии.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td>HTML основы (изучите <a href="ru/docs/Learn/HTML/Введение_в_HTML">Введение в HTML</a>), знание того, как работает CSS (изучите <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Вступление в CSS</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Узнать, как использовать систему адаптируемых блоков Flexbox для создания веб-макетов.</td> + </tr> + </tbody> +</table> + +<h2 id="Почему_Flexbox">Почему Flexbox?</h2> + +<p>Долгое время единственными надёжными инструментами CSS верстки были такие способы как Float (обтекание) и позиционирование.</p> + +<p>С их помощью сложно или невозможно достичь следующих простых требований к макету:</p> + +<ul> + <li>Вертикального выравнивания блока внутри родителя.</li> + <li>Оформления всех детей контейнера так, чтобы они распределили между собой доступную ширину/высоту, независимо от того, сколько ширины/высоты доступно.</li> + <li>Сделать все колонки в макете одинаковой высоты, даже если наполнение в них различно.</li> +</ul> + +<p>Как вы увидите в последующих разделах, flexbox значительно облегчает работу с макетами. Погружаемся!</p> + +<h2 id="Разберём_простой_пример">Разберём простой пример</h2> + +<p>В этой статье вы проработаете серию упражнений, которые помогут понять, как работает flexbox. Чтобы начать, скачайте на компьютер стартовый файл — <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox0.html">flexbox0.html</a> с нашего Github репозитория — загрузите его в современном браузере (Firefox или Chrome), а также в любимом редакторе кода. Также вы можете <a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox0.html">посмотреть его вживую</a>.</p> + +<p>Вы увидите элемент {{htmlelement("header")}} с заголовком верхнего уровня внутри, и элемент {{htmlelement("section")}} содержащий три элемента {{htmlelement("article")}}. Мы будем использовать их для создания стандартного трехколоночного макета.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13406/flexbox-example1.png" style="border-style: solid; border-width: 1px; display: block; height: 324px; margin: 0px auto; width: 800px;"></p> + +<h2 id="Определяем_какие_элементы_разместить_в_виде_flex_блоков">Определяем, какие элементы разместить в виде flex блоков</h2> + +<p>Для начала нам нужно выбрать, какие элементы следует выкладывать в виде flex блоков. Для этого мы устанавливаем специальное значение {{cssxref ("display")}} в родительском элементе тех элементов, которые вы хотите оформить. В нашем случае мы хотим расположить элементы {{htmlelement ("article")}}, поэтому мы устанавливаем это значение на {{htmlelement ("section")}} (который становится flex контейнером):</p> + +<pre class="brush: css notranslate">section { + display: flex; +}</pre> + +<p>В результате у нас получится вот так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13408/flexbox-example2.png" style="border-style: solid; border-width: 1px; display: block; height: 348px; margin: 0px auto; width: 800px;"></p> + +<p>Так, всего одно объявление делает всё, что нам нужно — здорово, правда? Мы получили 3-х колоночный макет с колонками равных размеров по ширине и высоте. Это связано с тем, что значения по умолчанию, заданные для flex элементов (дочерние элементы flex контейнера), настроены для решения основных задач. Подробнее об этом позже.</p> + +<p><strong>Примечание</strong>: Вы также можете установить значение {{cssxref("display")}} <code>inline-flex, </code>если хотите расставить inline элементы как flex блоки.</p> + +<h2 id="Внутри_flex_модели">Внутри flex модели</h2> + +<p>Когда элементы выложены как flex блоки, они располагаются вдоль двух осей:</p> + +<p><img alt="flex_terms.png" class="default internal" src="/files/3739/flex_terms.png" style="display: block; margin: 0px auto;"></p> + +<ul> + <li><strong>Главная ось (main axis)</strong> проходит в том направлении, вдоль которого расположены Flex элементы (например, в строку слева направо или вдоль колонок вниз.) Начало и конец этой оси называются <strong>main start</strong> и <strong>main end</strong>.</li> + <li><strong>Поперечная ось (сross axis)</strong> проходит перпендикулярно Flex элементам. Начало и конец этой оси называются <strong>cross start</strong> and <strong>cross end</strong>.</li> + <li>Родительский элемент, на который назначено свойство <code>display: flex ( </code>{{htmlelement("section")}} в нашем примере) называется <strong>flex container</strong>.</li> + <li>Элементы, размещённые в нём как Flex блоки называются <strong>flex items</strong> (в нашем примере это {{htmlelement("article")}} ).</li> +</ul> + +<p>Запомните эти термины, они пригодятся вам в последующих разделах.</p> + +<h2 id="Столбцы_или_строки">Столбцы или строки?</h2> + +<p>В Flexbox есть свойство под названием {{cssxref("flex-direction")}}, которое определяет направление главной оси (в каком направлении располагаются flexbox-дочерние элементы) — по умолчанию ему присваивается значение <code>row</code>, т.е. располагать дочерние элементы в ряд слева направо (для большинства языков) или справа налево (для арабских языков).</p> + +<p>Попробуйте добавить следующую строчку в ваш файл:</p> + +<pre class="brush: css notranslate">flex-direction: column</pre> + +<p>Вы увидите, что элементы расположились в виде столбцов, также как было до того, как мы добавили CSS код. Прежде чем продолжать, удалите эту строчку из примера.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете также распологать flex элементы в обратном направлении, используя значения <code>row-reverse</code> и <code>column-reverse</code>. Попробуйте их тоже!</p> +</div> + +<h2 id="Перенос_строк">Перенос строк</h2> + +<p>Проблема может быть в том, что, если у вас фиксированная ширина или высота макета, ваши flexbox элементы переполнят контейнер и нарушат макет. Посмотрите на этот пример: <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox-wrap0.html">flexbox-wrap0.html</a> и <a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox-wrap0.html">посмотрите его вживую</a> (сохраните его себе на компьютер, если хотите изучить этот пример):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13410/flexbox-example3.png" style="display: block; height: 646px; margin: 0px auto; width: 800px;"></p> + +<p>Мы видим, что дочерние элементы выбиваются из своего родителя-контейнера. Один из способов как это исправить - это добавить следующее свойство:</p> + +<pre class="brush: css notranslate">flex-wrap: wrap</pre> + +<p>Попробуйте, и вы увидите, что так макет стал выглядеть гораздо лучше:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13412/flexbox-example4.png" style="display: block; height: 646px; margin: 0px auto; width: 800px;"></p> + +<p>Теперь у нас в макете несколько рядов— все дети-блоки, которые не помещаются, переносятся на следующую строку, чтобы не было переполнения. Свойство <code>flex: 200px</code>, установленное на статьях, означает, что каждый блок должен быть минимум 200 пикселей в ширину. Мы обсудим это свойство более подробно позже. Вы также можете заметить, что несколько дочерних блоков в последней строке стали более широкими, так что вся строка стала заполнена.</p> + +<p>Но мы можем пойти дальше. Прежде всего, попробуйте изменить значение свойства {{cssxref("flex-direction")}} на <code>row-reverse</code> — теперь у вас также макет в несколько строк, но он начинается из противоположного угла окна браузера и теперь выстраивается в обратном порядке.</p> + +<h2 id="flex-flow_сокращение">flex-flow сокращение</h2> + +<p>На этом этапе нужно заметить, что существует сокращение для свойств {{cssxref("flex-direction")}} и {{cssxref("flex-wrap")}} — {{cssxref("flex-flow")}}. Например, вы можете заменить</p> + +<pre class="brush: css notranslate">flex-direction: row; +flex-wrap: wrap;</pre> + +<p>на</p> + +<pre class="brush: css notranslate">flex-flow: row wrap;</pre> + +<h2 id="Гибкое_изменение_размеров_flex_элементов">Гибкое изменение размеров flex элементов</h2> + +<p>Теперь давайте вернёмся к нашему первому примеру и посмотрим, как мы можем контролировать, в каких пропорциях flex элементы будут занимать место. Включите свою копию файла <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox0.html">flexbox0.html</a>, или скачайте <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox1.html">flexbox1.html</a> (<a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox1.html">просмотр</a>).</p> + +<p>Прежде всего, добавим следующее правило в конец вашего CSS кода:</p> + +<pre class="brush: css notranslate">article { + flex: 1; +}</pre> + +<p>Это безразмерное значение пропорции, которое указывает, сколько свободного пространства на главной оси (main axis) каждый flex элемент сможет занять. В этом случае, мы даём каждому элементу {{htmlelement("article")}} значение 1, а это значит, что они будут занимать равное количество свободного места в макете, которое осталось после установки свойств padding и margin.</p> + +<p>Теперь добавьте следующее правило в строку после предыдущего:</p> + +<pre class="brush: css notranslate">article:nth-of-type(3) { + flex: 2; +}</pre> + +<p>Обновив страницу, вы увидите, что третий элемент {{htmlelement("article")}} занимает в два раза больше доступной ширины, чем два других — итого теперь доступно 4 единицы пропорции. Первые два flex элемента имеют по одной единице, поэтому берут 1/4 пространства каждый. А у третьего 2 единицы, так что он берёт 2/4 свободного места (или 1/2).</p> + +<p>Вы также можете указать минимальный размер внутри значения flex. Попробуйте изменить существующие правила, добавив размеры:</p> + +<pre class="brush: css notranslate">article { + flex: 1 200px; +} + +article:nth-of-type(3) { + flex: 2 200px; +}</pre> + +<p>Это просто означает, что каждому flex элементу сначала будет дано 200px от свободного места. Потом оставшееся место будет поделено в соответствии с частями пропорций. Обновите страницу, и вы увидите разницу, как пространство поделено теперь.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13406/flexbox-example1.png" style="border-style: solid; border-width: 1px; display: block; height: 324px; margin: 0px auto; width: 800px;"></p> + +<p>Настоящая ценность flexbox можно увидеть в его гибкости/отзывчивости — если изменить размер окна или добавить ещё элемент {{htmlelement("article")}}, макет будет и дальше выглядеть также хорошо.</p> + +<h2 id="flex_краткий_код_против_развёрнутого">flex: краткий код против развёрнутого</h2> + +<p>{{cssxref("flex")}} это сокращённое свойство, в которым можно задать до трёх разных свойств:</p> + +<ul> + <li>Значение пропорции, которое мы обсуждали выше. Оно может быть установлено отдельно с помощью свойства {{cssxref("flex-grow")}}.</li> + <li>Следующее значение пропорции — {{cssxref("flex-shrink")}} — вступает в роль, когда flex элементы переполняют контейнер. Оно указывает, сколько забирается от размера каждого flex элемента, чтобы он перестал переполнять контейнер. Это продвинутая функция flexbox, и в этом параграфе мы не будем её разбирать.</li> + <li>Значение минимального размера, как мы обсуждали ранее. Оно может быть установлено отдельно с помощью свойства {{cssxref("flex-basis")}}.</li> +</ul> + +<p>Мы не советуем использовать развёрнутые свойства flex, если вам в действительности это не нужно (например, переопределить ранее установленное). Они приводят к написанию большого количества дополнительного кода и могут запутать кого угодно.</p> + +<h2 id="Горизонтальное_и_вертикальное_выравнивание">Горизонтальное и вертикальное выравнивание</h2> + +<p>Flexbox также имеет функции для выравнивания flex элементов вдоль основной (main) или поперечной (cross) осей. Рассмотрим их на новом примере — <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flex-align0.html">flex-align0.html</a> (<a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flex-align0.html">просмотр</a>) — который мы превратим в аккуратную, гибкую кнопочную панель инструментов. На данный момент вы видите горизонтальную панель меню, кнопки которой застряли в верхнем левом углу.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13414/flexbox-example5.png" style="display: block; height: 77px; margin: 0px auto; width: 600px;"></p> + +<p>Сначала сделайте себе копию этого примера.</p> + +<p>Теперь добавьте следующую строку в низ кода CSS:</p> + +<pre class="brush: css notranslate">div { + display: flex; + align-items: center; + justify-content: space-around; +}</pre> + +<p>Обновите страницу, и вы увидите, что кнопки теперь хорошо центрированы, горизонтально и вертикально. Мы сделали это с помощью двух новых свойств.</p> + +<p>{{cssxref("align-items")}} контролирует, где на поперечной оси находятся flex элементы.</p> + +<ul> + <li>По умолчанию стоит значение <code>stretch</code>, которое растягивает все flex элементы, чтобы заполнить родителя вдоль поперечной (cross axis) оси. Если у родителя нет фиксированной ширины вдоль поперечной оси, все flex элементы примут длину самого длинного flex элемента. Вот почему наш первый пример по умолчанию получил столбцы с одинаковой высотой.</li> + <li>Значение <code>center</code> , которое мы использовали в коде вверху, заставляет элементы сохранять свои собственные размеры, но центрирует их вдоль поперечной оси. Вот почему кнопки текущего примера центрированы по вертикали.</li> + <li>Также есть значения <code>flex-start</code> и <code>flex-end</code>, которые выравнивают все элементы по началу и концу поперечной оси соответственно. См. подробнее {{cssxref("align-items")}}.</li> +</ul> + +<p>Вы можете переопределить {{cssxref("align-items")}} поведение для отдельных flex элементов, применив свойство {{cssxref("align-self")}} к ним. Например, попробуйте добавить эти строки в код:</p> + +<pre class="brush: css notranslate">button:first-child { + align-self: flex-end; +}</pre> + +<p>Посмотрите, что произошло и удалите эти строки.</p> + +<p>{{cssxref("justify-content")}} контролирует, где flex элементы располагаются на главной оси.</p> + +<ul> + <li>По умолчанию стоит значение <code>flex-start</code>, которое располагает все элементы в начале главной оси. </li> + <li>Также можно использовать <code>flex-end, </code>чтобы расположить их в конце.</li> + <li><code>center</code> - также одно из значений <code>justify-content</code>, располагает все элементы по центру главной оси.</li> + <li>Значение, которое мы использовали выше, <code>space-around</code>, весьма полезно — оно распределяет все элементы равномерно по главной оси, с небольшим количеством свободного места на обоих концах.</li> + <li>И ещё одно значение, <code>space-between</code>, которое очень похоже на <code>space-around,</code> за исключением того, что оно не оставляет места на обоих концах.</li> +</ul> + +<p>Попробуйте немного поиграть с этими значениями прежде чем продолжить</p> + +<h2 id="Порядок_элементов_flex">Порядок элементов flex</h2> + +<p>В Flexbox также есть возможность менять порядок расположения flex элементов, не влияя на исходный порядок. Это ещё одна вещь, которую невозможно сделать традиционными методами CSS.</p> + +<p>Код здесь простой: попробуйте добавить следующий CSS вниз вашего кода примера:</p> + +<pre class="brush: css notranslate">button:first-child { + order: 1; +}</pre> + +<p>и теперь вы увидите, что кнопка «Smile» переместилась в конец главной оси. Давайте теперь поговорим подробнее о том, как это работает:</p> + +<ul> + <li>По умолчанию все элементы flex имеют значение {{cssxref ("order")}} равное 0.</li> + <li>Элементы Flex с установленными на них бОльшими значениями будут отображаться позже в порядке отображения, чем элементы с меньшими значениями порядка.</li> + <li>Элементы Flex с одинаковым значением порядка будут отображаться в исходном порядке. Так, если у вас есть четыре элемента с порядковыми значениями 2, 1, 1 и 0, установленными на них соответственно, их порядок отображения будет 4-й, 2-й, 3-й, затем 1-й.</li> + <li>Третий элемент появляется после второго, потому что он имеет то же значение порядка и находится после него в порядке написания.</li> +</ul> + +<p>Вы можете установить отрицательные значения , чтобы элементы отображались раньше, чем элементы с установленным 0. Например, вы можете сделать, чтобы кнопка «Blush» появлялась в начале основной оси, используя следующее правило:</p> + +<pre class="brush: css notranslate">button:last-child { + order: -1; +}</pre> + +<h2 id="Вложенные_flex_блоки">Вложенные flex блоки</h2> + +<p>Можно создать несколько довольно сложных макетов с помощью flexbox. Совершенно нормально сделать flex элемент flex контейнером, чтобы его потомки также были flex блоками. Посмотрите на <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/complex-flexbox.html">complex-flexbox.html</a> (<a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/complex-flexbox.html">см. вживую</a>).</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13418/flexbox-example7.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>HTML для этого довольно простой. У нас есть элемент {{htmlelement ("section")}}, содержащий три {{htmlelement ("article")}}. Третий {{htmlelement ("article")}} содержит ещё три {{htmlelement ("div")}}.</p> + +<pre class="notranslate">section - article + article + article - div - button + div button + div button + button + button</pre> + +<p>Давайте посмотрим на код, который мы использовали для макета.</p> + +<p>Прежде всего, мы устанавливаем дочерние элементы {{htmlelement ("section")}} в виде flex блоков.</p> + +<pre class="brush: css notranslate">section { + display: flex; +}</pre> + +<p>Затем мы устанавливаем несколько значений на самих {{htmlelement ("article")}}. Обратите внимание на второе правило: мы устанавливаем третий {{htmlelement ("article")}}, чтобы его дети были в макете в виде flex блоков, но на этот раз мы располагаем их как столбец.</p> + +<pre class="brush: css notranslate">article { + flex: 1 200px; +} + +article:nth-of-type(3) { + flex: 3 200px; + display: flex; + flex-flow: column; +} +</pre> + +<p>Затем мы берём первый {{htmlelement ("div")}}. Сначала мы пишем flex: 1 100px; чтобы дать ему минимальную высоту 100px, потом мы устанавливаем его дочерние элементы (элементы {{htmlelement ("button")}}) также в виде flex блоков. Им мы назначаем перенос блоков и выравниваем их по центру доступного пространства, как это было в примере с кнопкой.</p> + +<pre class="brush: css notranslate">article:nth-of-type(3) div:first-child { + flex: 1 100px; + display: flex; + flex-flow: row wrap; + align-items: center; + justify-content: space-around; +}</pre> + +<p>Наконец, мы устанавливаем размер кнопке, мы даем ему значение flex 1. Это даёт очень интересный эффект, который вы увидите, если попытаетесь изменить размер ширины окна браузера. Кнопки занимают столько места, сколько могут, и сидят на одной линии также, сколько могут. Если же они не могут комфортно расположиться на одной линии, они перепрыгнут на новые строки.</p> + +<pre class="brush: css notranslate">button { + flex: 1; + margin: 5px; + font-size: 18px; + line-height: 1.5; +}</pre> + +<h2 id="Совместимость_с_браузерами">Совместимость с браузерами</h2> + +<p>Поддержка Flexbox доступна в большинстве новых браузеров: Firefox, Chrome, Opera, Microsoft Edge и IE 11, более поздних версиях Android / iOS и т. д.. Однако помните, что до сих пор используются более старые браузеры, которые не поддерживают Flexbox ( или поддерживают, но старую версию.)</p> + +<p>Пока вы просто учитесь и экспериментируете, это не имеет большого значения. Однако, если вы рассматриваете возможность использования flexbox на реальном веб-сайте, вам необходимо провести тестирование и убедиться, что ваш пользовательский интерфейс по-прежнему приемлем в максимально возможном количестве браузеров.</p> + +<p>Flexbox немного сложнее, чем некоторые функции CSS. Например, если в браузере отсутствует поддержка CSS тени, сайт по-прежнему будет можно использовать. А вот неподдерживаемые функции flexbox, возможно, полностью сломают макет, что сделает сайт непригодным.</p> + +<p>Мы обсудим возможности преодоления проблем поддержки кросс-браузерности в следующем модуле.</p> + +<h2 id="Подытожим">Подытожим</h2> + +<p>Мы завершаем нашу статью по основам flexbox. Надеемся, что вам понравилось, и вы хорошо развлечётесь, путешествуя дальше и изучая его. Далее мы рассмотрим еще один важный аспект макетов CSS - grid-системы.</p> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Practical_positioning_examples", "Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout")}}</div> diff --git a/files/ru/learn/css/css_layout/floats/index.html b/files/ru/learn/css/css_layout/floats/index.html new file mode 100644 index 0000000000..4c4914cbe9 --- /dev/null +++ b/files/ru/learn/css/css_layout/floats/index.html @@ -0,0 +1,517 @@ +--- +title: Float +slug: Learn/CSS/CSS_layout/Floats +translation_of: Learn/CSS/CSS_layout/Floats +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">Первоначально используемое для "обтекания" картинок текстом, свойство {{cssxref("float")}} стало одним из наиболее часто используемых инструментов для создания макетов из нескольких столбцов на веб-страницах. С появлением flexbox и grid оно снова используется как задумывалось в начале, о чем подробнее в этой статье.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные требования:</th> + <td>Базовое знакомство с HTML (изучите <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), а также идея о том как работает CSS (изучите <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a>.)</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Научиться как создавать обтекаемые свойства на веб-страницах и как использовать свойство clear и другие методы <span class="tlid-translation translation" lang="ru"><span title="">очистки обтекаемых элементов</span></span>.</td> + </tr> + </tbody> +</table> + +<h2 id="Общие_сведения_о_float">Общие сведения о float</h2> + +<p>Свойство {{cssxref("float")}} вводилось для того, чтобы разработчики могли включать изображение, с обтеканием текста вокруг него слева или справа, как это часто используется в газетах.</p> + +<p>Но разработчики быстро осознали, что можно обтекать все что угодно, не только изображения, поэтому использование float расширилось, например для верстки забавных эффектов таких как <a href="https://css-tricks.com/snippets/css/drop-caps/">drop-caps</a> (буквица).</p> + +<p>Floats очень часто использовались для создания макетов целых веб-страниц, отображающих несколько колонок информации, обтекаемых так, что колонки располагаются друг за другом (поведение по умолчанию предполагает, что колонки должны располагаются друг за другом, в том же порядке в котором они появляются в источнике). Доступны более новые, лучшие методы и поэтому использование floats для этих целей следует рассматривать как <a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">устаревшей техникой</a>.</p> + +<p>В этой статье мы сконцентрируемся только на надлежащем использовании floats.</p> + +<h2 id="Простой_пример_float">Простой пример float</h2> + +<p>Давайте выясним как использовать floats. Мы начнем с очень простого примера включающего обтекание элемента блоком текста. Вы можете следовать за нами создав новый <code>index.html</code> файл на вашем компьютере, заполнив его <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">простым шаблоном HTML</a>, и вставив код ниже в подходящее место. В конце раздела вы можете увидеть живой пример того, как должен выглядеть финальный код.</p> + +<p>Во-первых, мы начнем с некоторого простого HTML — добавьте следующее в body вашего HTML, удалив все что там было до этого:</p> + +<pre class="brush: html notranslate"><h1>Simple float example</h1> + +<div class="box">Float</div> + +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> + +<p>Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p></pre> + +<p>А теперь примените следующий CSS для вашего HTML (используя элемент {{htmlelement("style")}} или {{htmlelement("link")}} на отдельный файл <code>.css</code> — на ваше усмотрение):</p> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.box { + width: 150px; + height: 100px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +}</pre> + +<p>Если вы сохраните и обновите сейчас, то <span class="tlid-translation translation" lang="ru"><span title="">вы увидите нечто похожее на то, чего ожидаете </span></span>— блок располагается выше текста, при нормальном потоке. Для того чтобы текст обтекал его вокруг добавьте два свойства к правилу <code>.box</code>:</p> + +<pre class="brush: css notranslate">.box { + float: left; + margin-right: 15px; + width: 150px; + height: 100px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +}</pre> + +<p>Если вы сохраните и обнавите сейчас, то <span class="tlid-translation translation" lang="ru"><span title="">вы увидите нечто похожее на следующее</span></span>:</p> + +<div id="Float_1"> +<div class="hidden"> +<h6 id="Float_Example_1">Float Example 1</h6> + +<pre class="brush: html notranslate"><h1>Simple float example</h1> + +<div class="box">Float</div> + +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> + +<p>Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> +</pre> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.box { + float: left; + margin-right: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Float_1', '100%', 500) }}</p> + +<p>Итак, давайте подумаем над тем, как работает float — элемент с установленным float (элемент {{htmlelement("div")}} в данном случае) изымается из нормального потока документа и крепится с левой стороны от родительского контейнера (элемент {{htmlelement("body")}} в данном случае). Любой контент, который следует ниже за обтекаемым элементом в макете при нормальном потоке теперь будет оборачивать его вокруг, заполняя пространство справа от него начиная на той же высоте что и вершина обтекаемого элемента. Там он остановится.</p> + +<p>Обтекание контента справа имеет точно такой же эффект, но наоборот — обтекаемый элемент будет прилипать справа, а контент будет оборачивать вокруг слева. Попробуйте изменить значение на <code>right</code> и замените {{cssxref("margin-right")}} на {{cssxref("margin-left")}} в последнем наборе правил, чтобы увидеть каков результат.</p> + +<p>В то время как мы можем добавлять margin к обтекаемому элементу чтобы оттолкнуть текст от него, мы не можем добавлять margin к тексту чтобы отодвинуть его от обтекаемого элемента. так происходит потому, что обтекаемые элементы изъяты из нормального потока, а следующие за ним блоки фактически располагаются за обтекаемым элементом. <span class="tlid-translation translation" lang="ru"><span title="">Вы можете продемонстрировать это, внеся некоторые изменения в ваш пример.</span></span></p> + +<p>Добавьте класс <code>special</code> к первому параграфу текста, тот который непосредственно следует за обтекаемым блоком, далее добавьте следующие правила в ваш CSS. Они дадут нашему параграфу цвет фона.</p> + +<pre class="brush: css notranslate">.special { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +} +</pre> + +<p>Чтобы эфект был лучше виден, измените <code>margin-right</code> обтекаемого объекта на <code>margin</code>, так вы получите пространство вокруг него. Вы сможете увидеть фон параграфа располагающегося прям под обтекаемым блоком, как на примере ниже.</p> + +<div id="Float_2"> +<div class="hidden"> +<h6 id="Float_Example_2">Float Example 2</h6> + +<pre class="brush: html notranslate"><h1>Simple float example</h1> + +<div class="box">Float</div> + +<p class="special">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> + +<p>Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} + +.special { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Float_2', '100%', 500) }}</p> + +<p><a href="/en-US/docs/Web/CSS/Visual_formatting_model#Line_boxes">Линейные блоки</a> нашего последующего элемента были сокращены так что текст располагается вокруг обтекаемого объекта, но из-за того, что обтекаемый объект удаляется из нормального потока блок вокруг параграфа все еще остается в полную ширину.</p> + +<h2 id="Очистка_обтекания">Очистка обтекания</h2> + +<p>Мы увидели, что обтекаемый объект удален из нормального потока и что другие элементы будут располагаться за ним, поэтому если мы хотим остановить перемещение следующего элемента нам необходимо очистить его; что достигается при помощи свойства {{cssxref("clear")}}.</p> + +<p>Добавьте класс <code>cleared</code> ко второму параграфу после обтекаемого элемента в ваш HTML из предыдущего примера. Далее добавьте следующий CSS:</p> + +<pre class="brush: css notranslate">.cleared { + clear: left; +} +</pre> + +<div id="Float_3"> +<div class="hidden"> +<h6 id="Float_Example_3">Float Example 3</h6> + +<pre class="brush: html notranslate"><h1>Simple float example</h1> + +<div class="box">Float</div> + +<p class="special">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> + +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + </pre> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} + +.special { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +} + +.cleared { + clear: left; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Float_3', '100%', 600) }}</p> + +<p>Вы должны увидеть, что следующий параграф очищает float элемента <span class="tlid-translation translation" lang="ru"><span title="">и больше не появляется рядом с ним. Свойство </span></span><code>clear</code> принимает следующие значения:</p> + +<ul> + <li><code>left</code>: очищает объекты, обтекаемые слева.</li> + <li><code>right</code>: очищает объекты, обтекаемые справа.</li> + <li><code>both</code>: очищает любые обтекаемые объекты, слева или справа.</li> +</ul> + +<h2 id="Очистка_блоков_обернутых_вокруг_обтекаемых_элементов">Очистка блоков обернутых вокруг обтекаемых элементов</h2> + +<p>Вы теперь знаете, как очистить что-либо следующее за обтекаемым элементом, но давайте посмотрим, что происходит если у вас имеется высокий обтекаемый объект и короткий параграф с блоком, оборачивающим оба элемента. Измените ваш документ так чтоб первый параграф и наш обтекаемый блок были обернуты в {{htmlelement("div")}} с классом <code>wrapper</code>.</p> + +<pre class="brush: html notranslate"><div class="wrapper"> + <div class="box">Float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate.</p> +</div> +</pre> + +<p>В вашем CSS добавьте следующее правило для класса <code>.wrapper</code> и обновите страницу:</p> + +<pre class="brush: css notranslate">.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +}</pre> + +<p>В добавок удалите класс <code>.cleared</code>:</p> + +<pre class="brush: css notranslate" id="ct-0">.cleared { + clear: left; +}</pre> + +<p>Вы увидите, что, точно так же как и в примере где мы устанавливаем цвет фона для параграфа, цвет фона располагается за обтекаемым объектом.</p> + +<div id="Float_4"> +<div class="hidden"> +<h6 id="Float_Example_4">Float Example 4</h6> + +<pre class="brush: html notranslate"><h1>Simple float example</h1> +<div class="wrapper"> + <div class="box">Float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> +</div> + +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Float_4', '100%', 600) }}</p> + +<p>И еще раз, так происходит потому, что обтекаемый объект изымается из нормального потока. <span class="tlid-translation translation" lang="ru"><span title="">Очистка следующего элемента не помогает с этой проблемой очистки блока, где вы хотите, чтобы нижняя часть блока обернула </span></span>обтекаемый объект и оборачивающий контент даже если контент короче. Существует три потенциальных способа разобраться с этой проблемой, два из которых работают во всех браузерах, но при этом немного хитры и третий новый способ, который <span class="tlid-translation translation" lang="ru"><span title="">правильно справляется с этой ситуацией.</span></span></p> + +<h3 id="Clearfix_hack">Clearfix hack</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Традиционно эта ситуация решалась с помощью так называемого «clearfix hack».</span></span> Это включает вставку некоторого сгенерированного контента после блока, содержащего обтекаемый объект и оберточный контент, а также настройки для очистки обоих.</p> + +<p>Добавьте следующий CSS в наш пример:</p> + +<pre class="brush: css notranslate">.wrapper::after { + content: ""; + clear: both; + display: block; +}</pre> + +<p>Теперь перезагрузите страницу и блок должен быть очищенным. <span class="tlid-translation translation" lang="ru"><span title="">По сути, это то же самое, как если бы вы добавили </span></span>HTML элемент такой как <code><div></code> ниже объекта и установили <code>clear: both</code>.</p> + +<div id="Float_5"> +<div class="hidden"> +<h6 id="Float_Example_5">Float Example 5</h6> + +<pre class="brush: html notranslate"><h1>Simple float example</h1> +<div class="wrapper"> + <div class="box">Float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> +</div> +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} + +.wrapper::after { + content: ""; + clear: both; + display: block; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Float_5', '100%', 600) }}</p> + +<h3 id="Использование_overflow">Использование overflow</h3> + +<p>Альтернативный метод — это задать свойство {{cssxref("overflow")}} для обертки (wrapper) на значение отличное от <code>visible</code>.</p> + +<p>Удалите clearfix CSS который вы добавляли в предыдущей секции и вместо него добавьте <code>overflow: auto</code> к правилу для обертки. Блок снова должен быть очищен.</p> + +<pre class="brush: css notranslate">.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; + overflow: auto; +}</pre> + +<div id="Float_6"> +<div class="hidden"> +<h6 id="Float_Example_6">Float Example 6</h6> + +<pre class="brush: html notranslate"><h1>Simple float example</h1> +<div class="wrapper"> + <div class="box">Float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> +</div> +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; + overflow: auto; +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Float_6', '100%', 600) }}</p> + +<p>Этот пример работает путем создания того, что известно как <strong>Блочный Контекст Форматирования (block formatting context </strong>(BFC)<strong>). </strong>Это как мини макет внутри вашей страницы, внутри которого содержится все, следовательно наш обтекаемый элемент находится внутри BFC и фон располагается за обоими элементами. Обычно это будет срабатывать, однако, в определенных случаях вы можете обнаружить нежелательную полосу прокрутки или обрезанные тени из-за <span class="tlid-translation translation" lang="ru"><span title="">непреднамеренный</span></span> последствий использования overflow.</p> + +<h3 id="display_flow-root">display: flow-root</h3> + +<p>Современный способ решения этой проблемы — это использование значения <code>flow-root</code> свойства <code>display</code>. Он существует только для создания BFC без использования хака — не будет возникать <span class="tlid-translation translation" lang="ru"><span title="">непреднамеренных </span></span>последствий, когда вы используете его. Удалите <code>overflow: auto</code> из вашего правила <code>.wrapper</code> и добавьте <code>display: flow-root</code>. <span class="tlid-translation translation" lang="ru"><span title="">Если предположить,</span></span> что у вас <a href="/en-US/docs/Web/CSS/display#Browser_compatibility">поддерживающий браузер</a>, блок будет очищаться.</p> + +<pre class="brush: css notranslate">.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; + display: flow-root; +}</pre> + +<div id="Float_7"> +<div class="hidden"> +<h6 id="Float_Example_7">Float Example 7</h6> + +<pre class="brush: html notranslate"><h1>Simple float example</h1> +<div class="wrapper"> + <div class="box">Float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> +</div> +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; + display: flow-root; +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Float_7', '100%', 600) }}</p> + +<h2 id="Проверьте_свои_навыки!">Проверьте свои навыки!</h2> + +<p>Вы достигли конца этой статьи, но помните ли вы самую важную информацию? <span class="tlid-translation translation" lang="ru"><span title="">Вы можете найти дополнительные тесты, чтобы убедиться, что вы усвоили эту информацию, прежде чем двигаться дальше </span></span>— см. <a href="/en-US/docs/Learn/CSS/CSS_layout/Floats_skills">Проверка ваших навыков: Floats</a>.</p> + +<h2 id="Заключение">Заключение</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Теперь вы знаете все, что нужно знать о float в современной веб-разработке. См. Статью об </span></span><a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">устаревших методах макета </a><span class="tlid-translation translation" lang="ru"><span title="">устаревших методах макета для получения информации о том, как они использовались раньше, что может быть полезно, если вы работаете над старыми проектами.</span></span></p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">Введение в CSS макет</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow">Нормальный поток</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Grid</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Позиционирование</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Макет с несколькими столбцами</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Responsive_Design">Отзывчивый дизайн</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Media_queries">Руководство новичка в media queries</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">Устаревшие методы макета</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">Поддержка старых браузеров</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">Базовая оценка понимания макета</a></li> +</ul> diff --git a/files/ru/learn/css/css_layout/floats_skills/index.html b/files/ru/learn/css/css_layout/floats_skills/index.html new file mode 100644 index 0000000000..425e8c3b50 --- /dev/null +++ b/files/ru/learn/css/css_layout/floats_skills/index.html @@ -0,0 +1,76 @@ +--- +title: 'Проверка ваших навыков: floats' +slug: Learn/CSS/CSS_layout/Floats_skills +translation_of: Learn/CSS/CSS_layout/Floats_skills +--- +<div>{{LearnSidebar}}</div> + +<div></div> + +<p>Цель этого задания - чтобы вы поработали со свойствами CSS {{CSSxRef("float")}} и {{CSSxRef("clear")}} которые описаны в нашем уроке <a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">Floats</a>. <span class="tlid-translation translation" lang="ru"><span title="">Вы будете работать над тремя небольшими задачами,</span></span> использующими различные элементы из пройденного материала.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: <span class="tlid-translation translation" lang="ru"><span title="">Вы можете опробовать решения в интерактивных редакторах ниже</span></span>, однако может быть полезным загрузить код и использовать онлайн инструменты такие как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, или <a href="https://glitch.com/">Glitch</a> чтобы проработать задания.</p> + +<p>Если вы застрянете, попросите нас о помощи — см. раздел {{anch("Оценка или дальнейшая помощь")}} в конце страницы</p> +</div> + +<h2 id="Floats_Раз">Floats Раз</h2> + +<p>В этом задании вам необходимо чтобы два элемента с классами float1 и float2 обтекали слева и справа соответственно. Текст должен появляться между двумя блоками как на изображении ниже.</p> + +<p><img alt="Two blocks displaying left and right of some text." src="https://mdn.mozillademos.org/files/17073/float-task1.png" style="height: 425px; width: 1067px;"></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Попробуйте обновить живой код ниже, чтобы воссоздать готовый пример</span></span>:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/float/float1.html", '100%', 700)}}</p> + +<div class="blockIndicator note"> +<p>Для оценки или дальнейшей работы, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/float/float1-download.html">загрузите отправную точку этого задания</a> чтобы работать в вашем собственном или онлайн редакторе.</p> +</div> + +<h2 id="Float_Два">Float Два</h2> + +<p>В этом примере элемент с классом float должен примыкать к левому краю и обтекаться справа. Далее мы хотим чтобы первая строка текста отображалась рядом с тем элементом, а следующая строка (с классом .below) отображалась под ним. Вы можете посмотреть желаемый результат на этом изображении.</p> + +<p><img alt="A box displayed to the left of a line of text, with some more text below." src="https://mdn.mozillademos.org/files/17074/float-task2.png" style="height: 522px; width: 1373px;"></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Попробуйте обновить живой код ниже, чтобы воссоздать готовый пример</span></span>:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/float/float2.html", '100%', 800)}}</p> + +<div class="blockIndicator note"> +<p>Для оценки или дальнейшей работы, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/float/float2-download.html">загрузите отправную точку этого задания</a> чтобы работать в вашем собственном или онлайн редакторе.</p> +</div> + +<h2 id="Float_Три">Float Три</h2> + +<p>И наконец у нас есть обтекаемый элемент в этом примере. Блок оборачивающий обтекаемый элемент и текст отображается за ними. Используйте самый последний доступный метод чтобы фон тянулся за обтеканием как показано на изображении.</p> + +<p><img alt="A block displayed to the right of some text both wrapped by a box with a background color." src="https://mdn.mozillademos.org/files/17075/float-task3.png" style="height: 427px; width: 1024px;"></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Попробуйте обновить живой код ниже, чтобы воссоздать готовый пример</span></span>:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/float/float3.html", '100%', 800)}}</p> + +<div class="blockIndicator note"> +<p>Для оценки или дальнейшей работы, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/float/float3-download.html">загрузите отправную точку этого задания</a> чтобы работать в вашем собственном или онлайн редакторе.</p> +</div> + +<h2 id="Оценка_или_дальнейшая_помощь">Оценка или дальнейшая помощь</h2> + +<p>Вы можете попрактиковаться с этими примерами в интерактивных редакторах упомянутых выше.</p> + +<p>Если вы хотите, чтобы вашу работу оценили, или вы застряли и хотите попросить помощи:</p> + +<ol> + <li>Разместите свою работу в онлайн редакторе в которым можно поделиться работами в таком как <a class="external external-icon" href="https://codepen.io/" rel="noopener">CodePen</a>, <a class="external external-icon" href="https://jsfiddle.net/" rel="noopener">jsFiddle</a>, или <a class="external external-icon" href="https://glitch.com/" rel="noopener">Glitch</a>. Вы можете написать код самостоятельно или использовать файлы с отправными точками ссылки на которые имеются в разделах выше.</li> + <li>Напишите пост с просьбой оценки и/или помощи на <a class="external external-icon" href="https://discourse.mozilla.org/c/mdn/learn" rel="noopener">MDN Discourse forum Learning category</a>. Ваш пост должен включать: + <ul> + <li>Описательный заголовок такой как "Требуется оценка теста по навыкам Float".</li> + <li>Детали о том, что вы уже попытались сделать и что бы вы хотели, чтобы мы сделали, например, если вы застряли и вам нужна помощь, либо вы хотите оценку.</li> + <li>Ссылку на онлайн редактор (как упомянуто выше в пункте 1) с примером, который нуждается в оценке или с которым нужна помощь. Это хорошая практика чтобы вникнуть — очень сложно помочь кому-либо с проблемным кодом если вы не видите их код.</li> + <li>Ссылку на актуальную задачу или страницу оценки, чтобы мы могли найти вопрос, по которому вам нужна помощь.</li> + </ul> + </li> +</ol> diff --git a/files/ru/learn/css/css_layout/fundamental_layout_comprehension/index.html b/files/ru/learn/css/css_layout/fundamental_layout_comprehension/index.html new file mode 100644 index 0000000000..4a85d07667 --- /dev/null +++ b/files/ru/learn/css/css_layout/fundamental_layout_comprehension/index.html @@ -0,0 +1,69 @@ +--- +title: Фундаментальное понимание раскладки +slug: Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension +tags: + - CSS + - Начинающий + - Обучение + - Раскладка +translation_of: Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Если вы проработали этот модуль, то уже имеете базовое представление о том, что вам нужно знать, чтобы создавать современную CSS раскладку и работать с более старым CSS. Это задание проверит некоторые из ваших знаний путём разработки раскладки для простой веб-страницы, используя различные техники.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимое условие:</th> + <td>Прежде чем приступать к этой аттестации, вы должны были уже проработать все статьи в этом модуле.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Проверить понимание фундаментальных навыков раскладки, освещаемых в этом модуле.</td> + </tr> + </tbody> +</table> + +<h2 id="Резюме_проекта">Резюме проекта</h2> + +<p>Вам предоставили некоторый html, базовый css и изображения — ваша задача, создать раскладку для дизайна, который должен выглядеть как на изображении ниже.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/16076/layout-task-complete.png" style="height: 706px; width: 1000px;"></p> + +<h3 id="Базовые_настройки">Базовые настройки</h3> + +<p>Вы можете скачать HTML, CSS, и набор из шести изображений <a href="https://github.com/mdn/learning-area/tree/master/css/css-layout/fundamental-layout-comprehension">тут</a>.</p> + +<p>Сохраните HTML документ и css стили внутри директории на вашем компьютере и добавьте изображения внутрь папки с именем <code>images</code>. Открыв <code>index.html</code> файл в браузере, вы должны получить страницу с базовой стилизацией, но без раскладки, что должно выглядеть как на изображении ниже.</p> + +<p>Эта отправная точка и всё содержимое отображается браузером в нормальном потоке.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/16075/layout-task-start.png" style="height: 675px; width: 1000px;"></p> + +<h3 id="Ваши_задачи">Ваши задачи</h3> + +<p>Теперь вам нужно реализовать раскладку. Задачи, которые вам необходимо выполнить:</p> + +<ol> + <li>Отобразить пункты навигации в строку, с одинаковым количеством пространства между элементами.</li> + <li>Панель навигации должна прокручиваться вместе с содержимым страницы и закрепляться вверху видимой области документа в рамках экрана.</li> + <li>Изображение, которое находится внутри статьи, должно обтекаться текстом вокруг него.</li> + <li>{{htmlelement("article")}} и {{htmlelement("aside")}} элементы должны отображаться как двухколоночная раскладка. Колонки должны иметь гибкий размер, если окно браузера уменьшится, колонки должны стать более узкими.</li> + <li>Фотографии должны отображаться как двухколоночная сетка с отступом в 1px между изображениями.</li> +</ol> + +<p>Вам нет необходимости изменять HTML для создания этой раскладки и техник, которые вы должны использовать:</p> + +<ul> + <li>Позиционирование</li> + <li>Раскладка на Float</li> + <li>Раскладка на Flexbox</li> + <li>Раскладка на CSS Grid</li> +</ul> + +<p>Есть множество способов, как выполнить некоторые из этих задач и часто не существует одного правильного или неправильного способа это сделать. Попробуйте несколько разных способов и увидите, какой работает лучше. Делайте заметки о ваших экспериментах и вы всегда сможете обсудить ваш способ в отдельной дискуссии для этого задания или на <a href="irc://irc.mozilla.org/mdn">#mdn</a> IRC канале.</p> + +<h2 id="Оценка_работы">Оценка работы</h2> + +<p>Если вы проходите эту аттестацию как часть организованного курса, вы должны быть в состоянии дать свою работу вашему учителю/наставнику для оценки. Если вы занимаетесь самообучением, тогда вы легко можете получить руководство по оценке работы, задавая вопросы в <a href="https://discourse.mozilla.org/t/fundamental-layout-comprehension-assessment/29982">отдельной дискуссии для этого задания</a> или на <a href="irc://irc.mozilla.org/mdn">#mdn</a> IRC канале в <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Сначала попробуйте выполнить упражнение — нет никаких причин для жульничества!</p> diff --git a/files/ru/learn/css/css_layout/grids/index.html b/files/ru/learn/css/css_layout/grids/index.html new file mode 100644 index 0000000000..f94f97fb10 --- /dev/null +++ b/files/ru/learn/css/css_layout/grids/index.html @@ -0,0 +1,642 @@ +--- +title: Grids +slug: Learn/CSS/CSS_layout/Grids +translation_of: Learn/CSS/CSS_layout/Grids +--- +<div> +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout/Floats", "Learn/CSS/CSS_layout")}}</div> +Сетки (grids) являются установленным инструментом проектирования и многие современные макеты веб-сайта основаны на регулярной сетке. В этой статье мы рассмотрим дизайн на основе сетки и увидим как CSS можно использовать для создания сеток <span class="seoSummary">—</span> как с помощью современных инструментов, так и с помощью новых технологий, которые только начинают становиться доступными в браузерах.</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td>основы HTML(изучите <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), понимание как работает CSS (изучите <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Introduction to CSS</a> и <a href="/en-US/docs/Learn/CSS/Styling_boxes">Styling boxes</a>.)</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Понять основные концепции, лежащие в основе систем компоновки сетки и как реализовать сетку на веб-странице.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_макет_сетки_grid_layout">Что такое макет сетки (grid layout)?</h2> + +<p>Сетка (grid) - это просто набор горизонтальных и вертикальных линий, создающих шаблон, по которому мы можем выстроить элементы дизайна. Они помогают нам создавать проекты, в которых элементы не прыгают или не меняют ширину при переходе от страницы к странице, обеспечивая большую согласованность на наших сайтах.</p> + +<p>В сетке обычно будут <strong>столбцы (columns)</strong>, <strong>строки (rows)</strong>, а затем промежутки между каждой строкой и столбцом, обычно называемые <strong>желобами (gutters)</strong>.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13899/grid.png" style="display: block; height: 553px; margin: 0px auto; width: 1196px;"></p> + +<p>[Временная диаграмма; скоро будет заменена лучшей диаграммой.]</p> + +<div class="note"> +<p><strong>Примечание</strong>: Может показаться удивительным, если кто-нибудь из фона дизайна, что CSS не имеет встроенной сетки, и вместо этого мы, похоже, используем множество субоптимальных методов для создания сетчатых конструкций. Как вы узнаете в последней части этой статьи, это изменится, однако вам, вероятно, понадобятся существующие методы создания гридов в течение некоторого времени.</p> +</div> + +<h2 id="Использование_“grid_system”_в_ваших_проектах">Использование “grid system” в ваших проектах</h2> + +<p>Чтобы обеспечить постоянный опыт на вашем сайте или в приложении, основываясь на системе сетки с самого начала, вам не нужно думать о том, насколько широкий элемент имеет отношение к другим элементам. Ваш выбор ограничен «количеством столбцов сетки, которые этот элемент будет охватывать».</p> + +<p>Ваша «сеточная система» может быть просто решением, принятым в процессе проектирования, для использования регулярной сетки. Если ваши проекты начнутся в приложении для редактирования графики, например Photoshop, вы можете создать сетку для ссылки во время этого процесса, как описано в <a href="http://www.elliotjaystocks.com/blog/a-better-photoshop-grid-for-responsive-web-design/">A better Photoshop grid for responsive web design</a> by Elliot Jay Stocks.</p> + +<p>Ваша сетевая система также может быть структурой - либо третьей стороной, либо созданной вами только для вашего проекта, - которую вы используете для обеспечения сетки с помощью CSS.</p> + +<h2 id="Создание_простых_рамок_сетки">Создание простых рамок сетки</h2> + +<p>Мы начнем с рассмотрения того, как вы можете создать простую сетку для вашего проекта.</p> + +<p>В настоящее время большинство макетов типа grid создаются с использованием поплавков (floats). Если вы прочитали<a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Floats"> нашу предыдущую статью о поплавках,</a> вы уже видели, как мы можем использовать эту технику для создания раскладки нескольких столбцов, что является сущностью любой сетки, использующей этот метод.</p> + +<p>Самый простой тип структуры сетки для создания фиксированной ширины — нам просто нужно выяснить, сколько общей ширины мы хотим для нашего дизайна, сколько столбцов мы хотим и насколько широки должны быть желоба и столбцы. Если бы вместо этого мы решили выложить наш проект на сетке со столбцами, которые растут и сокращаются в соответствии с шириной браузера, нам нужно будет рассчитать процентную ширину для столбцов и желобов между ними.</p> + +<p>В следующих разделах мы рассмотрим, как создать оба. Мы создадим сетку с 12 столбцами - очень общий выбор, который, как видно, очень адаптируется к различным ситуациям, учитывая, что 12 прекрасно делится на 6, 4, 3 и 2.</p> + +<h3 id="Простая_сетка_с_фиксированной_шириной">Простая сетка с фиксированной шириной</h3> + +<p>Давайте сначала создадим сетку, использующую столбцы фиксированной ширины.</p> + +<p>Начните с создания локальной копии нашего образца <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/simple-grid.html">simple-grid.html</a> файла, который содержит следующую разметку в своем теле.</p> + +<pre class="brush: html notranslate"><div class="wrapper"> + <div class="row"> + <div class="col">1</div> + <div class="col">2</div> + <div class="col">3</div> + <div class="col">4</div> + <div class="col">5</div> + <div class="col">6</div> + <div class="col">7</div> + <div class="col">8</div> + <div class="col">9</div> + <div class="col">10</div> + <div class="col">11</div> + <div class="col">12</div> + </div> + <div class="row"> + <div class="col span1">13</div> + <div class="col span6">14</div> + <div class="col span3">15</div> + <div class="col span2">16</div> + </div> +</div></pre> + +<p>Цель состоит в том, чтобы превратить это в демонстрационную сетку из двух рядов на двенадцать столбцов сетки (grid) - верхний ряд, демонстрирующий размер отдельных столбцов, второй ряд - некоторые области разного размера в сетке.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13901/simple-grid-finished.png" style="display: block; height: 50px; margin: 0px auto; width: 952px;"></p> + +<p>В элементе {{htmlelement ("style")}} добавьте следующий код, который дает контейнеру ширину 980 пикселей с отступом с правой стороны 20 пикселей. Это дает нам 960 пикселей для нашей общей ширины столбца/желоба - в этом случае отступы вычитаются из общей ширины содержимого, потому что мы установили {{cssxref ("box-sizing")}} в рамку по всем элементам на сайте (см. <a href="/en-US/docs/Learn/CSS/Styling_boxes/Box_model_recap#Changing_the_box_model_completely">Changing the box model completely</a> для большего объяснения).</p> + +<pre class="brush: css notranslate">* { + box-sizing: border-box; +} + + +body { + width: 980px; + margin: 0 auto; +} + +.wrapper { + padding-right: 20px; +}</pre> + +<p>Теперь используйте контейнер строк, который обернут вокруг каждой строки сетки, чтобы очистить одну строку от другой. Добавьте следующее правило ниже предыдущего:</p> + +<pre class="brush: css notranslate">.row { + clear: both; +}</pre> + +<p>Применение этого клиринга означает, что нам не нужно полностью заполнять каждую строку элементами, составляющими полные двенадцать столбцов. Строки будут разделены и не будут мешать друг другу.</p> + +<p>Желоба между колоннами шириной 20 пикселей. Мы создаем эти желоба в качестве поля в левой части каждого столбца, включая первый столбец, чтобы сбалансировать 20 пикселей прокладки в правой части контейнера. Таким образом, у нас есть 12 водосточных желобов - 12 x 20 = 240.</p> + +<p>Нам нужно вычесть это из нашей общей ширины 960 пикселей, что дает нам 720 пикселей для наших столбцов. Если мы разделим это на 12, мы знаем, что каждый столбец должен быть 60 пикселей в ширину. Наш следующий шаг - создать правило для класса <code>.col</code>, плавающее влево, предоставив ему {{cssxref ("margin-left")}} из 20 пикселей для формирования желоба и {{cssxref ("width" )}} из 60 пикселей. Добавьте нижеследующее правило в CSS:</p> + +<pre class="brush: css notranslate">.col { + float: left; + margin-left: 20px; + width: 60px; + background: rgb(255, 150, 150); +}</pre> + +<p>Верхний ряд отдельных столбцов теперь будет аккуратно размещаться в виде сетки.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Мы также дали каждому столбцу светло-красный цвет, чтобы вы могли точно видеть, сколько места занимает каждый.</p> +</div> + +<p>В контейнерах макетов, которые мы хотим разместить более одного столбца, нужно предоставить специальные классы, чтобы скорректировать их значения {{cssxref ("width")}} до необходимого количества столбцов (плюс желоба между ними). Нам нужно создать дополнительный класс, чтобы контейнеры могли охватывать от 2 до 12 столбцов. Каждая ширина является результатом сложения ширины столбца этого количества столбцов плюс ширины желоба, который всегда будет набирать номер меньше, чем число столбцов.</p> + +<p>Добавьте нижеследующую часть вашего CSS:</p> + +<pre class="brush: css notranslate">/ * Ширина двух колонок (120 пикселей) плюс одна ширина желоба (20 пикселей) */ +.col.span2 { width: 140px; } +/ * Три ширины столбца (180 пикселей) плюс две ширины желоба (40 пикселей) * / +.col.span3 { width: 220px; } +/* И так далее... */ +.col.span4 { width: 300px; } +.col.span5 { width: 380px; } +.col.span6 { width: 460px; } +.col.span7 { width: 540px; } +.col.span8 { width: 620px; } +.col.span9 { width: 700px; } +.col.span10 { width: 780px; } +.col.span11 { width: 860px; } +.col.span12 { width: 940px; }</pre> + +<p>С помощью этих классов мы можем теперь выкладывать разные столбцы ширины в сетке. Попробуйте сохранить и загрузить страницу в своем браузере, чтобы увидеть эффекты.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Если вам не удается заставить приведенный выше пример работать, попробуйте сравнить его с нашей <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/simple-grid-finished.html">готовой версией</a> на GitHub (см. также <a href="https://mdn.github.io/learning-area/css/css-layout/grids/simple-grid-finished.html">запуск в режиме реального времени</a>).</p> +</div> + +<p>Попробуйте изменить классы на своих элементах или даже добавить и удалить некоторые контейнеры, чтобы увидеть, как вы можете изменять макет. Например, вы можете сделать вторую строку следующим образом:</p> + +<pre class="brush: css notranslate"><div class="row"> + <div class="col span8">13</div> + <div class="col span4">14</div> +</div></pre> + +<p>Теперь у вас работает сетка, вы можете просто определить строки и количество столбцов в каждой строке, а затем заполнить каждый контейнер своим необходимым контентом. Отлично!</p> + +<h3 id="Создание_fluid_grid">Создание fluid grid</h3> + +<p>Наша сетка работает красиво, но имеет фиксированную ширину. Нам очень нужна гибкая (жидкая) сетка, которая будет расти и сокращаться с доступным пространством в браузере {{Glossary ("viewport")}}. Для этого мы можем использовать опорные пиксельные ширины и превратить их в проценты</p> + +<p>Уравнение, которое превращает фиксированную ширину в гибкую, основанную на процентах, выглядит следующим образом.</p> + +<pre class="notranslate">target / context = result</pre> + +<p>Для нашей ширины столбца наша <strong>целевая ширина</strong> составляет 60 пикселей, а наш <strong>контекст</strong> 960 пикселей. Для расчета процента мы можем использовать следующее.</p> + +<pre class="notranslate">60 / 960 = 0.0625</pre> + +<p>Затем мы перемещаем десятичные точки на 2 места, давая нам процент от 6,25%. Таким образом, в нашем CSS мы можем заменить ширину столбца 60 пикселей на 6,25%.</p> + +<p>Мы должны сделать то же самое с нашей шириной желоба:</p> + +<pre class="notranslate">20 / 960 = 0.02083333333</pre> + +<p>Поэтому нам нужно заменить 20 пикселей {{cssxref ("margin-left")}} на наше правило <code>.col</code> 20 пикселей {{cssxref ("padding-right")}} на <code>.wrapper </code>с 2.08333333%.</p> + +<h4 id="Обновление_нашей_сетки">Обновление нашей сетки</h4> + +<p>Чтобы начать работу в этом разделе, создайте новую копию предыдущей страницы примера или создайте локальную копию нашего кода <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/simple-grid-finished.html">simple-grid-finished.html</a>, который будет использоваться в качестве отправной точки.</p> + +<p>Обновите второе правило CSS (с помощью селектора <code>.wrapper</code>) следующим образом:</p> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 980px; + margin: 0 auto; +} + +.wrapper { + padding-right: 2.08333333%; +}</pre> + +<p>Мы не только дали нам процент {{cssxref ("width")}}, мы также добавили свойство {{cssxref ("max-width")}}, чтобы остановить распространение макета.</p> + +<p>Затем обновите четвертое правило CSS (с селектором <code>.col</code>) следующим образом:</p> + +<pre class="brush: css notranslate">.col { + float: left; + margin-left: 2.08333333%; + width: 6.25%; + background: rgb(255, 150, 150); +}</pre> + +<p>Теперь идет немного более трудоемкая часть - нам нужно обновить все наши правила <code>.col.span</code>, чтобы использовать проценты, а не ширину пикселей. Это занимает немного времени с калькулятором; чтобы сэкономить вам немного усилий, мы сделали это для вас ниже.</p> + +<p>Обновите нижний блок правил CSS следующим образом:</p> + +<pre class="brush: css notranslate">/* Two column widths (12.5%) plus one gutter width (2.08333333%) */ +.col.span2 { width: 14.58333333%; } +/* Three column widths (18.75%) plus two gutter widths (4.1666666) */ +.col.span3 { width: 22.91666666%; } +/* And so on... */ +.col.span4 { width: 31.24999999%; } +.col.span5 { width: 39.58333332%; } +.col.span6 { width: 47.91666665%; } +.col.span7 { width: 56.24999998%; } +.col.span8 { width: 64.58333331%; } +.col.span9 { width: 72.91666664%; } +.col.span10 { width: 81.24999997%; } +.col.span11 { width: 89.5833333%; } +.col.span12 { width: 97.91666663%; }</pre> + +<p>Теперь сохраните свой код, загрузите его в браузере и попробуйте изменить ширину видового экрана - вы должны увидеть, что ширины столбцов хорошо меняются. Отлично!</p> + +<div class="note"> +<p><strong>Примечание</strong>: Если вам не удается заставить приведенный выше пример работать, попробуйте сравнить его с нашей <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/fluid-grid.html">готовой версией на GitHub</a> (см. также<a href="https://mdn.github.io/learning-area/css/css-layout/grids/fluid-grid.html"> запуск в режиме реального времени</a>).</p> +</div> + +<h3 id="Более_простые_вычисления_с_использованием_функции_calc">Более простые вычисления с использованием функции calc()</h3> + +<p>Вы можете использовать функцию {{cssxref ("calc ()")}} для выполнения математики прямо внутри вашего CSS - это позволяет вставлять простые математические уравнения в ваши значения CSS, чтобы рассчитать, какое значение должно быть. Это особенно полезно, когда необходимо выполнить сложную математику и вы даже можете сделать расчет, который использует разные единицы, например «Я хочу, чтобы высота этого элемента всегда была на 100% от высоты родителя, минус 50 пикселей». См. <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Recording_API/Using_the_MediaStream_Recording_API#Keeping_the_interface_constrained_to_the_viewport_regardless_of_device_height_with_calc()">этот пример из учебника API MediaRecorder</a>.</p> + +<p>В любом случае, вернемся к нашим сетям! Любой столбец, который охватывает более одного столбца нашей сетки, имеет общую ширину 6,25%, умноженную на количество столбцов, спаренных плюс 2.08333333%, умноженное на количество желобов (которые всегда будут числом столбцов минус 1). Функция <code>calc () </code>позволяет нам делать это вычисление прямо внутри значения ширины, поэтому для любого элемента, охватывающего 4 столбца, мы можем это сделать, например:</p> + +<pre class="brush: css notranslate">.col.span4 { + width: calc((6.25%*4) + (2.08333333%*3)); +}</pre> + +<p>Попробуйте заменить нижний блок правил следующим, а затем перезагрузите его в браузере, чтобы узнать, получаете ли вы тот же результат:</p> + +<pre class="brush: css notranslate">.col.span2 { width: calc((6.25%*2) + 2.08333333%); } +.col.span3 { width: calc((6.25%*3) + (2.08333333%*2)); } +.col.span4 { width: calc((6.25%*4) + (2.08333333%*3)); } +.col.span5 { width: calc((6.25%*5) + (2.08333333%*4)); } +.col.span6 { width: calc((6.25%*6) + (2.08333333%*5)); } +.col.span7 { width: calc((6.25%*7) + (2.08333333%*6)); } +.col.span8 { width: calc((6.25%*8) + (2.08333333%*7)); } +.col.span9 { width: calc((6.25%*9) + (2.08333333%*8)); } +.col.span10 { width: calc((6.25%*10) + (2.08333333%*9)); } +.col.span11 { width: calc((6.25%*11) + (2.08333333%*10)); } +.col.span12 { width: calc((6.25%*12) + (2.08333333%*11)); }</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете увидеть нашу законченную версию в файле <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/fluid-grid-calc.html">liquid-grid-calc.html</a> (также см. ее <a href="https://mdn.github.io/learning-area/css/css-layout/grids/fluid-grid-calc.html">в режиме реального времени</a>).</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Если вы не можете заставить это работать, возможно, это связано с тем, что ваш браузер не поддерживает функцию <code>calc ()</code>, хотя он довольно хорошо поддерживается в браузерах - еще в IE9.</p> +</div> + +<h3 id="Семантические_и_несемантические_сетчатые_системы">Семантические и "несемантические" сетчатые системы</h3> + +<p>Добавление классов в вашу разметку для определения макета означает, что ваш контент и разметка привязаны к его визуальному представлению. Иногда вы слышите это использование классов CSS, описанных как «несемантические», - описывая, как выглядит контент, а не семантическое использование классов, описывающих контент. Это относится к классам <code>span2</code>, <code>span3</code> и т. Д.</p> + +<p>Это не единственный подход. Вместо этого вы можете выбрать свою сетку, а затем добавить информацию о размерах в правила для существующих семантических классов. Например, если у вас есть {{htmlelement ("div")}} с классом <code>content</code> в нем, который вы хотите разбить на 8 столбцов, вы можете скопировать по ширине из класса <code>span8</code>, предоставив вам следующее правило:</p> + +<pre class="brush: css notranslate">.content { + width: calc((6.25%*8) + (2.08333333%*7)); +}</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Если вы использовали препроцессор, такой как <a href="http://sass-lang.com/">Sass</a>, вы могли бы создать простой mixin, чтобы вставить это значение для вас.</p> +</div> + +<h3 id="Включение_офсетных_контейнеров_в_нашей_сетке">Включение офсетных контейнеров в нашей сетке</h3> + +<p>Сетка, которую мы создали, работает хорошо, пока мы хотим запустить все контейнеры заподлицо с левой стороны сетки. Если бы мы хотели оставить пустое пространство столбца перед первым контейнером - или между контейнерами - нам нужно было бы создать класс смещения, чтобы добавить левое поле на наш сайт, чтобы визуально визуализировать его по сетке. Больше математики!</p> + +<p>Давайте попробуем это.</p> + +<p>Начните с предыдущего кода или используйте наш файл <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/fluid-grid.html">fluid-grid.html</a> в качестве отправной точки.</p> + +<p>Давайте создадим класс в нашем CSS, который будет смещать элемент контейнера на одну ширину столбца. Добавьте нижеследующую часть вашего CSS:</p> + +<pre class="brush: css notranslate">.offset-by-one { + margin-left: calc(6.25% + (2.08333333%*2)); +}</pre> + +<p>Или если вы предпочитаете самостоятельно рассчитать проценты, используйте это:</p> + +<pre class="brush: css notranslate">.offset-by-one { + margin-left: 10.41666666%; +}</pre> + +<p>Теперь вы можете добавить этот класс в любой контейнер, в котором вы хотите оставить пустое пространство с одним столбцом в левой части окна. Например, если у вас есть это в вашем HTML:</p> + +<pre class="brush: html notranslate"><div class="col span6">14</div></pre> + +<p>Попробуйте заменить его на</p> + +<pre class="brush: html notranslate"><div class="col span5 offset-by-one">14</div></pre> + +<div class="note"> +<p><strong>Примечание</strong>: Обратите внимание, что вам необходимо уменьшить количество столбцов, чтобы освободить место для смещения!</p> +</div> + +<p>Попытайтесь загрузить и обновить, чтобы увидеть разницу или посмотрите наш пример <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/fluid-grid-offset.html">fluid-grid-offset.html</a> (см. <a href="https://mdn.github.io/learning-area/css/css-layout/grids/fluid-grid-offset.html">также «live»</a>). Готовый пример должен выглядеть так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13903/offset-grid-finished.png" style="display: block; height: 47px; margin: 0px auto; width: 944px;"></p> + +<div class="note"> +<p><strong>Примечание:</strong> В качестве дополнительного упражнения вы можете реализовать класс «смещение на два»?</p> +</div> + +<h3 id="Ограничения_с_плавающей_сеткой">Ограничения с плавающей сеткой</h3> + +<p>При использовании такой системы вам необходимо позаботиться о том, чтобы ваша общая ширина была правильно вставлена и что вы не включаете элементы в строку, которая содержит больше столбцов, чем может содержать строка. Из-за того, как работают поплавки, если количество столбцов сетки становится слишком большим для сетки, элементы на конце будут опускаться до следующей строки, разбивая сетку.</p> + +<p>Также имейте в виду, что если содержимое элементов становится шире, чем занимаемые им строки, оно будет переполняться и выглядит как беспорядок.</p> + +<p>Самое большое ограничение этой системы состоит в том, что она по существу одномерна. Мы имеем дело со столбцами и охватываем элементы по столбцам, но не по строкам. С помощью этих старых методов компоновки очень сложно контролировать высоту элементов без явной установки высоты, и это тоже очень негибкий подход - он работает только, если вы можете гарантировать, что ваш контент будет определенной высоты.</p> + +<h2 id="Flexbox_grids">Flexbox grids?</h2> + +<p>Если вы прочтете нашу предыдущую статью о <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a>, вы можете подумать, что flexbox - идеальное решение для создания сетчатой системы. В настоящее время доступно множество систем gridbox на основе flexbox и flexbox может решить многие из проблем, которые мы уже обнаружили при создании нашей сетки выше.</p> + +<p>Однако flexbox никогда не разрабатывался как сетчатая система и создает новый набор проблем при использовании в качестве одного. В качестве простого примера мы можем использовать тот же пример разметки, который мы использовали выше, и использовать следующий CSS для стилей классов-оболочек (<code>wrapper</code>), <code>row</code> и <code>col</code> классов:</p> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 980px; + margin: 0 auto; +} + +.wrapper { + padding-right: 2.08333333%; +} + + +.row { + display: flex; +} + +.col { + margin-left: 2.08333333%; + margin-bottom: 1em; + width: 6.25%; + flex: 1 1 auto; + background: rgb(255,150,150); +}</pre> + +<p>Вы можете попробовать сделать эти замены в своем собственном примере или посмотреть на наш пример кода <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/flexbox-grid.html">flexbox-grid.html </a>(см. также <a href="https://mdn.github.io/learning-area/css/css-layout/grids/flexbox-grid.html">он работает в режиме реального времени</a>).</p> + +<p>Здесь мы превращаем каждую строку в гибкий контейнер. С сеткой на основе flexbox нам все еще нужны строки, чтобы мы могли иметь элементы, которые составляют менее 100%. Мы установили этот контейнер для <code>display: flex</code>.</p> + +<p>На <code>.col </code>мы устанавливаем первое значение свойства {{cssxref ("flex")}} ({{cssxref ("flex-grow")}}) до 1, чтобы наши объекты могли расти, второе значение ({{cssxref (" flex-shrink ")}}) до 1, поэтому элементы могут сокращаться, а третье значение ({{cssxref (" flex-basis ")}}) - <code>auto</code>. Поскольку наш элемент имеет набор {{cssxref ("width")}}, <code>auto</code> будет использовать эту ширину в качестве базового значения flex (<code>flex-basis</code>).</p> + +<p>В верхней строке мы получаем двенадцать аккуратных коробок на сетке, и они растут и сжимаются одинаково, когда мы меняем ширину окна просмотра. Однако на следующей строке у нас есть только четыре элемента, и они также растут и сокращаются с 60px. Только с четырьмя из них они могут расти намного больше, чем элементы в строке выше, в результате они все занимают одну и ту же ширину во второй строке.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13905/flexbox-grid-incomplete.png" style="display: block; height: 71px; margin: 0px auto; width: 944px;"></p> + +<p>Чтобы исправить это, нам все равно нужно включить наши классы <code>span</code>, чтобы обеспечить ширину, которая заменит значение, используемое <code>flex-basis</code> для этого элемента.</p> + +<p>Они также не уважают сетку, используемую выше, потому что они ничего не знают об этом.</p> + +<p>Flexbox является <strong>одномерным</strong> по дизайну. Он имеет дело с одним измерением - со строкой или столбцом. Мы не можем создать строгую сетку для столбцов и строк, что означает, что если мы будем использовать flexbox для нашей сетки, нам все равно нужно рассчитать проценты, как для плавающего макета.</p> + +<p>В вашем проекте вы все равно можете использовать сетку flexbox из-за дополнительных возможностей выравнивания и распределения пространства. Flexbox обеспечивает надплавки. Однако вам следует помнить, что вы все еще используете инструмент для чего-то другого, кроме того, для чего он предназначен. Таким образом, вы можете почувствовать, что он заставляет вас прыгать через дополнительные обручи, чтобы получить конечный результат, который вы хотите.</p> + +<h2 id="Системы_сторонних_сетей">Системы сторонних сетей</h2> + +<p>Теперь, когда мы понимаем математику за нашими расчетами в сетке, мы находимся в хорошем месте, чтобы взглянуть на некоторые из сторонних сетевых систем, которые используются совместно. Если вы ищете «CSS Grid framework» в Интернете, вы найдете огромный список вариантов на выбор. В популярных структурах, таких как <a href="http://getbootstrap.com/">Bootstrap</a> и <a href="https://foundation.zurb.com/">Foundation</a>, есть сетка. Существуют также автономные сетчатые системы, разработанные с использованием CSS или с использованием препроцессоров.</p> + +<p>Давайте рассмотрим одну из этих автономных систем, поскольку она демонстрирует общие методы работы с сеткой. Сетка, которую мы будем использовать, является частью Skeleton, простой CSS-структуры.</p> + +<p>Для начала посетите <a href="http://getskeleton.com/">веб-сайт Skeleton</a> и выберите «Загрузить», чтобы загрузить ZIP-файл. Разархивируйте это и скопируйте файлы skeleton.css и normalize.css в новый каталог.</p> + +<p>Сделайте копию нашего файла <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/html-skeleton.html">html-skeleton.html</a> и сохраните его в том же каталоге, что и скелет, и нормализовать CSS.</p> + +<p>Включите скелет и нормализуйте CSS на странице HTML, добавив следующее в голову:</p> + +<pre class="brush: html notranslate"><link href="normalize.css" rel="stylesheet"> +<link href="skeleton.css" rel="stylesheet"></pre> + +<p>Скелет включает в себя больше, чем сетку - он также содержит CSS для типографики и других элементов страницы, которые вы можете использовать в качестве отправной точки. На данный момент мы оставим их по умолчанию, но именно эта сетка нас действительно интересует.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Нормализация - очень полезная небольшая библиотека CSS, написанная Николасом Галлахером, которая автоматически делает некоторые полезные основные исправления макета и делает стиль элементов по умолчанию более согласованным в разных браузерах.</p> +</div> + +<p>Мы будем использовать аналогичный HTML для нашего предыдущего примера. Добавьте в свой HTML-код следующее:</p> + +<pre class="brush: html notranslate"><div class="container"> + <div class="row"> + <div class="col">1</div> + <div class="col">2</div> + <div class="col">3</div> + <div class="col">4</div> + <div class="col">5</div> + <div class="col">6</div> + <div class="col">7</div> + <div class="col">8</div> + <div class="col">9</div> + <div class="col">10</div> + <div class="col">11</div> + <div class="col">12</div> + </div> + <div class="row"> + <div class="col">13</div> + <div class="col">14</div> + <div class="col">15</div> + <div class="col">16</div> + </div> +</div></pre> + +<p><br> + Чтобы начать использовать Skeleton, нам нужно предоставить оболочку {{htmlelement ("div")}} класс <code>container</code> - это уже включено в наш HTML. Это центрирует контент с максимальной шириной 960 пикселей. Вы можете видеть, как теперь коробки не становятся шире, чем 960 пикселей.</p> + +<p>Вы можете посмотреть в файле skeleton.css, чтобы увидеть CSS, который используется, когда мы применяем этот класс. <code><div></code> центрируется с использованием <code>auto</code> левого и правого полей, а отступы в 20 пикселей применяются слева и справа. Скелет также устанавливает свойство {{cssxref ("box-sizing")}} в <code>border-box</code>, как мы делали это раньше, поэтому дополнение и границы этого элемента будут включены в общую ширину.</p> + +<pre class="brush: css notranslate">.container { + position: relative; + width: 100%; + max-width: 960px; + margin: 0 auto; + padding: 0 20px; + box-sizing: border-box; +}</pre> + +<p>Элементы могут быть только частью сетки, если они находятся внутри строки, так как в нашем предыдущем примере нам нужен дополнительный <code><div></code> или другой элемент с классом строки (<code>row</code>), вложенным между <code>content</code> <code><div></code> и нашим контейнером фактического содержимого <code><div></code>. Мы уже это сделали.</p> + +<p>Теперь давайте выложим контейнеры. Скелет основан на сетке из 12 столбцов. В верхних строках нужны классы из <code>one column</code>, чтобы они охватывали один столбец.</p> + +<p>Добавьте их сейчас, как показано в следующем фрагменте:</p> + +<pre class="brush: html notranslate"><div class="container"> + <div class="row"> + <div class="one column">1</div> + <div class="one column">2</div> + <div class="one column">3</div> + /* and so on */ + </div> +</div></pre> + +<p>Затем дайте контейнеры во втором классе классов, объясняющие количество столбцов, которые они должны охватывать, например:</p> + +<pre class="brush: html notranslate"><div class="row"> + <div class="one column">13</div> + <div class="six columns">14</div> + <div class="three columns">15</div> + <div class="two columns">16</div> +</div></pre> + +<p>Попробуйте сохранить свой HTML-файл и загрузить его в свой браузер, чтобы увидеть эффект.</p> + +<div class="note"> +<p>Примечание. Если вам не удается заставить этот пример работать, попробуйте сравнить его с нашим <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/html-skeleton-finished.html">html-skeleton-finished.html</a> - файлом (см. также <a href="https://mdn.github.io/learning-area/css/css-layout/grids/html-skeleton-finished.html">в режиме реального времени</a>).</p> +</div> + +<p>Если вы посмотрите в файле skeleton.css, вы увидите, как это работает. Например, у Skeleton определены следующие элементы стиля с добавленными к ним классами «три столбца».</p> + +<pre class="brush: css notranslate">.three.columns { width: 22%; }</pre> + +<p>Весь Skeleton (или любая другая структура сетки) выполняет настройку предопределенных классов, которые вы можете использовать, добавив их в свою разметку. Это точно так же, как если бы вы сами делали расчет этих процентов.</p> + +<p>Как вы можете видеть, нам нужно написать очень мало CSS при использовании Skeleton. Он касается всех плавающих для нас, когда мы добавляем классы в нашу разметку. Именно эта способность нести ответственность за компоновку над чем-то еще, что делает использование рамки для сетчатой системы неотразимым выбором!</p> + +<p>Skeleton - это более простая сетка, чем некоторые из структур, с которыми вы можете столкнуться. Сетки в больших рамках, таких как Bootstrap и Foundation, предлагают больше функциональности и дополнительные точки останова для различной ширины экрана. Тем не менее, все они работают аналогичным образом - добавив определенные классы в свою разметку, вы можете контролировать, как элемент выложен с использованием предопределенной сетки.</p> + +<h2 id="Родные_CSS_Сетки_с_Grid_Layout">Родные CSS Сетки с Grid Layout</h2> + +<p>В начале этой статьи мы сказали, что CSS ранее не имел реальной системы для создания макетов сетки, но это изменится. Хотя мы еще не можем использовать встроенную сетовую систему CSS, в следующем году мы увидим поддержку браузера для модуля компоновки сетки CSS (<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout">CSS Grid Layout Module</a>).</p> + +<p>В настоящее время вы можете использовать только те методы, которые мы покажем вам в браузерах, которые реализуют макет сетки CSS «за флагом» - это означает, что он в настоящее время реализован, но в экспериментальном состоянии, которое вам нужно включить.</p> + +<p>В Firefox, например, вам нужно перейти к URL-адресу <code>about: config</code>, выполнить поиск по предпочтению <code>layout.css.grid.enabled</code> и дважды щелкнуть его, чтобы включить CSS-сетки. Вы можете узнать, как использовать его в других браузерах, посетив <a href="http://gridbyexample.com/browsers">Grid by Example</a>.</p> + +<p>Мы рассмотрели структуру Скелетной сетки выше - как и другие сторонние решетки и даже ручные сетки, для этого требуется добавить <code><div></code> для формирования строк, а затем указать количество столбцов, которые будут охватывать элементы в этих рядах.</p> + +<p>С помощью CSS Grid Layout вы можете полностью указать свою сетку в CSS, не добавляя эти вспомогательные классы в разметку вообще. Давайте рассмотрим наш простой пример и посмотрим, как мы будем создавать тот же макет с помощью CSS Grid Layout.</p> + +<h3 id="Создание_собственной_сетки">Создание собственной сетки</h3> + +<p>Сначала начните с создания локальной копии файла <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/css-grid.html">css-grid.html</a>. Он содержит следующую разметку:</p> + +<pre class="brush: html notranslate"><div class="wrapper"> + <div class="col">1</div> + <div class="col">2</div> + <div class="col">3</div> + <div class="col">4</div> + <div class="col">5</div> + <div class="col">6</div> + <div class="col">7</div> + <div class="col">8</div> + <div class="col">9</div> + <div class="col">10</div> + <div class="col">11</div> + <div class="col">12</div> + <div class="col">13</div> + <div class="col span6">14</div> + <div class="col span3">15</div> + <div class="col span2">16</div> +</div></pre> + +<p>На этот раз у нас есть родительский <code><div></code> с классом обертки (<code>wrapper</code>), а затем все дочерние элементы просто появляются непосредственно внутри обертки - никаких элементов строки. Мы добавили класс к элементам, которые должны охватывать более одного столбца.</p> + +<p>Теперь добавьте следующее в элемент {{htmlelement ("style")}}:</p> + +<pre class="brush: css notranslate">.wrapper { + width: 90%; + max-width: 960px; + margin: 0 auto; + display: grid; + grid-template-columns: repeat(12, 1fr); + grid-gap: 20px; +} + +.col { + background: rgb(255,150,150); +}</pre> + +<p>Здесь мы устанавливаем правило <code>.wrapper</code>, поэтому оно составляет 90% от ширины тела, с центром и имеет {{cssxref ("max-width")}} 960px.</p> + +<p>Теперь для свойств сетки CSS. Мы можем объявить сетку, используя значение <code>grid</code> свойства {{cssxref ("display")}}, установить желоб с свойством {{cssxref ("grid-gap")}}, а затем создать сетку из 12 столбцов равной ширине, используя {{cssxref ("grid-template-columns")}}, новую функцию <code>repeat()</code> и новую единицу, определенную для макета сетки - блок <code>fr</code>.</p> + +<p>Блок <code>fr</code> представляет собой блок фракции - он описывает долю доступного пространства в контейнере сетки. Если все столбцы равны <code>1fr</code>, каждый из них занимает равное количество места. Это устраняет необходимость вычислять проценты для создания гибкой сетки.</p> + +<p>Создав сетку, правила автоматического размещения сетки немедленно выведут наши коробки в этой сетке, и мы получим гибкую сетку с двенадцатью столбцами.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13907/css-grid-incomplete.png" style="display: block; height: 70px; margin: 0px auto; width: 971px;"></p> + +<p>Чтобы создать контейнеры, которые охватывают несколько треков столбцов в сетке, мы можем использовать свойство {{cssxref ("grid-column")}}. Чтобы охватить 6 столбцов, например:</p> + +<pre class="brush: css notranslate">.span6 { + grid-column: auto / span 6; +}</pre> + +<p>И для span 3:</p> + +<pre class="brush: css notranslate">.span3 { + grid-column: auto / span 3; +}</pre> + +<p>Значение перед косой чертой - это начальная строка - в этом случае мы явно не устанавливаем это и не позволяем браузеру размещать элемент на следующей доступной строке. Затем мы можем установить его на 6, 3 или сколько угодно строк.</p> + +<p>Добавьте нижеследующую часть вашего CSS:</p> + +<pre class="brush: css notranslate">.span2 { grid-column: auto / span 2;} +.span3 { grid-column: auto / span 3;} +.span4 { grid-column: auto / span 4;} +.span5 { grid-column: auto / span 5;} +.span6 { grid-column: auto / span 6;} +.span7 { grid-column: auto / span 7;} +.span8 { grid-column: auto / span 8;} +.span9 { grid-column: auto / span 9;} +.span10 { grid-column: auto / span 10;} +.span11 { grid-column: auto / span 11;} +.span12 { grid-column: auto / span 12;}</pre> + +<p>Попробуйте сохранить и обновить, и вы увидите, что контейнеры охватывают несколько столбцов, если это необходимо. Круто!</p> + +<p>Сетки CSS являются <strong>двумерными</strong>, так как макет растет и сжимается, элементы остаются выровненными по горизонтали и по вертикали.</p> + +<p>Вы можете проверить это, заменив последние 4 col <code><div></code> s следующим:</p> + +<pre class="brush: css notranslate"><div class="col">13some<br>content</div> +<div class="col span6">14this<br>is<br>more<br>content</div> +<div class="col span3">15this<br>is<br>less</div> +<div class="col span2">16</div></pre> + +<p>Здесь мы намеренно добавили некоторые фрагменты строки ({{htmlelement ("br")}}), чтобы заставить некоторые из столбцов стать выше других. Если вы попытаетесь сохранить и обновить, вы увидите, что столбцы регулируют их высоту, как самый высокий контейнер, поэтому все остается аккуратным.</p> + +<p>Окончательный макет выглядит так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13909/css-grid-finished.png" style="display: block; height: 130px; margin: 0px auto; width: 972px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Если вам не удается заставить этот пример работать, вы можете проверить свой код на нашу <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/css-grid-finished.html">законченную версию</a> (также смотрите, как она <a href="https://mdn.github.io/learning-area/css/css-layout/grids/css-grid-finished.html">работает в прямом эфире</a>).</p> +</div> + +<h3 id="Другие_полезные_функции_сетки_CSS">Другие полезные функции сетки CSS</h3> + +<p>С сетками CSS нам не нужно толкать вещи вдоль полей, чтобы их компенсировать. Попробуйте внести эти изменения в свой CSS:</p> + +<pre class="brush: css notranslate">.content { + grid-column: 2 / 8; +}</pre> + +<pre class="brush: html notranslate"><div class="col span2 content">16</div></pre> + +<p>Контейнер 16 теперь будет охватывать столбцы с 2 по 8, в следующей доступной строке, где он может поместиться.</p> + +<p>Мы можем так же легко группировать строки так же, как и столбцы:</p> + +<pre class="brush: css notranslate">.content { + grid-column: 2 / 8; + grid-row: 3 / 5; +}</pre> + +<p>Контейнер 16 теперь будет охватывать строки с 3 по 5, а также столбцы с 2 по 8.</p> + +<p>Нам также не нужно использовать маржу для фальшивых желобов или явно рассчитать их ширину - сетка CSS имеет эту функциональность, встроенную прямо в свойство <code>grid-gap</code>.</p> + +<p>Мы просто касаемся поверхности того, что возможно с помощью CSS Grid Layout, но главное, что нужно понять в контексте этой статьи, это то, что вам не нужно создавать сетку с сеткой - она одна. Вы можете написать CSS, который помещает элемент непосредственно в предопределенную сетку. Это первый раз, когда это было возможно с помощью CSS и это улучшится, когда поддержка браузера закрепится.</p> + +<h3 id="Активное_обучение_Напишите_свою_собственную_простую_сетку">Активное обучение: Напишите свою собственную простую сетку</h3> + +<p>В макете «<a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Introduction">Введение в CSS</a>» мы включили раздел о <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Introduction#CSS_tables">CSS-таблицах</a>, который включал простой пример формы (см. Пример <a href="https://mdn.github.io/learning-area/css/styling-boxes/box-model-recap/css-tables-example.html">css-tables-example.html live</a> и <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/box-model-recap/css-tables-example.html">исходный код</a>). Мы хотели бы, чтобы вы взяли копию этого примера и выполните следующие действия:</p> + +<ol> + <li>Удалите элементы <code><div></code> внутри <code><form></code> - вам больше не нужны эти данные, поскольку CSS-сетки могут обрабатывать размещение содержимого по строкам и столбцам для вас.</li> + <li>Используйте свойства сетки CSS, чтобы создать макет для вашей формы как можно ближе к оригиналу. Вам нужно будет установить ширину на содержащем элементе и подумать о том, как установить пробелы в столбцах, а также пробелы в строке.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Сначала выполните это и если вы действительно застряли, вы можете проверить свой код на примере <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/css-tables-as-grid.html">css-tables-as-grid.html</a>. Не обманывайте - сначала попробуйте упражнение!</p> +</div> + +<h2 id="Резюме">Резюме</h2> + +<p>Прочитав эту статью, вы должны теперь понять, как grid-схемы и grid-структуры работают в CSS. Вы также заглянули в будущее сетки CSS и теперь должны понимать, что используемые нами grid-сетки - это, по сути, стоп-решение, пока у нас не будет широко распространенного способа достижения этого в CSS.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout/Floats", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">Introduction to CSS layout</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Positioning</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Practical_positioning_examples">Practical positioning examples</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Grids</a></li> +</ul> diff --git a/files/ru/learn/css/css_layout/index.html b/files/ru/learn/css/css_layout/index.html new file mode 100644 index 0000000000..a4fcfa8ac5 --- /dev/null +++ b/files/ru/learn/css/css_layout/index.html @@ -0,0 +1,84 @@ +--- +title: CSS layout +slug: Learn/CSS/CSS_layout +tags: + - Beginner + - CSS + - Floating + - Grids + - Guide + - Landing + - Layout + - Learn + - Module + - Multiple column + - NeedsTranslation + - Positioning + - TopicStub + - flexbox + - float + - Верстка + - Сетка + - позиционирование + - разметка страницы +translation_of: Learn/CSS/CSS_layout +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">К текущему моменту мы познакомились с основами CSS. Мы знаем, как оформлять текст, как оформлять и изменять блоки, в которых находится ваш контент. Пришло время узнать, как разместить ваши блоки в нужных местах в зависимости от области просмотра и тому подобного. Мы уже знаем достаточно, чтобы погрузиться в изучение разметки с помощью CSS, в то, как изменять отображение в зависимости от особенностей экрана, как иcпользовать современные методы разметки, такие как Flexbox и CSS grid, и некоторые традиционные методы разметки, которые все ещё применяются.</p> + +<h2 id="Необходимые_условия">Необходимые условия</h2> + +<p>Перед изучением этого раздела вы должны:</p> + +<ol> + <li>Иметь общее представление об HTML, как указано в разделе <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Вступление в HTML</a>.</li> + <li>Ориентироваться в основах CSS, как указано в разделе <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Вступление в CSS</a>.</li> + <li>Понимать, как <a href="/en-US/docs/Learn/CSS/Styling_boxes">стилизовать блочные элементы</a>.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Если вы работаете на компьютере/планшете/других устройствах, где нет возможности создать ваш собственный файл, вы можете попробовать (большую часть) примеры кода в онлайн-программах для написания кода <a href="http://jsbin.com/">JSBin</a> и <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководство">Руководство</h2> + +<p>Эти разделы содержат инструкции по основным инструментам и методам верстки, доступным в CSS. На последнем уроке у Вас будет возможность оценить понимание пройденного материала посредством вёрстки веб-страницы.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">Введение в CSS вёрстку</a></dt> + <dd>В этом разделе будут описаны некоторые возможности CSS вёрстки, которых мы уже касались в предыдущих модулях - различные значения {{cssxref("display")}} — и представлены некоторые концепции, которые мы рассмотрим в этом модуле.</dd> + <dt><a href="/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow">Нормальный поток</a></dt> + <dd>Элементы на веб-страницах размещаются в соответствии с нормальным потоком - пока мы не сделаем что-либо, чтобы это изменить. Этот раздел объясняет основы нормального потока как фундамент для изучения влияния на него.</dd> +</dl> + +<dl> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></dt> + <dd><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Using_flexbox_to_lay_out_web_applications">Flexbox</a> - это метод одномерной верстки для размещения элементов в строках или столбцах. Элементы растягиваются, чтобы заполнить дополнительное пространство и сжимаются, чтобы поместиться в меньшее пространство. Данный раздел объясняет фундаментальные принципы.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Grids">Grids</a></dt> + <dd>CSS Grid Layout - это двумерная система верстки для веб. Она позволяет вам размещать контент в строках и столбцах и имеет множество возможностей, которые упрощают построение сложных макетов. Этот раздел даст вам все, что нужно знать для начала работы с макетом страницы.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Floats">Floats</a></dt> + <dd>Изначально созданное для плавающих изображений внутри текстовых блоков, свойство {{cssxref("float")}} стало одним из наиболее часто используемых инструментов для создания мульти-колоночной верстки веб-страниц. С появлением Flexbox и Grid оно вернулось к первоначальному предназначению, как объясняется в этом разделе.</dd> +</dl> + +<dl> + <dt><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Позиционирование</a></dt> + <dd>Позиционирование позволяет вам брать элементы из нормального потока и изменять их поведение, например, заставляет находиться друг под другом или всегда оставаться в одном и том же месте внутри окна просмотра браузера. В этом разделе объясняются различные значения {{cssxref("position")}} и способы их применения.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Мульти-колоночная верстка</a></dt> + <dd>Спецификация мульти-колоночной верстки дает вам способ размещения содержимого в столбцах по аналогии с версткой газет. Этот раздел объясняет, как использовать эту возможность.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">Устаревшие методы верстки</a></dt> + <dd>Grid-системы - это очень распространенная возможность, используемая в CSS layouts, и до CSS Grid Layout они, как правило, реализовывались с помощью floats или других возможностей верстки. Вы представляете свою верстку в виде заданного числа столбцов (например, 4 или 6), а затем вы помещаете содержимое в эти воображаемые столбцы. В этом разделе мы рассмотрим, как работают эти старые методы, чтобы вы понимали, как они использовались, если столкнётесь со старыми проектами.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">Поддержка старыми браузерами</a></dt> + <dd> + <p>В этом модуле мы рекомендуем использовать Flexbox и Grid как основные методы верстки для ваших проектов. Однако, ваш сайт могут посещать со старых браузеров или браузеров, которые не поддерживают данные методы. В сети это будет всегда - по мере появления новых возможностей, для различных браузеров будут приорететны различные вещи. Этот раздел объясняет, как использовать современные веб-технологии без блокировки пользователей со старыми технологиями.</p> + </dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">Фундаментальное понятие верстки</a></dt> + <dd>Оценка ваших знаний различных методов верстки посредством вёрстки веб-страницы.</dd> +</dl> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<dl> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Practical_positioning_examples">Практические примеры позиционирования</a></dt> + <dd>Этот раздел показывает, как построить пример из реальной жизни, чтобы проиллюстрировать, что вы можете сделать при помощи позиционирования.</dd> +</dl> diff --git a/files/ru/learn/css/css_layout/introduction/index.html b/files/ru/learn/css/css_layout/introduction/index.html new file mode 100644 index 0000000000..fd443580da --- /dev/null +++ b/files/ru/learn/css/css_layout/introduction/index.html @@ -0,0 +1,705 @@ +--- +title: Введение в CSS вёрстку +slug: Learn/CSS/CSS_layout/Introduction +translation_of: Learn/CSS/CSS_layout/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/CSS/CSS_layout/Normal_Flow", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">В этой статье мы рассмотрим некоторые функции макета CSS, которые мы затрагивали в предыдущих статьях, например различные значения свойства {{cssxref("display")}}, и разберем некоторые концепции, которые будут рассмотрены в этой статье. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Базовые знания HTML (изучите <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">введение в HTML</a>), и понимание как работает CSS (изучите <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">введение в CSS</a>.)</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Предоставить вам обзор методов компоновки страниц CSS. Каждый метод может быть изучен более подробно в последующих статьях. </td> + </tr> + </tbody> +</table> + +<p>Методы компановки страниц CSS позволяют нам использовать элементы, расположенные на веб-странице, и контролировать где они находятся относительно их позиции по умолчанию, других элементов вокруг них, их родителей или главного окна. Методы компоновки страниц, которые мы подробно рассмотрим в этой статье.</p> + +<ul> + <li>Нормальный поток</li> + <li>Свойство {{cssxref("display")}}</li> + <li>Flexbox</li> + <li>Grid</li> + <li>Floats</li> + <li>Позиционирование</li> + <li>Макет таблицы</li> + <li>Многоколоночный макет</li> +</ul> + +<p>Каждый метод имеет свои преимущества и недостатки и ни одна техника не предназначена для использования в изоляции от других. Разбирая данные методы, вы поймете, какой из них лучший инструмент разметки для каждой задачи.</p> + +<h2 id="Normal_flow">Normal flow</h2> + +<p>Нормальный поток (Normal flow) это то как ваш браузер отображает по умолчанию, когда вы не меняли расположение элементов на странице. Взглянем на пример:</p> + +<pre class="brush: html notranslate"><p>I love my cat.</p> + +<ul> + <li>Buy cat food</li> + <li>Exercise</li> + <li>Cheer up friend</li> +</ul> + +<p>The end!</p></pre> + +<p>По умолчанию ваш браузер выведет этот код следующим образом:</p> + +<p>{{ EmbedLiveSample('Normal_flow', '100%', 200) }}</p> + +<p>Заметьте, что HTML элементы здесь отображаются точно в таком порядке, как и в исходном коде — первый параграф, за ним неупорядоченный список, затем второй параграф.</p> + +<p>Элементы, выводящеся один <em>под</em> другим, называются <em>блочными</em>, в противоположность <em>строчным</em>, которые выводятся один <em>вслед</em> за другим, как отдельные слова в обычном абзаце текста.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Направление, в котором отображается содержимое блока, называется Block Direction. Block Direction вертикально в языках типа Английского, имеющих горизонтальное направление письма. В языках, типа Японского, имеющих вертикальное направление письма, Block Direction горизонтально. Соответствующее Inline Direction отвечает за направление отображения строковых элементов (таких как предложение).</p> +</div> + +<p>Когда вы используете CSS для создания разметки, вы двигаете элементы относительно их обычного расположения, но для многих элементов на вашей странице их обычное положение - это именно то, что вам подойдет. Именно поэтому важно начинать верстку с создания правильно организованного HTML документа, для того, чтобы базовое расположение элементов впоследствии работало на вас.</p> + +<p>Методы CSS, которыми вы можете управлять разметкой элементов:</p> + +<ul> + <li><strong>Свойство {{cssxref("display")}} </strong>— Стандартные значениея <code>block</code>, <code>inline</code> или <code>inline-block </code>могут изменять поведение элементов в обычном потоке (см.подробнее <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Box_model#Types_of_CSS_boxes">Types of CSS boxes</a>). Также можно менять сами методы разметки такими значениями свойства <code>display</code>, как <a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">CSS Grid</a> или <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a>.</li> + <li><strong>Floats</strong> — Применение значения {{cssxref("float")}} типа <code>left</code> может заставить элемент блочного типа "прилепить" содержимое к одной стороне элемента, как иногда изображения обволакиваются текстом на газетных страницах.</li> + <li><strong>Свойство {{cssxref("position")}} </strong>— Позволяет точно контролировать положение блоков внутри других блоков. <code>static</code> позиционирование является стандартным, но также можно применять другие значения свойства, например фиксированное в углу экрана.</li> + <li><strong>Макет Таблицы</strong> — свойства для разметки таблиц могут быть использованы и для нетабличных элеметов, с помощью <code>display: table</code> и соотвествующих свойств.</li> + <li><strong>Multi-column layout</strong> — <a href="/en-US/docs/Web/CSS/CSS_Columns">Многоколоночный макет</a> поможет расположить содержимое столбцами, как в газетах.</li> +</ul> + +<h2 id="Свойство_display">Свойство display </h2> + +<p>Значения свойства <code>display</code> являются главными методами верстки разметки страницы в CSS. Это свойство позволяет нам менять то, как что-то отображается по умолчанию. Каждый элемент по умолчанию имеет свойство <code>display</code>, влияющее на то, как этот элемент отображается. Например, параграфы на английском располагаются один под другим только потому что они имеют по умолчанию свойство <code>display: block</code>. Если же вы создадите ссылку внутри параграфа, эта ссылка будет отображаться в общем потоке с остальным текстом, без переноса на новую строку. Это потому что у элемента {{htmlelement("a")}} по умолчанию установлено свойство <code>display: inline</code>.</p> + +<p>Вы можете изменить дефолтное поведение display. К примеру, {{htmlelement("li")}} отображается как <code>display: block</code> по умолчанию, это означает что элементы списка отображаются один за другим в нашем документе.Если мы изменим значение display на <code>inline</code> они будут отображаться друг за другом, как это делают слова в предложении. Тот факт, что вы можете изменить значение display для любого элемента означает, что вы можете выбирать HTML элементы по их семантическому значению, не беспокоясь о том как они будут выглядеть. То как они выглядят это то, что вы можете поменять.</p> + +<p><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">В дополнение к возможности менять значение с </span></font><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;"> </span></font>block</code> на <code>inline</code> и обратно, есть и другие возможности вёрстки с другими значениями <code>display</code>. Однако, в основном все они требуют использования дополнительных свойств. Двумя наиболее важными для задач вёрстки страниц являются <code>display: flex</code> и <code>display: grid</code>.</p> + +<h2 id="Flexbox">Flexbox</h2> + +<p>Flexbox (сокращение от <a href="/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout">Flexible Box Layout</a>) это модуль, разработанный для облегчения верстки в одном из измерений — как ряд или как колонка. Для использования, установите свойство <code>display: flex</code> для родительского элемента тех элементов, к которым хотите применить этот тип верстки; все его прямые потомки станут flex элементами. Рассмотрим это на простом примере.</p> + +<p>Разметка HTML, представленная ниже, состоит из элемента <code>wrapper</code>, включающего в себя три {{htmlelement("div")}} элемента. По умолчанию все они будут изображаться как блочные, один под другим.</p> + +<p>Но если мы добавим свойство <code>display: flex</code> родительскому элементу, три дочерних сгруппируются в колонки. Всё это потому что они сами становятся элементами <em>flex </em>и наследуют некоторые свойства, установленные контейнеру, в котором они находятся. Они выстраиваются в строку, потому что начальное значение {{cssxref("flex-direction")}} это <code>row</code>. Высота становится равной высоте самого высокого элемента, потому что начальное значение {{cssxref("align-items")}} установлено как <code>stretch</code>. Это значит, элементы вытягиваются по высоте контейнера, который в этом случае сам принимает высоту самого высокого элемента. Все они группируются в начале контейнера, оставляя пустое пространство в конце строки.</p> + +<div id="Flex_1"> +<div class="hidden"> +<h6 id="Flexbox_Example_1">Flexbox Example 1</h6> + +<pre class="brush: css notranslate">* {box-sizing: border-box;} + +.wrapper > div { + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} + </pre> +</div> + +<pre class="brush: css notranslate">.wrapper { + display: flex; +} +</pre> + +<pre class="brush: html notranslate"><div class="wrapper"> + <div class="box1">One</div> + <div class="box2">Two</div> + <div class="box3">Three</div> +</div> +</pre> +</div> + +<p>{{ EmbedLiveSample('Flex_1', '300', '200') }}</p> + +<p>В дополнение к свойствам, применяемым к контейнеру, существуют свойства, применяемые ко вложенным элементам. Эти свойства помимо всего прочего, могут менять размеры элемента, растягивая его и заставляя занимать всё доступное место.</p> + +<p>В качестве простого примера, добавим свойство {{cssxref("flex")}} ко всем дочерним элементам, со значением <code>1</code>. Это заставит все элементы растянуться и заполнить контейнер, не оставляя свободного места в конце строки. Если освободится дополнительное пространство, элементы растянутся; если доступное местро убавится - элементы сожмутся. Также, если вы добавите дополнительный элемент, остальные элементы станут меньше, для того, чтобы все они были одного размера.</p> + +<div id="Flex_2"> +<div class="hidden"> +<h6 id="Flexbox_Example_2">Flexbox Example 2</h6> + +<pre class="brush: css notranslate"> * {box-sizing: border-box;} + + .wrapper > div { + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; + } + </pre> +</div> + +<pre class="brush: css notranslate">.wrapper { + display: flex; +} + +.wrapper > div { + flex: 1; +} +</pre> + +<pre class="brush: html notranslate"><div class="wrapper"> + <div class="box1">One</div> + <div class="box2">Two</div> + <div class="box3">Three</div> +</div> +</pre> +</div> + +<p>{{ EmbedLiveSample('Flex_2', '300', '200') }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: Это было очень краткое введение в то что возможно во Flexbox, чтобы узнать больше см. нашу статью <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a>.</p> +</div> + +<h2 id="Grid_Layout">Grid Layout</h2> + +<p>В то время как flexbox предназначен для одномерной разметки, Grid Layout предназначен для двумерной — выстраивая предметы в ряды и столбцы.</p> + +<p>Еще раз, вы можете переключиться на Grid Layout при помощи конкретного значения отображения — <code>display: grid</code>. Пример ниже использует разметку подобную примеру flex, а также мы определяем некоторые дорожки рядов и столбцов в родительском элементе, используя свойства {{cssxref("grid-template-rows")}} и {{cssxref("grid-template-columns")}} соответственно. Мы определили три столбца каждый по <code>1fr</code> и два ряда по <code>100px</code>. Мне не надо вводить какие-либо правила для дочерних элементов; <span class="tlid-translation translation" lang="ru"><span title="">они автоматически помещаются в ячейки, созданные нашей сеткой.</span></span></p> + +<div id="Grid_1"> +<div class="hidden"> +<h6 id="Grid_example_1">Grid example 1</h6> + +<pre class="brush: css notranslate"> * {box-sizing: border-box;} + + .wrapper > div { + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; + } + </pre> +</div> + +<pre class="brush: css notranslate">.wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: 100px 100px; + grid-gap: 10px; +} +</pre> + +<pre class="brush: html notranslate"><div class="wrapper"> + <div class="box1">One</div> + <div class="box2">Two</div> + <div class="box3">Three</div> + <div class="box4">Four</div> + <div class="box5">Five</div> + <div class="box6">Six</div> +</div> +</pre> +</div> + +<p>{{ EmbedLiveSample('Grid_1', '300', '330') }}</p> + +<p>Когда у вас есть сетка (grid), мы можете точно размещать на ней свои элементы, а не полагаться на поведение авто-размещения, отмеченного выше. Ниже во втором примере мы задали ту же сетку, но в этот раз с тремя дочерними элементами. Мы задали начало и конец линии каждого элемента используя свойства {{cssxref("grid-column")}} и {{cssxref("grid-row")}}. Это заставляет элементы охватывать несколько дорожек.</p> + +<div id="Grid_2"> +<div class="hidden"> +<h6 id="Grid_example_2">Grid example 2</h6> + +<pre class="brush: css notranslate"> * {box-sizing: border-box;} + + .wrapper > div { + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; + } + </pre> +</div> + +<pre class="brush: css notranslate">.wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: 100px 100px; + grid-gap: 10px; +} + +.box1 { + grid-column: 2 / 4; + grid-row: 1; +} + +.box2 { + grid-column: 1; + grid-row: 1 / 3; +} + +.box3 { + grid-row: 2; + grid-column: 3; +} +</pre> + +<pre class="brush: html notranslate"><div class="wrapper"> + <div class="box1">One</div> + <div class="box2">Two</div> + <div class="box3">Three</div> +</div> +</pre> +</div> + +<p>{{ EmbedLiveSample('Grid_2', '300', '330') }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: Эти два примера всего лишь малая часть мощности Grid layout; чтобы узнать больше см. нашу статью <a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Grid Layout</a>.</p> +</div> + +<p>Остальная часть этого руководства освещает другие методы разметок, которые менее важны для основной структуры разметки вашей страницы, но все равно могут помочь вам в достижении определенных задач. Понимая природу задачи каждой разметки, вы вскоре обнаружите, что, глядя на конкретный компонент вашего дизайна, часто будет ясно какой тип разметки подходит лучше всего.</p> + +<h2 id="Floats">Floats</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Делая элемент плавающим (float) мы меняем поведение этого элемента и элементов блочного уровня, следующих за ним в нормальном потоке.</span> <span title="">Элемент перемещается влево или вправо и удаляется из нормального потока (</span></span>normal flow<span class="tlid-translation translation" lang="ru"><span title="">), а окружающий контент обтекает плавающий элемент.</span></span></p> + +<p>Свойство {{cssxref("float")}} имеет четыре возможных значения:</p> + +<ul> + <li><code>left</code> — Элемент выравнивается слева и другие элементы обтекают его справа.</li> + <li><code>right</code> — Элемент выравнивается справа и другие элементы обтекают его слева.</li> + <li><code>none</code> — Не задает float совсем. Это значение по умолчанию.</li> + <li><code>inherit</code> — Определяет, что значение свойства <code>float</code> должно быть унаследовано от родительского элемента.</li> +</ul> + +<p>В примере ниже мы задаем элементу <code><div></code> float - left и даем {{cssxref("margin")}} с правой стороны чтобы отталкивать текст от этого элемента. Это дает нам эффект того, что текст оборачивает этот блок <span class="tlid-translation translation" lang="ru"><span title="">и является большей частью того, что вам нужно знать о float, используемых в современном веб-дизайне.</span></span></p> + +<div id="Float_1"> +<div class="hidden"> +<h6 id="Floats_example">Floats example</h6> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 0 auto; +} + +p { + line-height: 2; + word-spacing: 0.1rem; +} + +.box { + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + border-radius: 5px; +} +</pre> +</div> + +<pre class="brush: html notranslate"><h1>Simple float example</h1> + +<div class="box">Float</div> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +</pre> + +<pre class="brush: css notranslate"> +.box { + float: left; + width: 150px; + height: 150px; + margin-right: 30px; +} +</pre> +</div> + +<p>{{ EmbedLiveSample('Float_1', '100%', 600) }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: Float полностью объяснен в нашем уроке по свойствам <a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">float и clear</a>. До таких методов как Flexbox и Grid Layout, float использовался как метод создания макетов колонок. Вы все еще можете встретить эти методы в интернете; мы рассмотрим их в уроке по <a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">устаревшим методам разметки</a>.</p> +</div> + +<h2 id="Методы_позиционирования">Методы позиционирования</h2> + +<p>Позиционирование позволяет вам перемещать элементы с места, где бы они располагались при нормальном потоке в другую локацию. Позиционирование не является методом создания основной разметки страницы, <span class="tlid-translation translation" lang="ru"><span title="">это больше об управлении и точной настройке положения определенных элементов на странице.</span></span></p> + +<p>Однако, существуют полезные методы точной разметки шаблонов, которые полагаются на свойство {{cssxref("position")}}. Понимание позиционирования также способствует пониманию нормального потока <span class="tlid-translation translation" lang="ru"><span title=""> и того, что значит вывести элемент из нормального потока.</span></span></p> + +<p>Существует пять типов позиционирования о которых вам следует знать:</p> + +<ul> + <li><strong>Static positioning (статическое позиционирование)</strong> — умолчание, которое получают все элементы — это все лишь значит "поместить элемент в его нормальную позицию в разметке документа — тут нет ничего особенного на что посмотреть".</li> + <li><strong>Relative positioning (относительное позиционирование) </strong>позволяет вам менять положение элемента на странице, перемещая его относительно его положения в нормальном потоке — в том числе заставляя его перекрывать другие элементы на странице.</li> + <li><strong>Absolute positioning (абсолютное позиционирование) </strong>полностью перемещает элемент из нормального потока разметки страницы так будто он находится на своем собственном отдельном слое. Оттуда вы можете исправлять его положение относительно краев <code><html></code> элемента страницы (или его ближайшего позиционированного элемента предка). Это является полезным при создании сложных эффектов разметки такие как вкладки, <span class="tlid-translation translation" lang="ru"><span title=""> в которых различные панели содержимого располагаются друг над другом</span></span> и отображаются и/или скрываются по желанию или информационные панели, которые располагаются на экране по умолчанию, но могут скользить по экрану используя кнопки управления.</li> + <li><strong>Fixed positioning (фиксированное позиционирование) </strong>очень похоже на абсолютное за исключением того, что он изменяет положение относительно окна просмотра браузера, а не другого элемента. Это полезно при создании эффектов таких как постоянное меню навигации, которое всегда остается в одном и том же месте на экране, в то время как другой контент прокручивается.</li> + <li><strong>Sticky positioning (липкое позиционирование) </strong>это новый метод позиционирования, который заставляет элемент вести себя как <code>position: static</code> пока не достигнет определенной линии окна просмотра и с этого момента будет вести себя как <code>position: fixed</code>.</li> +</ul> + +<h3 id="Пример_простого_позиционирования">Пример простого позиционирования</h3> + +<p>Для ознакомления с этими методами верстки, мы покажем вам пару быстрых примеров. Наши примеры будут иметь одинаковый HTML, который выглядит следующим образом:</p> + +<pre class="brush: html notranslate"><h1>Positioning</h1> + +<p>I am a basic block level element.</p> +<p class="positioned">I am a basic block level element.</p> +<p>I am a basic block level element.</p></pre> + +<p>Этот HTML по умолчанию будет стилизован, используя следующий CSS:</p> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; +} + +p { + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + margin: 10px; + border-radius: 5px; +} +</pre> + +<p>Результат выглядит следующим образом:</p> + +<p>{{ EmbedLiveSample('Пример_простого_позиционирования', '100%', 300) }}</p> + +<h3 id="Relative_positioning">Relative positioning</h3> + +<p>Относительное (Relative) позиционирование позволяет вам смещать элемент относительно положения, которое он бы имел по умолчанию в нормальном потоке. Это значит, что вы можете выполнить такую задачу как перемещение иконки немного вниз, так чтобы он был на одной линии с текстовой меткой. Чтобы сделать это, мы можем добавить следующее правило для добавления относительного позиционирования.</p> + +<pre class="brush: css notranslate">.positioned { + position: relative; + top: 30px; + left: 30px; +}</pre> + +<p>Здесь мы даем нашему среднему параграфу {{cssxref("position")}} со значением <code>relative</code> — сам по себе он ничего не делает, поэтому мы также добавляем свойства {{cssxref("top")}} и {{cssxref("left")}}. Они служат для перемещения задействованного элемента вниз и вправо — что может выглядеть как противоположность тому, чего вы ожидаете, но вам надо думать об этом так будто элемент отталкивается от левого или верхнего края, и в результате он перемещается вправо и вниз.</p> + +<p>Добавление этого кода даст следующий результат:</p> + +<div id="Relative_1"> +<div class="hidden"> +<h6 id="Relative_positioning_example">Relative positioning example</h6> + +<pre class="brush: html notranslate"><h1>Relative positioning</h1> + +<p>I am a basic block level element.</p> +<p class="positioned">This is my relatively positioned element.</p> +<p>I am a basic block level element.</p></pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; +} + +p { + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + margin: 10px; + border-radius: 5px; +} +</pre> +</div> + +<pre class="brush: css notranslate">.positioned { + position: relative; + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Relative_1', '100%', 300) }}</p> + +<h3 id="Absolute_positioning">Absolute positioning</h3> + +<p>Абсолютное (Absolute) позиционирование используется чтобы полностью удалить элемент из нормального потока и разместить его, используя смещение от краев содержащего блока.</p> + +<p>Возвращаясь к нашему примеру без позиционирования, мы можем добавить следующее CSS правило, чтобы реализовать абсолютное позиционирование:</p> + +<pre class="brush: css notranslate">.positioned { + position: absolute; + top: 30px; + left: 30px; +}</pre> + +<p>Здесь мы даем нашему среднему параграфу {{cssxref("position")}} со значением <code>absolute</code>, и все те же свойства {{cssxref("top")}} и {{cssxref("left")}} как ранее. Однако, добавление этого кода даст следующий результат:</p> + +<div id="Absolute_1"> +<div class="hidden"> +<h6 id="Absolute_positioning_example">Absolute positioning example</h6> + +<pre class="brush: html notranslate"><h1>Absolute positioning</h1> + +<p>I am a basic block level element.</p> +<p class="positioned">This is my absolutely positioned element.</p> +<p>I am a basic block level element.</p></pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; +} + +p { + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + margin: 10px; + border-radius: 5px; +} +</pre> +</div> + +<pre class="brush: css notranslate">.positioned { + position: absolute; + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Absolute_1', '100%', 300) }}</p> + +<p>Это совсем другое! Позиционированный элемент теперь совершенно отделен от разметки остальной страницы и располагется поверх него. Другие два параграфа теперь располагаются вместе так будто бы их позиционированный брат не существует. Свойства {{cssxref("top")}} и {{cssxref("left")}} имеют иной эффект на абсолютно позиционированные элементы, чем на относительно позиционированные элементы. В данном случае смещения были рассчитаны сверху и слева от страницы. Возможно изменить родительский элемент так что он становится контейнером, но мы рассмотрим это в уроке по <a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">позиционированию</a>.</p> + +<h3 id="Fixed_positioning">Fixed positioning</h3> + +<p>Фиксированное (Fixed) позиционирование удаляет наш элемент из потока документа так же, как и абсолютное позиционирование. Однако, вместо смещения применяемого относительно контейнера, оно применяется относительно окна просмотра. Поскольку элемент остается зафиксированным относительно окна просмотра, мы можем создавать такие эффекты как меню, которое остается зафиксированным пока страница прокручивается под ним.</p> + +<p>Для этого примера наш HTML это три параграфа текста для того, чтобы мы могли прокручивать страницу и блок, которому мы дадим <code>position: fixed</code>.</p> + +<pre class="brush: html notranslate"><h1>Fixed positioning</h1> + +<div class="positioned">Fixed</div> + +<p>Paragraph 1.</p> +<p>Paragraph 2.</p> +<p>Paragraph 3.</p> +</pre> + +<div id="Fixed_1"> +<div class="hidden"> +<h6 id="Fixed_positioning_example">Fixed positioning example</h6> + +<pre class="brush: html notranslate"><h1>Fixed positioning</h1> + +<div class="positioned">Fixed</div> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +</pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; +} + +.positioned { + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + padding: 10px; + margin: 10px; + border-radius: 5px; +}</pre> +</div> + +<pre class="brush: css notranslate">.positioned { + position: fixed; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Fixed_1', '100%', 200) }}</p> + +<h3 id="Sticky_positioning">Sticky positioning</h3> + +<p>Липкое (Sticky) позиционирование — это последний тип позиционирования которой мы имеем в нашем распоряжении. Это микс дефолтного статического позиционирования с фиксированным позиционированием. когда элемент имеет <code>position: sticky</code> он будет прокручиваться в нормальном потоке пока не достигнет границы окна просмотра которую мы задали. С этого момента он (элемент) "прилипает", как если бы был применен <code>position: fixed</code>.</p> + +<div id="Sticky_1"> +<div class="hidden"> +<h6 id="Sticky_positioning_example">Sticky positioning example</h6> + +<pre class="brush: html notranslate"><h1>Sticky positioning</h1> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<div class="positioned">Sticky</div> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> </pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; +} + +.positioned { + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + padding: 10px; + margin: 10px; + border-radius: 5px; +}</pre> +</div> + +<pre class="brush: css notranslate">.positioned { + position: sticky; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Sticky_1', '100%', 200) }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: чтобы узнать больше о позиционировании, см. нашу статью <a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Позиционирование.</a></p> +</div> + +<h2 id="Макет_таблицы">Макет таблицы</h2> + +<p>HTML таблицы хороши для отображения табличных данных, но много лет назад — до того, как даже <span class="tlid-translation translation" lang="ru"><span title="">базовый CSS</span></span> <span class="tlid-translation translation" lang="ru"><span title="">надежно</span></span> поддерживался <span class="tlid-translation translation" lang="ru"><span title="">в браузерах </span></span>— веб-разработчики также использовали таблицы для разметки всей веб-страницы — размещая свои заголовки, нижние колонтитулы, различные колонки и т.д. в разных строках и столбцах таблиц. Это работало в то время, но оно имеет много проблем — разметка таблиц не гибкая, очень тяжелая в верстке, сложна в отладке, и семантически не верная. (например, пользователи скринридеров имеют проблемы с навигацией в табличном макете).</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">То, как таблица выглядит на веб-странице при использовании разметки таблицы, обусловлено набором свойств CSS, которые определяют макет таблицы</span></span>. <span class="tlid-translation translation" lang="ru"><span title="">Эти свойства могут использоваться для размещения элементов, которые не являются таблицами, использование, которое иногда описывается как «использование CSS таблиц».</span></span></p> + +<p>Пример ниже показывает одно такое использование; использование CSS таблиц для верстки должно считаться устаревшим методом на данный момент, для тех ситуаций, когда у вас старые браузеры без поддержки Flexbox или Grid.</p> + +<p>Давайте взглянем на пример. Во-первых, немного простой разметки, которая создает HTML форму. Каждый input элемент имеет label, и мы также заключили описание в параграф. каждая пара label/input обернута в {{htmlelement("div")}}, для целей верстки.</p> + +<pre class="brush: html notranslate"><form> + <p>First of all, tell us your name and age.</p> + <div> + <label for="fname">First name:</label> + <input type="text" id="fname"> + </div> + <div> + <label for="lname">Last name:</label> + <input type="text" id="lname"> + </div> + <div> + <label for="age">Age:</label> + <input type="text" id="age"> + </div> +</form></pre> + +<p>А теперь CSS для нашего примера. Большая часть CSS довольно обычна, за исключением использования свойства {{cssxref("display")}}. {{htmlelement("form")}}-е, {{htmlelement("div")}}-ам, а также {{htmlelement("label")}}-ам и {{htmlelement("input")}}-ам было сказано отображать как таблица, табличные строки и табличные ячейки соответственно — в принципе, они будут вести себя как разметка HTML таблицы, заставляя label-ы and input-ы красиво выравниваться по умолчанию. Все что мы должны будем сделать это добавить немного размеров, margin и т.д., чтобы все выглядело красивей, и на этом мы закончили.</p> + +<p>Вы заметите, что параграфу с описанием дано <code>display: table-caption;</code> — что заставляет его вести себя как табличный {{htmlelement("caption")}} — а <code>caption-side: bottom;</code> для того чтобы указать описанию располагаться снизу таблицы в целях дизайна, не смотря на то что разметка находится до <code><input></code> элементов в источнике. Это обеспечивает гибкостью.</p> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +form { + display: table; + margin: 0 auto; +} + +form div { + display: table-row; +} + +form label, form input { + display: table-cell; + margin-bottom: 10px; +} + +form label { + width: 200px; + padding-right: 5%; + text-align: right; +} + +form input { + width: 300px; +} + +form p { + display: table-caption; + caption-side: bottom; + width: 300px; + color: #999; + font-style: italic; +}</pre> + +<p>Это дает нам следующий результат:</p> + +<p>{{ EmbedLiveSample('Макет_таблицы', '100%', '170') }}</p> + +<p>Также вы можете посмотреть этот живой пример на <a href="https://mdn.github.io/learning-area/css/styling-boxes/box-model-recap/css-tables-example.html">css-tables-example.html</a> (смотрите также <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/box-model-recap/css-tables-example.html">исходный код</a>.)</p> + +<h2 id="Многоколоночный_макет">Многоколоночный макет</h2> + +<p>Модуль многоколоночного макета (multi-column layout) дает нам способ располагать контент в столбцах, подобно тому, как текст располагается в газете. Хоть и чтение <span class="tlid-translation translation" lang="ru"><span title="">столбцов вверх и вниз менее полезно в контексте веба, так как вы не хотите заставлять пользователей прокручивать вверх и вниз, размещение контента по столбцам может быть полезной техникой.</span></span></p> + +<p>Чтобы превратить блок в многоколоночный контейнер мы используем свойство {{cssxref("column-count")}}, которое говорит браузеру сколько колонок мы хотим иметь, либо свойство {{cssxref("column-width")}}, которое говорит браузеру заполнить контейнер <span class="tlid-translation translation" lang="ru"><span title="">как можно большим количеством столбцов, по крайней мере, такой ширины.</span></span></p> + +<p>В примере ниже мы начинаем с HTML блоком, который содержится в элементе <code><div></code> с классом <code>container</code>.</p> + +<pre class="brush: html notranslate"><div class="container"> + <h1>Multi-column layout</h1> + + <p>Paragraph 1.</p> + <p>Paragraph 2.</p> + +</div> +</pre> + +<p>Мы используем <code>column-width</code> 200 px для этого контейнера, заставляя браузер создавать столько 200 пиксельных столбцов, сколько уместится в этом контейнере и затем разделить оставшееся пространство между созданными столбцами.</p> + +<div id="Multicol_1"> +<div class="hidden"> +<h6 id="Multicol_example">Multicol example</h6> + +<pre class="brush: html notranslate"> <div class="container"> + <h1>Multi-column Layout</h1> + + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + + </div> + </pre> + +<pre class="brush: css notranslate">body { max-width: 800px; margin: 0 auto; } </pre> +</div> + +<pre class="brush: css notranslate"> .container { + column-width: 200px; + }</pre> +</div> + +<p>{{ EmbedLiveSample('Multicol_1', '100%', 200) }}</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Эта статья предоставила короткое обобщение всех методов макетов о которых вам следует знать. Читайте далее для получения дополнительной информации по каждому методу!</p> + +<p>{{NextMenu("Learn/CSS/CSS_layout/Normal_Flow", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">Введение в CSS верстку</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow">Нормальный поток</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Grid</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Позиционирование</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Многоколоночный макет</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">Устаревшие методы верстки</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">Поддержка старых браузеров</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">Оценка понимания базовых макетов</a></li> +</ul> diff --git a/files/ru/learn/css/css_layout/positioning/index.html b/files/ru/learn/css/css_layout/positioning/index.html new file mode 100644 index 0000000000..3fe1be6b00 --- /dev/null +++ b/files/ru/learn/css/css_layout/positioning/index.html @@ -0,0 +1,581 @@ +--- +title: Позиционирование +slug: Learn/CSS/CSS_layout/Positioning +translation_of: Learn/CSS/CSS_layout/Positioning +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Floats", "Learn/CSS/CSS_layout/Multiple-column_Layout", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">Позиционирование позволяет вам изымать элементы из нормального потока макета документа и заставить их вести себя по-другому; например, располагаться друг на друге или всегда оставаться на одном и том же месте внутри окна просмотра браузера. Эта статья объясняет разные значения {{cssxref("position")}} и как их использовать.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Основы HTML (изучите <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), идея о том как работает CSS (изучите <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a>.)</p> + </td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Изучить как работает CSS позиционирование.</td> + </tr> + </tbody> +</table> + +<p>Нам бы хотелось чтобы вы следовали за нами с упражнениями на вашем локальном ПК, если возможно возьмите копию <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/0_basic-flow.html">0_basic-flow.html</a></code> из нашего GitHub репозитория (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/0_basic-flow.html">исходный код здесь</a>) и используйте его как отправную точку.</p> + +<h2 id="Введение_в_позиционирование">Введение в позиционирование</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вся идея позиционирования заключается в том, чтобы позволить нам переопределять поведение базового потока документа, описанного выше, для того чтобы производить интересные эффекты. Что если вам захочется слегка изменить позицию каких-либо блоков внутри макета относительно их позиции в потоке макета по умолчанию? Ваш инструмент - позиционирование. Или </span></span><span class="tlid-translation translation" lang="ru"><span title="">если вы хотите создать элемент пользовательского интерфейса, который плавает над другими частями страницы и/или всегда располагается на одном и том же месте в окне браузера не зависимо от того сколько прокручивалась страница? Позиционирование делает возможным работу таких макетов.</span></span></p> + +<p>Существует несколько разных типов позиционирования<span class="tlid-translation translation" lang="ru"><span title="">, которые вы можете применить к элементам HTML. Для активации специфического типа позиционирования у элемента, мы используем свойство </span></span>{{cssxref("position")}}.</p> + +<h3 id="Статическое_позиционирование">Статическое позиционирование</h3> + +<p>Статическое позиционирование — это умолчание, которое получает каждый элемент, что всего лишь значит "поставить элемент в его нормальное положение в потоке макета документа — ничего особенного для рассмотрения".</p> + +<p>Чтобы продемонстрировать это и настроить ваш образец для будущих разделов, сначала добавьте <code>class</code> <code>positioned</code> ко второму {{htmlelement("p")}} в HTML:</p> + +<pre class="brush: html notranslate"><p class="positioned"> ... </p></pre> + +<p>А теперь добавьте следующее правило в конец вашего CSS:</p> + +<pre class="brush: css notranslate">.positioned { + position: static; + background: yellow; +}</pre> + +<p>И если вы сейчас сохраните и обновите, то вы не увидите никаких изменений, не считая обновленного цвета фона 2-го параграфа. Это нормально, как мы и говорили ранее, статическое позиционирование является поведением по умолчанию!</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете посмотреть живой пример на данном этапе на <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/1_static-positioning.html">1_static-positioning.html</a></code> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/1_static-positioning.html">см. исходный код</a>).</p> +</div> + +<h3 id="Относительное_позиционирование">Относительное позиционирование</h3> + +<p>Относительное позиционирование первый тип позиции, который мы рассмотрим. Оно очень похоже на статическое позиционирование, за исключением того что вы можете модифицировать окончательное положение позиционируемого объекта занявшего свое место в макете нормального потока, в том числе заставлять его перекрывать другие элементы на странице. Двигайтесь далее и обновите объявление <code>position</code> в вашем коде:</p> + +<pre class="brush: css notranslate">position: relative;</pre> + +<p>Если вы сохраните и обновите на данном этапе, в результате вы совсем не увидите изменений. Так как же вам модифицировать положение? Вам необходимо использовать свойства {{cssxref("top")}}, {{cssxref("bottom")}}, {{cssxref("left")}}, и {{cssxref("right")}} которые мы объясним в следующем разделе.</p> + +<h3 id="Введение_в_top_bottom_left_и_right">Введение в top, bottom, left, и right</h3> + +<p>{{cssxref("top")}}, {{cssxref("bottom")}}, {{cssxref("left")}}, и {{cssxref("right")}} используются вместе с {{cssxref("position")}} чтобы указать куда именно перемещать позиционируемый элемент. Для того чтобы попробовать, добавьте следующее объявление к правилу <code>.positioned</code> в вашем CSS:</p> + +<pre class="brush: css notranslate">top: 30px; +left: 30px;</pre> + +<div class="note"> +<p><strong>Примечание</strong>: значения этих свойств могут принимать любые <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Values_and_units">единицы</a> которые вы ожидаете по логике: пиксели, мм, rems, %, и т.д.</p> +</div> + +<p>Если вы сейчас сохраните и обновите, вы получите примерно такой результат:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Relative positioning</h1> + +<p>I am a basic block level element. My adjacent block level elements sit on new lines below me.</p> + +<p class="positioned">By default we span 100% of the width of our parent element, and we are as tall as our child content. Our total width and height is our content + padding + border width/height.</p> + +<p>We are separated by our margins. Because of margin collapsing, we are separated by the width of one of our margins, not both.</p> + +<p>inline elements <span>like this one</span> and <span>this one</span> sit on the same line as one another, and adjacent text nodes, if there is space on the same line. Overflowing inline elements <span>wrap onto a new line if possible — like this one containing text</span>, or just go on to a new line if not, much like this image will do: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +.positioned { + position: relative; + background: yellow; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Введение_в_top_bottom_left_и_right', '100%', 500) }}</p> + +<p>Круто, правда? Хорошо, вероятно это не то, чего вы ожидали — почему он переместился вниз и вправо, когда мы указали вверх и влево? <span class="tlid-translation translation" lang="ru"><span title="">Как бы нелогично это ни звучало</span></span> это всего лишь способ того как работает позиционирование — вам надо думать о невидимой силе толкающей указанную сторону позиционируемого блока, перемещая его в противоположную сторону. Так, например, если вы указали <code>top: 30px;</code>, сила толкает блок, заставляя его перемещаться вниз на 30px.</p> + +<div class="note"> +<p><strong>Примечание</strong>: вы можете посмотреть пример на этом этапе на <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/2_relative-positioning.html">2_relative-positioning.html</a></code> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/2_relative-positioning.html">см. исходный код</a>).</p> +</div> + +<h3 id="Абсолютное_позиционирование">Абсолютное позиционирование</h3> + +<p>Абсолютное позиционирование дает совершенно другие результаты. Давайте попробуем изменить объявление позиции в вашем коде как показано ниже:</p> + +<pre class="brush: css notranslate">position: absolute;</pre> + +<p>Если вы сохраните и обновновите, то вы должны увидеть нечто подобное:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Absolute positioning</h1> + +<p>I am a basic block level element. My adjacent block level elements sit on new lines below me.</p> + +<p class="positioned">By default we span 100% of the width of our parent element, and we are as tall as our child content. Our total width and height is our content + padding + border width/height.</p> + +<p>We are separated by our margins. Because of margin collapsing, we are separated by the width of one of our margins, not both.</p> + +<p>inline elements <span>like this one</span> and <span>this one</span> sit on the same line as one another, and adjacent text nodes, if there is space on the same line. Overflowing inline elements <span>wrap onto a new line if possible — like this one containing text</span>, or just go on to a new line if not, much like this image will do: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +.positioned { + position: absolute; + background: yellow; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Абсолютное_позиционирование', '100%', 420) }}</p> + +<p>В первую очередь обратите внимание на то, что интервал там, где должен быть позиционируемый элемент в потоке документа теперь отсутствует — первый и третий элементы сблизились так будто, он больше не существует! Ну, в каком-то смысле это правда. Абсолютно позиционированный элемент больше не существует в нормальном потоке макета документа. Вместо этого он располагается на своем собственном слое отдельно от всего остального. Это очень полезно: это значит, что мы можем создавать изолированные функции пользовательского интерфейса, которые не влияют на макет других элементов страницы. Например, всплывающие информационные блоки и меню управления; <span class="tlid-translation translation" lang="ru"><span title="">опрокидывающиеся панели; ф</span></span><span class="tlid-translation translation" lang="ru"><span title="">ункции пользовательского интерфейса, которые можно перетаскивать в любом месте страницы;</span> <span title="">и так далее...</span></span></p> + +<p>Во-вторых, обратите внимание, что позиция элемента изменилась — это потому, что {{cssxref("top")}}, {{cssxref("bottom")}}, {{cssxref("left")}}, и {{cssxref("right")}} ведут себя по-другому с абсолютным позиционированием. <span class="tlid-translation translation" lang="ru"><span title="">Вместо того, чтобы позиционировать элемент на основе его относительного положения в обычном потоке макета документа, они определяют расстояние, на котором элемент должен находиться от каждой из сторон содержащего элемента. Поэтому в этом случае мы говорим, что абсолютно позиционированный элемент должен располагаться в 30px от верха "содержащего элемента" и 30px от левого края (В этом случае "содержащий элемент" является </span></span><strong><span class="tlid-translation translation" lang="ru"><span title="">исходным содержащим блоком</span></span></strong>. См. раздел ниже для дополнительной информации<span class="tlid-translation translation" lang="ru"><span title="">).</span></span></p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете использовать {{cssxref("top")}}, {{cssxref("bottom")}}, {{cssxref("left")}}, и {{cssxref("right")}} для изменения размера элемента если вам надо. Попробуйте установить <code>top: 0; bottom: 0; left: 0; right: 0;</code> и <code>margin: 0;</code> для вашего позиционируемого элемента и посмотрите, что произойдет! <span class="tlid-translation translation" lang="ru"><span title="">Потом снова все верните...</span></span></p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Да, margin-ы все еще влияют на позиционируемый элемент. Однако, схлопывания margin не происходит.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: вы можете посмотреть пример на этом этапе на <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/3_absolute-positioning.html">3_absolute-positioning.html</a></code> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/3_absolute-positioning.html">см. исходный код</a>).</p> +</div> + +<h3 id="Контекст_позиционирования">Контекст позиционирования</h3> + +<p>Какой элемент является "содержащим" относительно абсолютно позиционируемого элемента? Это очень сильно зависит от свойства позиции предка позиционируемого элемента (см. <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block">Определение содержащего блока</a>).</p> + +<p>Если никакие из элементов предков не имеют конкретно заданного свойства позиции, то по умолчанию все элементы предков будут иметь статическую позицию. В результате этого абсолютно позиционируемый элемент будет содержаться в <strong><span class="tlid-translation translation" lang="ru"><span title="">исходным </span></span>содержащем блоке</strong>. <span class="tlid-translation translation" lang="ru"><span title="">Исходный </span></span>содержащий блок <span class="tlid-translation translation" lang="ru"><span title="">имеет размеры области просмотра</span></span>, а также является блоком, содержащим элемент {{htmlelement("html")}}. <span class="tlid-translation translation" lang="ru"><span title="">Проще говоря</span></span>, абсолютно позиционируемый элемент будет отображаться за пределами элемента {{htmlelement("html")}} и будет расположен относительно исходного окна просмотра.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Позиционируемый элемент вложен в {{htmlelement ("body")}} в исходном HTML, но в конечном макете он расположен на </span></span>30px от верхнего и левого края страницы. Мы можем изменить <strong>контекст </strong> <strong>позиционирования </strong>— относительно какого элемента позиционируется позиционируемый элемент. <span class="tlid-translation translation" lang="ru"><span title="">Это делается путем установки позиционирования на одном из предков элемента </span></span>— <span class="tlid-translation translation" lang="ru"><span title="">на один из элементов, внутри которого он вложен (вы не можете позиционировать его относительно элемента, внутри которого он НЕ вложен).</span> <span title="">Чтобы продемонстрировать это, добавьте следующее объявление в правило вашего </span></span><code>body</code><span class="tlid-translation translation" lang="ru"><span title="">:</span></span></p> + +<pre class="brush: css notranslate">position: relative;</pre> + +<p>Это должно дать следующий результат:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Positioning context</h1> + +<p>I am a basic block level element. My adjacent block level elements sit on new lines below me.</p> + +<p class="positioned">Now I'm absolutely positioned relative to the <code>&lt;body&gt;</code> element, not the <code>&lt;html&gt;</code> element!</p> + +<p>We are separated by our margins. Because of margin collapsing, we are separated by the width of one of our margins, not both.</p> + +<p>inline elements <span>like this one</span> and <span>this one</span> sit on the same line as one another, and adjacent text nodes, if there is space on the same line. Overflowing inline elements <span>wrap onto a new line if possible — like this one containing text</span>, or just go on to a new line if not, much like this image will do: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; + position: relative; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +.positioned { + position: absolute; + background: yellow; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Контекст_позиционирования', '100%', 420) }}</p> + +<p>Позиционируемый элемент теперь располагается относительно элемента {{htmlelement("body")}}.</p> + +<div class="note"> +<p><strong>Примечание</strong>: вы можете посмотреть живой пример на этом этапе на <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/4_positioning-context.html">4_positioning-context.html</a></code> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/4_positioning-context.html">см. исходный код</a>).</p> +</div> + +<h3 id="Введение_в_z-index">Введение в z-index</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Все это абсолютное позиционирование </span></span>— <span class="tlid-translation translation" lang="ru"><span title="">хорошее развлечение</span></span>, но кое-что чего мы еще не рассмотрели — когда элементы начинают перекрываться, что определяет который из элементов будет появляться поверх другого элемента? В примере, который мы видели все это время, у нас имеется только один позиционируемый элемент в контексте позиционирования, и он появляется сверху поскольку позиционируемые элементы "побеждают" не позиционированные элементы. Что же насчет того, когда мы имеем более одного?</p> + +<p>Попробуйте добавить следующий CSS, чтобы сделать первый параграф так же абсолютно позиционированным:</p> + +<pre class="brush: css notranslate">p:nth-of-type(1) { + position: absolute; + background: lime; + top: 10px; + right: 30px; +}</pre> + +<p>На этом этапе вы увидите, что первый параграф окрашенный в лаймовый изъят из потока документа и помещен чуточку выше того места, где он был исходно. А <span class="tlid-translation translation" lang="ru"><span title="">также он расположен под оригинальным параграфом </span></span><code>.positioned</code>, где они оба перекрываются. Это потому что параграф <code>.positioned</code> является вторым параграфом по порядку в источнике и позже позиционируемые элементы в порядке источника выигрывают над ранее позиционируемыми элементами в порядке источника.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Можете ли вы изменить порядок наложения?</span></span> Да, можете, используя свойство {{cssxref("z-index")}}. "z-index" это ссылка к z-оси. Вы можете вспомнить из предыдущих этапов в этом курсе, где мы обсуждали использование горизонтальных (x-ось) и вертикальных (y-оси) координат веб-страницами для <span class="tlid-translation translation" lang="ru"><span title="">определения позиции для таких вещей, как фоновые изображения</span></span> и смещение теней. (0,0) находится наверху слева страницы (или элемента) и оси x- и y- направляются направо и вниз страницы (<span class="tlid-translation translation" lang="ru"><span title="">во всяком случае,</span></span> для языков, направленных слева на право).</p> + +<p>У веб-страниц также имеется z-ось: воображаемая линия, которая направляется от поверхности вашего экрана к вашему лицу (<span class="tlid-translation translation" lang="ru"><span title="">или что еще вам нравится иметь перед экраном). </span></span>Значения {{cssxref("z-index")}} влияют на то где позиционируемый элемент располагается на этой оси; положительные значения перемещают их выше по наложению, а отрицательные значения перемещают их ниже по наложению. По умолчанию все позиционируемые элементы имеют <code>z-index</code> <code>auto</code>, что фактически равно 0.</p> + +<p>Для того чтобы изменить порядок наложения, попробуйте объявить для вашего <code>p:nth-of-type(1)</code> правила:</p> + +<pre class="brush: css notranslate">z-index: 1;</pre> + +<p>Теперь вы должны видеть законченный пример, с параграфом лаймового цвета сверху:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>z-index</h1> + +<p>I am a basic block level element. My adjacent block level elements sit on new lines below me.</p> + +<p class="positioned">Now I'm absolutely positioned relative to the <code>&lt;body&gt;</code> element, not the <code>&lt;html&gt;</code> element!</p> + +<p>We are separated by our margins. Because of margin collapsing, we are separated by the width of one of our margins, not both.</p> + +<p>inline elements <span>like this one</span> and <span>this one</span> sit on the same line as one another, and adjacent text nodes, if there is space on the same line. Overflowing inline elements <span>wrap onto a new line if possible — like this one containing text</span>, or just go on to a new line if not, much like this image will do: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; + position: relative; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +.positioned { + position: absolute; + background: yellow; + top: 30px; + left: 30px; +} + +p:nth-of-type(1) { + position: absolute; + background: lime; + top: 10px; + right: 30px; + z-index: 1; +} +</pre> +</div> + +<p>{{ EmbedLiveSample('Введение_в_z-index', '100%', 400) }}</p> + +<p>Обратите внимание что <code>z-index</code> принимает значения индекса только без единиц измерения; вы не можете задавать значения, что хотите, чтобы какой-то элемент был на 23 пикселя выше по z-оси — это так не работает. Более высокие значения будут располагаться над меньшими значениями и от вас зависит какие значения вы используете. Используя 2 и 3, вы получите тот же эффект что и 300 и 40000.</p> + +<div class="note"> +<p><strong>Примечание</strong>: вы можете посмотреть живой пример на этом этапе на <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/5_z-index.html">5_z-index.html</a></code> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/5_z-index.html">см. исходный код</a>).</p> +</div> + +<h3 id="Фиксированное_позиционированиее">Фиксированное позиционированиее</h3> + +<p>А теперь давайте посмотрим на фиксированное позиционирование. Оно работает точно также как и абсолютное позиционирование, одним ключевым отличием: в то время как абсолютное позиционирование фиксирует элемент в месте относительно его ближайшего позиционированного предка (исходный содержащий блок если нет иного), <strong>фиксированное позиционирование </strong><em>обычно </em>фиксирует элемент в месте относительно <span class="tlid-translation translation" lang="ru"><span title="">видимой части области просмотра</span></span>, <span class="tlid-translation translation" lang="ru"><span title="">кроме случаев, когда один из его потомков</span></span> является фиксированным блоком <span class="tlid-translation translation" lang="ru"><span title="">из-за того, что его</span></span> <a href="/en-US/docs/Web/CSS/transform">свойству transform </a><span class="tlid-translation translation" lang="ru"><span title="">отличается от none. </span></span>Это значит, что вы можете создать <span class="tlid-translation translation" lang="ru"><span title="">элементы пользовательского интерфейса, которые зафиксированы на месте, </span></span> <span class="tlid-translation translation" lang="ru"><span title="">как постоянные меню навигации,</span></span> которые всегда видимы вне зависимости от того сколько прокручивается страница.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Давайте составим простой пример, чтобы показать, что мы имеем в виду. Во-первых, удалите существующие правила </span></span><code>p:nth-of-type(1)</code> и <code>.positioned</code> из вашего CSS.</p> + +<p>А теперь, обновите правило <code>body</code> удалив объявление <code>position: relative;</code> и добавьте фиксированную высоту как тут:</p> + +<pre class="brush: css notranslate">body { + width: 500px; + height: 1400px; + margin: 0 auto; +}</pre> + +<p>Теперь мы собираемся дать элементу {{htmlelement("h1")}} <code>position: fixed;</code>, а также заставить его располагаться на верху окна просмотра. Добавьте следующее правило в ваш CSS:</p> + +<pre class="brush: css notranslate">h1 { + position: fixed; + top: 0; + width: 500px; + margin-top: 0; + background: white; + padding: 10px; +}</pre> + +<p><code>top: 0;</code> необходим чтобы приклеить его к верху экрана. мы дали заголовку ту же ширину что и колонкам с контентом и затем даем ему белый фон и немного padding и margin, чтобы контент не был видимым под ним.</p> + +<p>Если вы сохраните и обновите сейчас, вы увидите маленький забавный эффект, <span class="tlid-translation translation" lang="ru"><span title="">при котором заголовок останется неизменным, а содержимое будет прокручиваться вверх и исчезать под ним.</span></span> Но мы можем улучшить это — в данный момент некоторый контент начинается под заголовком. Это из-за того, что позиционируемый заголовок больше не появляется в потоке документа, поэтому остальное содержимое поднимается наверх. Нам надо сдвинуть все это немного вниз; мы можем сделать это установив немного верхнего margin к первому параграфу. Добавьте его сейчас:</p> + +<pre class="brush: css notranslate">p:nth-of-type(1) { + margin-top: 60px; +}</pre> + +<p>Теверь вы должны видеть законченный пример:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Fixed positioning</h1> + +<p>I am a basic block level element. My adjacent block level elements sit on new lines below me.</p> + +<p class="positioned">I'm not positioned any more...</p> + +<p>We are separated by our margins. Because of margin collapsing, we are separated by the width of one of our margins, not both.</p> + +<p>inline elements <span>like this one</span> and <span>this one</span> sit on the same line as one another, and adjacent text nodes, if there is space on the same line. Overflowing inline elements <span>wrap onto a new line if possible — like this one containing text</span>, or just go on to a new line if not, much like this image will do: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css notranslate">body { + width: 500px; + height: 1400px; + margin: 0 auto; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +h1 { + position: fixed; + top: 0px; + width: 500px; + background: white; + padding: 10px; +} + +p:nth-of-type(1) { + margin-top: 60px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Фиксированное_позиционированиее', '100%', 400) }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: вы можете посмотреть живой пример на этом этапе на <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/6_fixed-positioning.html">6_fixed-positioning.html</a></code> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/6_fixed-positioning.html">см. исходный код</a>).</p> +</div> + +<h3 id="position_sticky">position: sticky</h3> + +<p>Доступно другое значение позиции называемое <code>position: sticky</code>, которое несколько новее чем другие. <span class="tlid-translation translation" lang="ru"><span title="">По сути, это гибрид относительной и фиксированной позиции, который позволяет позиционируемому элементу вести себя как будто он относительно позиционирован, до тех пор пока он не будет прокручен до определенной пороговой точки (напрмер, 10px от вершины окна просмотра), после чего он становится фиксированным. </span></span> <span class="tlid-translation translation" lang="ru"><span title="">Это можно использовать, например, чтобы заставить панель навигации прокручиваться вместе со страницей до определенной точки, а затем задерживать в верхней части страницы.</span></span></p> + +<div id="Sticky_1"> +<div class="hidden"> +<h6 id="Sticky_positioning_example">Sticky positioning example</h6> + +<pre class="brush: html notranslate"><h1>Sticky positioning</h1> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<div class="positioned">Sticky</div> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> </pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; +} + +.positioned { + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + padding: 10px; + margin: 10px; + border-radius: 5px; +}</pre> +</div> + +<pre class="brush: css notranslate">.positioned { + position: sticky; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Sticky_1', '100%', 200) }}</p> + +<p>Интересное и общее использование <code>position: sticky</code> <span class="tlid-translation translation" lang="ru"><span title="">заключается </span></span>в создании индексных страниц <span class="tlid-translation translation" lang="ru"><span title="">с прокруткой, где разные заголовки липнут к верху страницы</span></span>, когда они достигают его. Разметка такого примера может выглядеть так:</p> + +<pre class="brush: html notranslate"><h1>Sticky positioning</h1> + +<dl> + <dt>A</dt> + <dd>Apple</dd> + <dd>Ant</dd> + <dd>Altimeter</dd> + <dd>Airplane</dd> + <dt>B</dt> + <dd>Bird</dd> + <dd>Buzzard</dd> + <dd>Bee</dd> + <dd>Banana</dd> + <dd>Beanstalk</dd> + <dt>C</dt> + <dd>Calculator</dd> + <dd>Cane</dd> + <dd>Camera</dd> + <dd>Camel</dd> + <dt>D</dt> + <dd>Duck</dd> + <dd>Dime</dd> + <dd>Dipstick</dd> + <dd>Drone</dd> + <dt>E</dt> + <dd>Egg</dd> + <dd>Elephant</dd> + <dd>Egret</dd> +</dl> +</pre> + +<p>CSS может выглядеть как показано ниже. В нормальном потоке элементы {{htmlelement("dt")}} будут прокручиваться вместе с контентом. Когда мы добавляем <code>position: sticky</code> к элементу {{htmlelement("dt")}}, вместе со значением {{cssxref("top")}} 0, поддерживающие браузеры будут приклеивать заголовки к вершине окна просмотра когда они будут достигать той позиции. каждый последующий заголовок будет затем заменять предыдущий при его прокрутке вверх к той позиции.</p> + +<pre class="brush: css notranslate">dt { + background-color: black; + color: white; + padding: 10px; + position: sticky; + top: 0; + left: 0; + margin: 1em 0; +} +</pre> + +<div id="Sticky_2"> +<div class="hidden"> +<pre class="brush: css notranslate">body { + width: 500px; + height: 1400px; + margin: 0 auto; +} + +dt { + background-color: black; + color: white; + padding: 10px; + position: sticky; + top: 0; + left: 0; + margin: 1em 0; +} +</pre> + +<pre class="brush: html notranslate"><h1>Sticky positioning</h1> + +<dl> + <dt>A</dt> + <dd>Apple</dd> + <dd>Ant</dd> + <dd>Altimeter</dd> + <dd>Airplane</dd> + <dt>B</dt> + <dd>Bird</dd> + <dd>Buzzard</dd> + <dd>Bee</dd> + <dd>Banana</dd> + <dd>Beanstalk</dd> + <dt>C</dt> + <dd>Calculator</dd> + <dd>Cane</dd> + <dd>Camera</dd> + <dd>Camel</dd> + <dt>D</dt> + <dd>Duck</dd> + <dd>Dime</dd> + <dd>Dipstick</dd> + <dd>Drone</dd> + <dt>E</dt> + <dd>Egg</dd> + <dd>Elephant</dd> + <dd>Egret</dd> +</dl> +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Sticky_2', '100%', 200) }}</p> + +<p>Липкие элементы являются "липкими" относительно ближайшего предка с "прокручивающимся механизмом", который определяется свойством <a href="/en-US/docs/Web/CSS/position">позиции</a> его предка.</p> + +<div class="note"> +<p><strong>Примечание</strong>: вы можете посмотреть живой пример на этом этапе на <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/7_sticky-positioning.html">7_sticky-positioning.html</a></code> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/7_sticky-positioning.html">см. исходный код</a>).</p> +</div> + +<h2 id="Проверь_свои_навыки!">Проверь свои навыки!</h2> + +<p>Вы достигли конца этой статьи, но помните ли вы самую важную информацию? Вы можете найти дальнейшую проверку что вы усвоили эту информацию прежде чем, отправитесь дальше — см. <a href="/en-US/docs/Learn/CSS/CSS_layout/Position_skills">Проверьте свои навыки: Позиционирование</a>.</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Я уверен, что вы повеселились с основами позиционирования; хотя это не является методом, который вы бы использовали для целого макета, все же как вы видите, существует много задач, подходящих для него.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Floats", "Learn/CSS/CSS_layout/Multiple-column_Layout", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li>Справка свойства {{cssxref("position")}}.</li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Practical_positioning_examples">Примеры практического позиционирования</a>, для дополнительных полезных идей</li> +</ul> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">Введение в CSS макет</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow">Нормальный поток</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Grid</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Позиционирование</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Макет с несколькими столбцами</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Responsive_Design">Отзывчивый дизайн</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Media_queries">Руководство новичка в media queries</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">Устаревшие методы макетов</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">Поддержка старых браузеров</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">Базовая оценка понимания макета</a></li> +</ul> diff --git a/files/ru/learn/css/css_layout/practical_positioning_examples/index.html b/files/ru/learn/css/css_layout/practical_positioning_examples/index.html new file mode 100644 index 0000000000..1dbbc6012b --- /dev/null +++ b/files/ru/learn/css/css_layout/practical_positioning_examples/index.html @@ -0,0 +1,408 @@ +--- +title: Practical positioning examples +slug: Learn/CSS/CSS_layout/Practical_positioning_examples +translation_of: Learn/CSS/CSS_layout/Practical_positioning_examples +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">Основы позиционирования, приведенные в последней статье, мы теперь рассмотрим, как создать некоторые примеры реального мира, чтобы проиллюстрировать, какие вещи вы можете сделать с позиционированием.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Основы HTML (уроки <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), и идея о том, как работает CSS (уроки <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Introduction to CSS</a>.)</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Чтобы получить представление о практичности позиционирования</td> + </tr> + </tbody> +</table> + +<h2 id="Информационный_блок_с_вкладками">Информационный блок с вкладками</h2> + +<p>Первый пример, который мы рассмотрим, - это классический информационный блок с вкладками - очень распространенная функция, используемая, когда вы хотите упаковать много информации в небольшую область. Сюда входят информационные приложения, такие как стратегии / военные игры, мобильные версии веб-сайтов, где экран и пространство ограничены и необходимы компактные информационные окна, где вы можете сделать много информации, не заполняя весь пользовательский интерфейс. Наш простой пример будет выглядеть так, как только мы закончим:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13368/tabbed-info-box.png" style="display: block; height: 400px; margin: 0px auto; width: 450px;"></p> + +<div class="note"> +<p><strong>Примечание: </strong>Вы можете увидеть, что готовый пример работает в прямом эфире <a href="http://mdn.github.io/learning-area/css/css-layout/practical-positioning-examples/info-box.html">info-box.html</a> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/practical-positioning-examples/info-box.html">source code</a>). Проверьте его, чтобы понять, что вы будете строить в этом разделе статьи.</p> +</div> + +<p>Возможно, вы думаете: «Почему бы просто не создавать отдельные вкладки в виде отдельных веб-страниц и просто иметь вкладки, переходящие на отдельные страницы, чтобы создать эффект?» Этот код был бы проще, да, но тогда каждый отдельный «просмотр страницы» на самом деле был бы вновь загруженной веб-страницей, что затрудняло бы сохранение информации между представлениями и интеграцию этой функции в более крупный дизайн пользовательского интерфейса. Кроме того, так называемые «одностраничные приложения» становятся очень популярными - особенно для мобильных веб-интерфейсов - потому что все, что обслуживается как один файл, сокращает количество HTTP-запросов, необходимых для просмотра всего содержимого, тем самым повышая производительность.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Некоторые веб-разработчики занимаются еще более быстрыми темпами, имея только одну страницу информации, загружаемую сразу и динамическое изменение информации, отображаемой с помощью функции JavaScript, такой как <a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a>. На этом этапе вашего обучения мы хотим сохранить все как можно проще. Впоследствии есть JavaScript, но только немного.</p> +</div> + +<p>Для начала мы хотели бы, чтобы вы создали локальную копию исходного HTML-файла — <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/practical-positioning-examples/info-box-start.html">info-box-start.html</a>. Сохраните это где вам удобно на локальном компьютере и откройте его в текстовом редакторе. Давайте посмотрим на HTML, содержащийся в теле:</p> + +<pre class="brush: html"><section class="info-box"> + <ul> + <li><a href="#" class="active">Tab 1</a></li> + <li><a href="#">Tab 2</a></li> + <li><a href="#">Tab 3</a></li> + </ul> + <div class="panels"> + <article class="active-panel"> + <h2>The first tab</h2> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque turpis nibh, porttitor nec venenatis eu, pulvinar in augue. Vestibulum et orci scelerisque, vulputate tellus quis, lobortis dui. Vivamus varius libero at ipsum mattis efficitur ut nec nisl. Nullam eget tincidunt metus. Donec ultrices, urna maximus consequat aliquet, dui neque eleifend lorem, a auctor libero turpis at sem. Aliquam ut porttitor urna. Nulla facilisi.</p> + </article> + <article> + <h2>The second tab</h2> + + <p>This tab hasn't got any Lorem Ipsum in it. But the content isn't very exciting all the same.</p> + </article> + <article> + <h2>The third tab</h2> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque turpis nibh, porttitor nec venenatis eu, pulvinar in augue. And now an ordered list: how exciting!</p> + + <ol> + <li>dui neque eleifend lorem, a auctor libero turpis at sem.</li> + <li>Aliquam ut porttitor urna.</li> + <li>Nulla facilisi</li> + </ol> + </article> + </div> +</section></pre> + +<p>Итак, у нас есть элемент {{htmlelement ("section")}} с <code>классом</code> <code>info-box</code>, который содержит {{htmlelement ("ul")}} и {{htmlelement ("div")}}. Неупорядоченный список содержит три элемента списка со ссылками внутри, которые станут фактическими вкладками для отображения наших панелей контента. <code>div</code> содержит три элемента {{htmlelement ("article")}}, которые будут составлять панели содержимого, соответствующие каждой вкладке. Каждая панель содержит некоторый образец контента.</p> + +<p>Идея здесь заключается в том, что мы будем стилизовать вкладки, чтобы они выглядели как стандартное меню горизонтальной навигации и нарисуем панели, чтобы они сидели друг над другом, используя абсолютное позиционирование. Мы также предоставим вам немного JavaScript для включения на вашу страницу, чтобы отобразить соответствующую панель при нажатии вкладки и вы создатите саму вкладку. Вам не нужно будет понимать сам JavaScript на данном этапе, но вы должны подумать об изучении базового <a href="/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript</a> как можно скорее - чем сложнее ваши функции пользовательского интерфейса, тем больше вероятность того, что вам понадобится JavaScript для реализации желаемую функциональность.</p> + +<h3 id="Общая_настройка">Общая настройка</h3> + +<p>Для начала добавьте следующее между вашим открытием и закрытием {{HTMLElement ("style")}} tags:</p> + +<pre class="brush: css">html { + font-family: sans-serif; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; +}</pre> + +<p>Это всего лишь общая настройка для установки шрифта sans-serif на нашей странице, используйте поле <code>border-box </code>{{cssxref ("box-sizing")}} и избавьтесь от стандартного {{htmlelement ("body") }} поля.</p> + +<p>Затем добавьте следующее ниже вашего предыдущего CSS:</p> + +<pre class="brush: css">.info-box { + width: 450px; + height: 400px; + margin: 0 auto; +}</pre> + +<p>Это задает конкретную ширину и высоту содержимого и центрирует его на экране с использованием старого <code>margin: 0 auto </code>трюкa. Раньше в курсе мы советовали не устанавливать фиксированную высоту на контейнеры содержимого, если это вообще возможно; это нормально в этом случае, потому что у нас есть фиксированный контент на наших вкладках. Это также выглядит немного раздражающим, чтобы иметь разные вкладки на разных высотах.</p> + +<h3 id="Укладка_наших_вкладок">Укладка наших вкладок</h3> + +<p>Теперь мы хотим, чтобы стиль вкладок выглядел как вкладки - в основном это горизонтальное меню навигации, но вместо того, чтобы загружать разные веб-страницы, когда они нажимаются, как мы видели ранее в курсе, они вызывают отображение разных панелей на той же странице. Сначала добавьте следующее правило внизу CSS, чтобы удалить по умолчанию {{cssxref ("padding-left")}} и {{cssxref ("margin-top")}} из неупорядоченного списка:</p> + +<pre class="brush: css">.info-box ul { + padding-left: 0; + margin-top: 0; +}</pre> + +<div class="note"> +<p><strong>Заметка</strong>: Мы используем селектор-потомки с полем <code>.info-box</code> в начале цепочки в этом примере - это значит, что мы можем вставить эту функцию на страницу с другим содержимым, уже на ней, не опасаясь вмешиваться в стили, применяемые к другим частям страницы.</p> +</div> + +<p>Затем мы нарисуем горизонтальные вкладки - все элементы списка будут перемещены влево, чтобы заставить их сидеть в одной строке вместе, их {{cssxref ("list-style-type")}} имеет значение <code>none</code>, чтобы избавиться от пули и их {{cssxref ("width")}} установлены на <code>150px</code>, чтобы они удобно располагались в информационном окне. Элементы {{htmlelement ("a")}} имеют {{cssxref ("display")}} встроенный блок, поэтому они будут сидеть в строке, но все же быть стильными и соответствующим образом оформлены для кнопок вкладок, используя множество других свойств.</p> + +<p>Добавьте следующий CSS:</p> + +<pre class="brush: css">.info-box li { + float: left; + list-style-type: none; + width: 150px; +} + +.info-box li a { + display: inline-block; + text-decoration: none; + width: 100%; + line-height: 3; + background-color: red; + color: black; + text-align: center; +}</pre> + +<p>Наконец, для этого раздела мы установим некоторые стили в состояниях ссылок. Во-первых, мы настроим <code>:focus</code> и <code>:hover</code> состояния вкладок, чтобы выглядеть по-другому, когда они сфокусированы / зависают, предоставляя пользователям некоторую визуальную обратную связь. Во-вторых, мы установим правило, которое ставит один и тот же стиль на одной из вкладок, когда на нем присутствует <code>class</code> of <code>active</code>. Мы установим это с помощью JavaScript при нажатии на вкладку. Поместите следующий CSS ниже других стилей:</p> + +<pre class="brush: css">.info-box li a:focus, .info-box li a:hover { + background-color: #a60000; + color: white; +} + +.info-box li a.active { + background-color: #a60000; + color: white; +}</pre> + +<h3 id="Styling_the_panels">Styling the panels</h3> + +<p>The next job is to style our panels. Let's get going!</p> + +<p>First, of all, add the following rule to style the <code>.panels</code> {{htmlelement("div")}} container. Here we simply set a fixed {{cssxref("height")}} to make sure the panels fit snugly inside the info-box, {{cssxref("position")}} <code>relative</code> to set the {{htmlelement("div")}} as the positioning context, so you can then place positioned child elements relative to it and not the {{htmlelement("html")}} element, and finally we {{cssxref("clear")}} the float set in the CSS above so that it doesn't interfere with the remainder of the layout.</p> + +<pre class="brush: css">.info-box .panels { + height: 352px; + position: relative; + clear: both; +}</pre> + +<p>Finally for this section, we will style the individual {{htmlelement("article")}} elements that comprise our panels. The first rule we'll add will absolutely {{cssxref("position")}} the panels, and make them all sit flush to the {{cssxref("top")}} and {{cssxref("left")}} of their {{htmlelement("div")}} container — this part is absolutely key to this whole layout feature, as it makes the panels sit on top of one another. The rule also gives the panels the same set height as the container, and gives the content some padding, a text {{cssxref("color")}}, and a {{cssxref("background-color")}}.</p> + +<p>The second rule we'll add here makes it so that a panel with a <code>class</code> of <code>active-panel</code> set on it will have a {{cssxref("z-index")}} of 1 applied to it, which will make it sit above the other panels (positioned elements have a <code>z-index</code> of 0 by default, which would put them below). Again, we'll add this class using JavaScript at the appropriate time.</p> + +<pre class="brush: css">.info-box article { + position: absolute; + top: 0; + left: 0; + height: 352px; + padding: 10px; + color: white; + background-color: #a60000; +} + +.info-box .active-panel { + z-index: 1; +}</pre> + +<h3 id="Adding_our_JavaScript">Adding our JavaScript</h3> + +<p>The final step to getting this feature working is to add some JavaScript. Put the following block of code, exactly as written in between your opening and closing {{htmlelement("script")}} tags (you'll find these below the HTML content):</p> + +<pre>var tabs = document.querySelectorAll('.info-box li a'); +var panels = document.querySelectorAll('.info-box article'); + +for(i = 0; i < tabs.length; i++) { + var tab = tabs[i]; + setTabHandler(tab, i); +} + +function setTabHandler(tab, tabPos) { + tab.onclick = function() { + for(i = 0; i < tabs.length; i++) { + tabs[i].className = ''; + } + + tab.className = 'active'; + + for(i = 0; i < panels.length; i++) { + panels[i].className = ''; + } + + panels[tabPos].className = 'active-panel'; + } +}</pre> + +<p>This code does the following:</p> + +<ul> + <li>First we save a reference to all the tabs and all the panels in two variables called <code>tabs</code> and <code>panels</code>, so we can easily do things to them later on.</li> + <li>Then we use a <code>for</code> loop to cycle through all the tabs and run a function called <code>setTabHandler()</code> on each one, which sets up the functionality that should occur when each one is clicked on. When run, the function is passed a reference to the particular tab it is being run for, and an index number <code>i</code> that indentifies the tab's position in the <code>tabs</code> array.</li> + <li>In the <code>setTabHandler()</code> function, the tab has an <code>onclick</code> event handler set on it, so that when the tab is clicked, the following occurs: + <ul> + <li>A <code>for</code> loop is used to cycle through all the tabs and remove any classes that are present on them.</li> + <li>A <code>class</code> of <code>active</code> is set on the tab that was clicked on — remember from earlier that this class has an associated rule in the CSS that sets the same {{cssxref("color")}} and {{cssxref("background-color")}} on the tab as the panels are styled with.</li> + <li>A <code>for</code> loop is used to cycle through all the panels and remove any classes that are present on them.</li> + <li>A class of <code>active-panel</code> is set on the panel that corresponds to the tab that was clicked on — remember from earlier that this class has an associated rule in the CSS that sets its {{cssxref("z-index")}} to 1, making it appear over the top of the other panels.</li> + </ul> + </li> +</ul> + +<p>That's it for the first example. Keep your code open, as we'll be adding to it in the second one.</p> + +<h2 id="A_fixed_position_tabbed_info-box">A fixed position tabbed info-box</h2> + +<p>In our second example, we will take our first example — our info-box — and add it into the context of a full web page. But not only that — we'll give it fixed position so that it stays in the same position in the browser window. When the main content scrolls, the info-box will stay in the same position on the screen. Our finished example will look like this:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13364/fixed-info-box.png" style="border-style: solid; border-width: 1px; display: block; height: 585px; margin: 0px auto; width: 1118px;"></p> + +<div class="note"> +<p><strong>Note</strong>: You can see the finished example running live at <a href="http://mdn.github.io/learning-area/css/css-layout/practical-positioning-examples/fixed-info-box.html">fixed-info-box.html</a> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/practical-positioning-examples/fixed-info-box.html">source code</a>). Check it out to get an idea of what you will be building in this section of the article.</p> +</div> + +<p>As a starting point, you can use your completed example from the first section of the article, or make a local copy of <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/practical-positioning-examples/info-box.html">info-box.html</a> from our Github repo.</p> + +<h3 id="HTML_additions">HTML additions</h3> + +<p>First of all, we need some additional HTML to represent the web site main content. Add the following {{htmlelement("section")}} just below your opening {{htmlelement("body")}} tag, just before the existing section:</p> + +<pre class="brush: html"><section class="fake-content"> + <h1>Fake content</h1> + <p>This is fake content. Your main web page contents would probably go here.</p> + <p>This is fake content. Your main web page contents would probably go here.</p> + <p>This is fake content. Your main web page contents would probably go here.</p> + <p>This is fake content. Your main web page contents would probably go here.</p> + <p>This is fake content. Your main web page contents would probably go here.</p> + <p>This is fake content. Your main web page contents would probably go here.</p> + <p>This is fake content. Your main web page contents would probably go here.</p> + <p>This is fake content. Your main web page contents would probably go here.</p> +</section></pre> + +<div class="note"> +<p><strong>Note</strong>: You can feel free to change the fake content for some real content if you like.</p> +</div> + +<h3 id="Changes_to_the_existing_CSS">Changes to the existing CSS</h3> + +<p>Next we need to make some small changes to the existing CSS, to get the info-box placed and positioned. Change your <code>.info-box</code> rule to get rid of <code>margin: 0 auto;</code> (we no longer want the info-box centered), add {{cssxref("position")}}<code>: fixed;</code>, and stick it to the {{cssxref("top")}} of the browser viewport.</p> + +<p>It should now look like this:</p> + +<pre class="brush: css">.info-box { + width: 450px; + height: 400px; + position: fixed; + top: 0; +}</pre> + +<h3 id="Styling_the_main_content">Styling the main content</h3> + +<p>The only thing left for this example is to provide the main content with some styling. Add the following rule underneath the rest of your CSS:</p> + +<pre class="brush: css">.fake-content { + background-color: #a60000; + color: white; + padding: 10px; + height: 2000px; + margin-left: 470px; +}</pre> + +<p>To start with, we give the content the same {{cssxref("background-color")}}, {{cssxref("color")}}, and {{cssxref("padding")}} as the info-box panels. We then give it a large {{cssxref("margin-left")}} to move it over to the right, making space for the info-box to sit in, so it is not overlapping anything else.</p> + +<p>This marks the end of the second example; we hope you'll find the third just as interesting.</p> + +<h2 id="A_sliding_hidden_panel">A sliding hidden panel</h2> + +<p>The final example we'll present here is a panel that slides on and off the screen at the press of an icon — as mentioned earlier, this is popular for situations like mobile layouts, where the available screen spaces is small, so you don't want to use up most of it by showing a menu or info panel instead of the useful content.</p> + +<p>Our finished example will look like this:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13366/hidden-sliding-panel.png" style="border-style: solid; border-width: 1px; display: block; height: 521px; margin: 0px auto; width: 950px;"></p> + +<div class="note"> +<p><strong>Note</strong>: You can see the finished example running live at <a href="http://mdn.github.io/learning-area/css/css-layout/practical-positioning-examples/hidden-info-panel.html">hidden-info-panel.html</a> (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/practical-positioning-examples/hidden-info-panel.html">source code</a>). Check it out to get an idea of what you will be building in this section of the article.</p> +</div> + +<p>As a starting point, make a local copy of <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/practical-positioning-examples/hidden-info-panel-start.html">hidden-info-panel-start.html</a> from our Github repo. This doesn't follow on from the previous example, so a fresh start file is required. Let's have a look at the HTML in the file:</p> + +<pre class="brush: css"><label for="toggle">❔</label> +<input type="checkbox" id="toggle"> +<aside> + + ... + +</aside></pre> + +<p>To start with here we've got a {{htmlelement("label")}} element and an {{htmlelement("input")}} element — <code><label></code> elements are normally used to associate a text label with a form element for accessibility purposes (allowing a screen user to see what description goes with what form element). Here it is associated with the <code><input></code> checkbox using the <code>for</code> and <code>id</code> attributes.</p> + +<div class="note"> +<p><strong>Note</strong>: We've put a special question mark character into our HTML to act as our info icon — this represents the button that will be pressed to show/hide the panel.</p> +</div> + +<p>Here we are going to use these elements for a slightly different purpose — another useful side effect of <code><label></code> elements is that you can click a checkbox's label to check the checkbox, as well as just the checkbox itself. This has led to the well-known <a href="https://css-tricks.com/the-checkbox-hack/">checkbox hack</a>, which provides a JavaScript-free way of controlling an element by toggling a button. The element we'll be controlling is the {{htmlelement("aside")}} element that follows the other two (we've left its contents out of the above code listing for brevity).</p> + +<p>In the below sections we'll explain how this all works.</p> + +<h3 id="Styling_the_form_elements">Styling the form elements</h3> + +<p>First let's deal with the form elements — add the following CSS in between your {{htmlelement("style")}} tags:</p> + +<pre class="brush: css">label[for="toggle"] { + font-size: 3rem; + position: absolute; + top: 4px; + right: 5px; + z-index: 1; + cursor: pointer; +} + +input[type="checkbox"] { + position: absolute; + top: -100px; +}</pre> + +<p>The first rule styles the <code><label></code>; here we've:</p> + +<ul> + <li>Set a large {{cssxref("font-size")}} to make the icon nice and big.</li> + <li>Set {{cssxref("position")}} <code>absolute</code> on it, and used {{cssxref("top")}} and {{cssxref("right")}} to position it nicely in the top-right corner.</li> + <li>Set a {{cssxref("z-index")}} of 1 on it — this is so that when the info panel is styled and shown, it doesn't cover up the icon; instead the icon will sit on top of it so it can be pressed again to hide the info pane.</li> + <li>Used the {{cssxref("cursor")}} property to change the mouse cursor when it is hovering over the icon to a hand pointer (like the one you see when links are hovered over), as an extra visual clue to users that the icon does something interesting.</li> +</ul> + +<p>The second rule sets {{cssxref("position")}} <code>absolute</code> on the actual checkbox <code><input></code> element, and hides it off the top of the screen. We don't actually want to see this on our UI.</p> + +<h3 id="Styling_the_panel">Styling the panel</h3> + +<p>Now it's time to style the actual sliding panel itself. Add the following rule to the bottom of your CSS:</p> + +<pre class="brush: css">aside { + background-color: #a60000; + color: white; + + width: 340px; + height: 100%; + padding: 0 20px; + + position: fixed; + top: 0; + right: -370px; + + transition: 0.6s all; +}</pre> + +<p>There's a lot going on here — let's discuss it bit by bit:</p> + +<ul> + <li>First, we set some simple {{cssxref("background-color")}} and {{cssxref("color")}} on the info box.</li> + <li>Next, we set a fixed {{cssxref("width")}} on the panel, and make its {{cssxref("height")}} the entire height of the browser viewport.</li> + <li>We also include some horizontal {{cssxref("padding")}} to space it out a bit.</li> + <li>Next we set {{cssxref("position")}}<code>: fixed;</code> on the panel so it will always appear in the same place, even if the page has content to scroll. We glue it to the {{cssxref("top")}} of the viewport, and set it so that by default it is offscreen to the {{cssxref("right")}}.</li> + <li>Finally, we set a {{cssxref("transition")}} on the element. Transitions are an interesting feature that allow you to make changes between states happen smoothly, rather than just going "on", "off" abruptly. In this case we are intending to make the panel slide smoothly onscreen when the checkbox is checked. (Or to put it another way, when the question mark icon is clicked — remember, clicking the <code><label></code> will check the associated checkbox! We told you it was a hack.) You will learn a lot more about...</li> +</ul> + +<h3 id="Setting_the_checked_state">Setting the checked state</h3> + +<p>There is one final bit of CSS to add — put the following at the bottom of your CSS:</p> + +<pre class="brush: css">input[type=checkbox]:checked + aside { + right: 0px; +}</pre> + +<p>The selector is pretty complex here — we are selecting the <code><aside></code> element adjacent to the <code><input></code> element, but only when it is checked (note the use of the {{cssxref(":checked")}} pseudo-class to achieve this). When this is the case, we are setting the {{cssxref("right")}} property of the <code><aside></code> to <code>0px</code>, which causes the panel to appear on the screen again (smoothly due to the transition). Clicking the label again unchecks the checkbox, which hides the panel again.</p> + +<p>So there you have it — a rather clever JavaScript-free way to create a toggling button effect. This will work in IE9 and above (the smooth transition will work in IE10 and above.) This effect does have some concerns — this is a bit of an abuse of form elements, as they weren't intended for this purpose. In addition, the effect is not great in terms of accessibility; the label is not focusable by default, and the non-semantic use of the form elements could cause issues with screen readers. JavaScript and a link or button might be more appropriate, but it is still fun to experiment with.</p> + +<h2 id="Summary">Summary</h2> + +<p>So that rounds off our look at positioning — by now, you should have an idea of how the basic mechanics work, as well as understanding how to start applying these to building some interesting UI features. Don't worry if you didn't get this all immediately — positioning is a fairly advanced topic, and you can always work through the articles again to aid your understanding. The next subject we'll turn to is Flexbox.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">Introduction to CSS layout</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Positioning</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Practical_positioning_examples">Practical positioning examples</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Grids</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/css/css_layout/макет_с_несколькими_столбцами/index.html b/files/ru/learn/css/css_layout/макет_с_несколькими_столбцами/index.html new file mode 100644 index 0000000000..9ba48bbbef --- /dev/null +++ b/files/ru/learn/css/css_layout/макет_с_несколькими_столбцами/index.html @@ -0,0 +1,468 @@ +--- +title: Макет с несколькими столбцами +slug: Learn/CSS/CSS_layout/Макет_с_несколькими_столбцами +translation_of: Learn/CSS/CSS_layout/Multiple-column_Layout +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout/Responsive_Design", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">Спецификация макет с несколькими столбцами дает вам метод верстки контента по столбцам, точно также как вы можете видеть в газете. Эта статья объясняет, как использовать эту функцию.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Основы HTML (изучите <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), идея о том как работает CSS (изучите <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a>.)</p> + </td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td> + <p>Изучить как создавать макет с неколькими столбцами на веб-страницах, такой как вы модете найти в газете.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Базовый_пример">Базовый пример</h2> + +<p>Сейчас мы будем изучать как использовать макет с несколькими столбцами, часто называемый <em>multicol. </em>Вы можете следовать за нами <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/multicol/0-starting-point.html">скачав файл отправной точки multicol</a> и добавлять CSS в соответствующие места. В конце раздела вы можете посмотреть живой пример того, как конечный код должен выглядеть.</p> + +<p>Наша отправная точка содержит немного очень простого HTML; обертака с классом <code>container</code> внутри которого имеется заголовок и несколько параграфов.</p> + +<p>{{htmlelement("div")}} с классом контейнер станет нашим multicol контейнером. Мы включаем multicol используя одно из двух свойств {{cssxref("column-count")}} или {{cssxref("column-width")}}. Какое значение вы дадите свойству <code>column-count</code> столько столбцов он и создаст, поэтому если вы добавите следующий CSS в ваши стили и перезагрузите страницу, то получите три столбца:</p> + +<pre class="brush: css notranslate">.container { + column-count: 3; +} +</pre> + +<p>Колонки, которые вы создаете имеют гибкую ширину — браузер решает какое пространство назначить каждому столбцу.</p> + +<div id="Multicol_1"> +<div class="hidden"> +<h6 id="column-count_example">column-count example</h6> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} + </pre> +</div> + +<pre class="brush: html notranslate"><div class="container"> + <h1>Simple multicol example</h1> + + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. + Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. + Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse + ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit + quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique + elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit + cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis + dis parturient montes, nascetur ridiculus mus.</p> +</div> +</pre> + +<pre class="brush: css notranslate">.container { + column-count: 3; +} +</pre> +</div> + +<p>{{ EmbedLiveSample('Multicol_1', '100%', 400) }}</p> + +<p>Измените ваш CSS чтобы использовать следующий <code>column-width</code>:</p> + +<pre class="brush: css notranslate">.container { + column-width: 200px; +} +</pre> + +<p>Теперь браузер будет давать столько столбцов размером, который вы определили, сколько он сможет; любое оставшееся пространство далее делится между существующими столбцами. Это значит, что вы не получите точную ширину, которую вы задали, только если ваш контейнер <span class="tlid-translation translation" lang="ru"><span title="">не делится точно на эту ширину.</span></span></p> + +<div id="Multicol_2"> +<div class="hidden"> +<h6 id="column-width_example">column-width example</h6> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +}</pre> + +<pre class="brush: html notranslate"><div class="container"> + <h1>Simple multicol example</h1> + + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. + Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. + Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse + ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit + quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique + elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit + cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis + dis parturient montes, nascetur ridiculus mus.</p> +</div></pre> +</div> + +<pre class="brush: css notranslate">.container { + column-width: 200px; +} +</pre> +</div> + +<p>{{ EmbedLiveSample('Multicol_2', '100%', 400) }}</p> + +<h2 id="Стилизация_столбцов">Стилизация столбцов</h2> + +<p>Столбцы, созданные при помощи multicol не могут быть стилизованы по одному. Нет способа сделать один столбец больше, чем другие, или изменить фон или цвет текста одного столбца. У вас есть две возможности изменить способ отображения столбцов:</p> + +<ul> + <li>Изменение размера отступов между столбцами используя {{cssxref("column-gap")}}.</li> + <li>Добавление линейки между столбцами при помощи {{cssxref("column-rule")}}.</li> +</ul> + +<p>Используя ваш пример выше, измените размер отступа добавлением свойства <code>column-gap</code>:</p> + +<pre class="brush: css notranslate">.container { + column-width: 200px; + column-gap: 20px; +}</pre> + +<p>Вы можете поиграть с разными значениями — свойство принимает любые единицы измерения длины. Теперь добавьте линейку между столбцами при помощи <code>column-rule</code>. Таким же способом как и свойство {{cssxref("border")}} с которым вы сталкивались в предыдущих уроках, <code>column-rule</code> — это короткая запись {{cssxref("column-rule-color")}}, {{cssxref("column-rule-style")}} и {{cssxref("column-rule-width")}} и принимает те же значения что и <code>border</code>.</p> + +<pre class="brush: css notranslate">.container { + column-count: 3; + column-gap: 20px; + column-rule: 4px dotted rgb(79, 185, 227); +}</pre> + +<p>Попробуйте добавить линейки других стилей и цветов.</p> + +<div id="Multicol_3"> +<div class="hidden"> +<h6 id="Styling_the_columns">Styling the columns</h6> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} +.container { + column-count: 3; + column-gap: 20px; + column-rule: 4px dotted rgb(79, 185, 227); +}</pre> + +<pre class="brush: html notranslate"><div class="container"> + <h1>Simple multicol example</h1> + + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. + Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. + Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse + ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit + quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique + elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit + cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis + dis parturient montes, nascetur ridiculus mus.</p> +</div></pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Multicol_3', '100%', 400) }}</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Следует обратить внимание на то, что линейка не занимает никакой ширины.</span></span> Она располагается в промежутках, которые вы создали при помощи <code>column-gap</code>. Чтобы придать больше пространства <span class="tlid-translation translation" lang="ru"><span title="">по обе стороны от линейки, вам нужно увеличить размер </span></span><code>column-gap</code><span class="tlid-translation translation" lang="ru"><span title="">.</span></span></p> + +<h2 id="Свойств_column-span">Свойств column-span</h2> + +<p>Вы можете заставить элемент растянуться через все столбцы. В этом случае контент разрывается, когда сталкивается со spanning элементом и продолжается ниже, создавая новый набор блоков столбцов. Чтобы растянуть элемент через все столбцы используйте свойство {{cssxref("column-span")}} установленное на значение <code>all</code>.</p> + +<div class="blockIndicator note"> +<p>Обратите внимание что невозможно растянуть элемент через несколько столбцов. Это свойство может иметь либо значение <code>none</code> (по умолчанию) либо <code>all</code>.</p> +</div> + +<div id="Multicol_Span"> +<div class="hidden"> +<h6 id="Spanning_the_columns">Spanning the columns</h6> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} +.container { + column-count: 3; + column-gap: 20px; + column-rule: 4px dotted rgb(79, 185, 227); +} +h2 { + column-span: all; + background-color: rgb(79, 185, 227); + color: white; + padding: .5em; +} +</pre> + +<pre class="brush: html notranslate"><div class="container"> + <h1>Simple multicol example</h1> + + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. + Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. + + <h2>Spanning subhead</h2> + Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse + ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit + quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique + elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit + cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis + dis parturient montes, nascetur ridiculus mus.</p> +</div></pre> +</div> +</div> + +<p>{{ EmbedLiveSample('Multicol_Span', '100%', 400) }}</p> + +<h2 id="Столбцы_и_фрагментация">Столбцы и фрагментация</h2> + +<p>Содержимое макета нескольких столбцов является фрагментированным. <span class="tlid-translation translation" lang="ru"><span title="">По сути, он ведет себя так же, как контент в постраничных медиа </span></span>— так же, как когда вы печатаете веб-страницы. Когда вы переводите ваш контент в multicol контейнер он фрагментируется на столбцы и контент разбивается чтобы позволить этому произойти.</p> + +<p>Порой это разрывание происходит в местах, мешающих чтению. В живом примере ниже, я использовал multicol чтобы разместить несколько блоков, каждый из которых имеет заголовок и немного текста внутри. <span class="tlid-translation translation" lang="ru"><span title="">Заголовок отделяется от текста, если столбцы разделяются между ними.</span></span></p> + +<div id="Multicol_4"> +<div class="hidden"> +<h6 id="Cards_example">Cards example</h6> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} </pre> +</div> + +<pre class="brush: html notranslate"><div class="container"> + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + +</div> +</pre> + +<pre class="brush: css notranslate">.container { + column-width: 250px; + column-gap: 20px; +} + +.card { + background-color: rgb(207, 232, 220); + border: 2px solid rgb(79, 185, 227); + padding: 10px; + margin: 0 0 1em 0; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Multicol_4', '100%', 600) }}</p> + +<p>Для того чтобы управлять этим поведением мы можем использовать свойства из спецификации <a href="/en-US/docs/Web/CSS/CSS_Fragmentation">CSS Фрагментации</a>. Эта спецификация дает нам свойства для управления разрывами контента в multicol и постраничных медиа. Например, добавьте свойство {{cssxref("break-inside")}} со значением <code>avoid</code> к правилам <code>.card</code>. Это контейнер заголовка и текста и поэтому мы не хотим фрагментировать этот блок.</p> + +<p>В настоящее время также стоит добавлять старое свойство <code>page-break-inside: avoid</code> для лучшей поддержки старых браузеров.</p> + +<pre class="brush: css notranslate">.card { + break-inside: avoid; + page-break-inside: avoid; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + margin: 0 0 1em 0; +} +</pre> + +<p>Перезагрузите страницу и ваши блоки должны остаться в целости.</p> + +<div id="Multicol_5"> +<div class="hidden"> +<h6 id="Multicol_Fragmentation">Multicol Fragmentation</h6> + +<pre class="brush: css notranslate">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} </pre> + +<pre class="brush: html notranslate"><div class="container"> + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>I am the heading</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + +</div> +</pre> +</div> + +<pre class="brush: css notranslate">.container { + column-width: 250px; + column-gap: 20px; +} + +.card { + break-inside: avoid; + page-break-inside: avoid; + background-color: rgb(207, 232, 220); + border: 2px solid rgb(79, 185, 227); + padding: 10px; + margin: 0 0 1em 0; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Multicol_5', '100%', 600) }}</p> + +<h2 id="Проверь_свои_навыки!">Проверь свои навыки!</h2> + +<p>Вы достигли конца этой статьи, но помните ли вы самую важную информацию? Вы можете найти дальнейшие тесты для проверки того, что вы усвоили эту информацию прежде чем, отправитесь дальше — см. <a href="/en-US/docs/Learn/CSS/CSS_layout/Multicol_skills">Поверьте свои навыки: Макет с несколькими столбцами</a>.</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Вы теперь знаете, как использовать базовые функции макета с несколькими столбцами, еще один инструмент в вашем распоряжении при выборе метода макета для дизайна который вы строите.</p> + +<h2 id="См._также">См. также</h2> + +<ul> + <li><a href="/en-US/docs/Web/CSS/CSS_Fragmentation">CSS Фрагментация</a></li> + <li><a href="/en-US/docs/Web/CSS/CSS_Columns/Using_multi-column_layouts">Применение макета с несколькими столбцами</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout/Responsive_Design", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">Введение в CSS макет</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow">Нормальный поток</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Grid</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Позиционирование</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Макет с несколькими столбцами</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Responsive_Design">Отзывчивый дизайн</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Media_queries">Руководство новичка в media queries</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">Устаревшие методы макетов</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">Поддержка старых браузеров</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">Базовая оценка понимания макета</a></li> +</ul> diff --git a/files/ru/learn/css/css_layout/навыки_multicol/index.html b/files/ru/learn/css/css_layout/навыки_multicol/index.html new file mode 100644 index 0000000000..c549f1210b --- /dev/null +++ b/files/ru/learn/css/css_layout/навыки_multicol/index.html @@ -0,0 +1,78 @@ +--- +title: 'Проверь свои навыки: Multicol' +slug: Learn/CSS/CSS_layout/Навыки_Multicol +translation_of: Learn/CSS/CSS_layout/Multicol_skills +--- +<div>{{LearnSidebar}}</div> + +<div></div> + +<p>Цель этого задания — чтобы вы поработали с CSS свойствами {{CSSxRef("column-count")}}, {{CSSxRef("column-width")}}, {{CSSxRef("column-gap")}}, {{CSSxRef("column-span")}} и {{CSSxRef("column-rule")}} и со значениями которые описаны в нашем уроке <a href="/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Макет с несколькими столбцами</a>. <span class="tlid-translation translation" lang="ru"><span title="">Вы будете работать над тремя небольшими задачами,</span></span> использующими различные элементы из пройденного материала.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: <span class="tlid-translation translation" lang="ru"><span title="">Вы можете опробовать решения в интерактивных редакторах ниже</span></span>, однако может быть полезным загрузить код и использовать онлайн инструменты такие как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, or <a href="https://glitch.com/">Glitch</a> чтобы проработать задания.</p> + +<p>Если вы застрянете, попросите нас о помощи — см. раздел {{anch("Оценка и дальнейшая помощь")}} в конце страницы.</p> +</div> + +<h2 id="Multicol_Раз">Multicol Раз</h2> + +<p>В этом задании вам необходимо создать три столбца с отступом 50px между каждый столбцом.</p> + +<p><img alt="Three columns of text" src="https://mdn.mozillademos.org/files/17081/multicol-task1.png" style="height: 722px; width: 1226px;"></p> + +<p>Попробуйте обновить живой пример ниже для воссоздания законченного примера:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/multicol/multicol1.html", '100%', 1000)}}</p> + +<div class="blockIndicator note"> +<p>Для оценки или дальнейшей работы, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/multicol/multicol1-download.html">загрузите отправную точку этого задания</a> чтобы работать в вашем собственном или онлайн редакторе.</p> +</div> + +<h2 id="Multicol_Два">Multicol Два</h2> + +<p>Создайте столбцы с минимальной шириной 200px.</p> + +<p>Затем добавьте серую линейку 5px между каждым столбцом, убедитесь, что между краями линейки и содержимым столбцов есть пространство 10px.</p> + +<p><img alt="Three columns of text with a grey rule between them." src="https://mdn.mozillademos.org/files/17082/multicol-task2.png" style="height: 668px; width: 1222px;"></p> + +<p>Попробуйте обновить живой код ниже для воссоздания законченного примера:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/multicol/multicol2.html", '100%', 1000)}}</p> + +<div class="blockIndicator note"> +<p>Для оценки или дальнейшей работы, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/multicol/multicol2-download.html">загрузите отправную точку этого задания</a> чтобы работать в вашем собственном или онлайн редакторе.</p> +</div> + +<h2 id="Multicol_Три">Multicol Три</h2> + +<p>Заставьте элемент содержащий заголовок и подзаголовок растянуться через все столбцы так чтоб это выглядело как на картинке</p> + +<p><img alt="Three columns of text with a heading and subheading spanning all three in the middle." src="https://mdn.mozillademos.org/files/17083/multicol-task3.png" style="height: 871px; width: 1222px;"></p> + +<p>Попробуйте обновить живой код ниже для воссоздания законченного примера:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/multicol/multicol3.html", '100%', 1000)}}</p> + +<div class="blockIndicator note"> +<p>Для оценки или дальнейшей работы, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/multicol/multicol3-download.html">загрузите отправную точку этого задания</a> чтобы работать в вашем собственном или онлайн редакторе.</p> +</div> + +<h2 id="Оценка_и_дальнейшая_помощь">Оценка и дальнейшая помощь</h2> + +<p>Вы можете попрактиковаться с этими примерами в интерактивных редакторах упомянутых выше.</p> + +<p>Если вы хотите, чтобы вашу работу оценили, или вы застряли и хотите попросить помощи:</p> + +<ol> + <li>Разместите свою работу в онлайн редакторе в которым можно поделиться работами в таком как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, или <a href="https://glitch.com/">Glitch</a>. Вы можете написать код самостоятельно или использовать файлы с отправными точками ссылки на которые имеются в разделах выше.</li> + <li>Напишите пост с просьбой оценки и/или помощи на <a class="external external-icon" href="https://discourse.mozilla.org/c/mdn/learn" rel="noopener">MDN Discourse forum Learning category</a>. Ваш пост должен включать: + <ul> + <li>Описательный заголовок такой как "Требуется оценка проверки навыков по Multicol задание 1".</li> + <li>Детали о том, что вы уже попытались сделать и что бы вы хотели, чтобы мы сделали, например, если вы застряли и вам нужна помощь, либо вы хотите оценку.</li> + <li>Ссылку на онлайн редактор (как упомянуто выше в пункте 1) с примером, который нуждается в оценке или с которым нужна помощь. Это хорошая практика чтобы вникнуть — очень сложно помочь кому-либо с проблемным кодом если вы не видите их код.</li> + <li>Ссылку на актуальную задачу или страницу оценки, чтобы мы могли найти вопрос, по которому вам нужна помощь.</li> + </ul> + </li> +</ol> diff --git a/files/ru/learn/css/css_layout/навыки_позиционирования/index.html b/files/ru/learn/css/css_layout/навыки_позиционирования/index.html new file mode 100644 index 0000000000..f63a3a3a94 --- /dev/null +++ b/files/ru/learn/css/css_layout/навыки_позиционирования/index.html @@ -0,0 +1,64 @@ +--- +title: 'Проверьте свои навыки: позиционирование' +slug: Learn/CSS/CSS_layout/Навыки_позиционирования +translation_of: Learn/CSS/CSS_layout/Position_skills +--- +<div>{{LearnSidebar}}</div> + +<div></div> + +<p>Цель этого задания - чтобы вы поработали с CSS свойством {{CSSxRef("position")}} и его значениями которые описаны в нашем уроке <a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Позиционирование</a>. <span class="tlid-translation translation" lang="ru"><span title="">Вы будете работать над двумя небольшими задачами,</span></span> использующими различные элементы из пройденного материала.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: <span class="tlid-translation translation" lang="ru"><span title="">Вы можете опробовать решения в интерактивных редакторах ниже</span></span>, однако может быть полезным загрузить код и использовать онлайн инструменты такие как<a href="https://codepen.io/"> CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, или <a href="https://glitch.com/">Glitch</a> чтобы проработать задания.</p> + +<p>Если вы застрянете, попросите нас о помощи — см. раздел {{anch("Оценка и дальнейшая помощь")}} в конце страницы</p> +</div> + +<h2 id="Позиционирование_Раз">Позиционирование Раз</h2> + +<p>В этом задании вам необходимо расположить элементы с классом target в верхнем правом углу контейнера, который имеет серую границу 5px.</p> + +<p><img alt="The green box is at the top right of a container with a grey border." src="https://mdn.mozillademos.org/files/17077/position-task1.png" style="height: 661px; width: 1033px;"></p> + +<p>Попробуйте обновить живой код ниже для воссоздания законченного примера:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/position/position1.html", '100%', 1000)}}</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В качестве дополнительной задачи</span></span>, сможете ли вы изменить цель так чтоб она отображалась под текстом?</p> + +<div class="blockIndicator note"> +<p>Для оценки или дальнейшей работы, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/position/position1-download.html">загрузите отправную точку этого задания</a> чтобы работать в вашем собственном или онлайн редакторе</p> +</div> + +<h2 id="Позиционирование_Два">Позиционирование Два</h2> + +<p>В примере ниже если вы прокрутите блок <span class="tlid-translation translation" lang="ru"><span title="">боковая панель прокручивается вместе с контентом. Измените его так чтобы боковая панель оставалась на месте и прокручивался только контент.</span></span></p> + +<p><img alt="The content is scrolled but the sidebar has stayed in place." src="https://mdn.mozillademos.org/files/17078/position-task2.png" style="height: 827px; width: 1123px;"></p> + +<p>Попробуйте обновить живой код ниже для воссоздания законченного примера:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/tasks/position/position2.html", '100%', 1000)}}</p> + +<div class="blockIndicator note"> +<p>ля оценки или дальнейшей работы, <a href="https://github.com/mdn/css-examples/blob/master/learn/tasks/position/position1-download.html">загрузите отправную точку этого задания</a> чтобы работать в вашем собственном или онлайн редактор</p> +</div> + +<h2 id="Оценка_и_дальнейшая_помощь">Оценка и дальнейшая помощь</h2> + +<p>Вы можете попрактиковаться с этими примерами в интерактивных редакторах упомянутых выше.</p> + +<p>Если вы хотите, чтобы вашу работу оценили, или вы застряли и хотите попросить помощи:</p> + +<ol> + <li>Разместите свою работу в онлайн редакторе в которым можно поделиться работами в таком как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, или <a href="https://glitch.com/">Glitch</a>. Вы можете написать код самостоятельно или использовать файлы с отправными точками ссылки на которые имеются в разделах выше.</li> + <li>Напишите пост с просьбой оценки и/или помощи на <a class="external external-icon" href="https://discourse.mozilla.org/c/mdn/learn" rel="noopener">MDN Discourse forum Learning category</a>. Ваш пост должен включать: + <ul> + <li>Описательный заголовок такой как "Требуется оценка проверки навыков по Позиционированияю".</li> + <li>Детали о том, что вы уже попытались сделать и что бы вы хотели, чтобы мы сделали, например, если вы застряли и вам нужна помощь, либо вы хотите оценку.</li> + <li>Ссылку на онлайн редактор (как упомянуто выше в пункте 1) с примером, который нуждается в оценке или с которым нужна помощь. Это хорошая практика чтобы вникнуть — очень сложно помочь кому-либо с проблемным кодом если вы не видите их код.</li> + <li>Ссылку на актуальную задачу или страницу оценки, чтобы мы могли найти вопрос, по которому вам нужна помощь.</li> + </ul> + </li> +</ol> diff --git a/files/ru/learn/css/css_layout/нормальный_поток/index.html b/files/ru/learn/css/css_layout/нормальный_поток/index.html new file mode 100644 index 0000000000..d936c240c5 --- /dev/null +++ b/files/ru/learn/css/css_layout/нормальный_поток/index.html @@ -0,0 +1,96 @@ +--- +title: Базовый поток +slug: Learn/CSS/CSS_layout/Нормальный_поток +tags: + - float + - grid +translation_of: Learn/CSS/CSS_layout/Normal_Flow +--- +<div>{{LearnSidebar}}</div> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Introduction", "Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout")}}</p> + +<p class="summary">Эта статья объясняет нормальный/базовый поток (normal flow) или способ, которым элементы страницы располагаются на веб-странице по умолчанию.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Что нужно знать прежде чем изучать:</th> + <td>Основы HTML (изучите <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), и понимания как работает CSS (изучите <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a>.)</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Объяснить как браузеры размещают элементы на веб-странице по умолчанию, т.е. прежде, чем мы начнем вносить какие-либо изменения.</td> + </tr> + </tbody> +</table> + +<p>Как говорилось ранее, элементы на веб-странице располагаются в нормальном потоке, если вы не применили к ним ни единого CSS для изменения их поведения. И, как мы уже выяснили, вы можете изменить поведение элементов либо путем изменения их положения в этом нормальном потоке, либо удалением этих элементов из этого потока. Хорошо структурированный документ, читабельный в нормальном потоке является лучшим путём начала любой веб-страницы. Это гарантирует, что ваш контент будет читабельным, даже если пользователи используют очень ограниченный браузер или устройство для чтения, которое считывает содержимое страницы. Кроме того, поскольку нормальный поток предназначен для создания читабельного документа, имейте в виду, что вы не сражаетесь с первоначальным видом документа, а работаете с ним.</p> + +<p>Прежде чем углубиться в разные способы компоновки, стоит пересмотреть некоторые из вещей, которые вы изучили в предыдущих модулях в отношении нормального потока документов. </p> + +<h2 id="Как_элементы_располагаются_по_умолчанию">Как элементы располагаются по умолчанию?</h2> + +<p>Прежде всего, индивидуальные боксы элементов располагаются в зависимости от содержимого элементов, затем добавляя какой-нибудь padding, border и margin вокруг них - это опять-таки боксовая модель, которую мы рассмотрели ранее.</p> + +<p>По умолчанию содержимое элемента уровня блока составляет 100% от ширины его родительского элемента и столь же высок, как и его содержимое. Встроенные элементы высоки и широки, как их содержимое. Вы не можете установить ширину или высоту на встроенные элементы — они просто находятся внутри содержимого элементов блочного уровня. Если вы хотите контролировать размер встроенного элемента вам нужно настроить его так, чтобы он себя вёл как элемент блочного уровня при помощи <code>display: block;</code> (или даже, <code>display: inline-block;</code>, который смешивает характеристики обоих.).</p> + +<p>Это объясняет отдельные элементы, но как насчет того, как элементы взаимодействуют друг с другом? Нормальный поток макета (упомянутый в статье введения макета) - это система, посредством которой элементы размещаются внутри окна просмотра браузера. По умолчанию элементы уровня блока выкладываются в направлении, что блокирует отображение в режиме записи документа - каждый из них будет отображаться в новой строке ниже последней строки, и они будут разделены любым полем, установленным на них. Поэтому на английском языке или на любом другом, в котором режим писания горизонтальный, сверху вниз, элементы уровня блока располагаются вертикально.</p> + +<p>Встроенные элементы ведут себя по-другому — они не появляются на новых строках; они распологаются на той же строке, что и другие и любой смежной или завернутый текст располагается на всю ширину внутри элемента уровня родительского блока, до тех пор, пока не закончится пространство. Если пространства нет, тогда текст и/или элементы перейдут на новую строку (не с абзаца).</p> + +<p>Если два смежных элемента имеют заданные для них поля/внешние отступы (margin) и эти поля соприкасаются друг с другом, большее из них остается, а меньшее исчезает — это звётся схлопывание полей (margin collapsing), и мы рассматривали это ранее.</p> + +<p>Давайте посмотрим на пример, который объясняет всё из того, что мы рассмотрели в данной статье:</p> + +<div id="Normal_Flow"> +<pre class="brush: html notranslate"><h1>Базовый поток документа</h1> + +<p>Я базовый элемент уровня блока. Мои соседние блочные элементы находятся на новой строке подо мной.</p> + +<p>По умолчанию мы охватываем 100% ширины нашего родительского элемента, и мы так же высоки, как и наш child-контент. Наша общая ширина и высота - это наш контент + внутренний отступ (padding) + ширина / высота границы.</p> + +<p>Мы отделены нашими полями. Из-за схлопывания полей мы отделены шириной одного из наших полей, а не обоих</p> + +<p>Встроенные элементы <span>такие как этот</span> и <span>этот</span> находятся на одной линии с другими, и смежным текстом, если есть пространство. Встроенные элементы, что не влезают <span>переходять на новую строку если это возможно (как этот текст)</span>если же это невозможно, они переходят на новую строку, как это изображение: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css notranslate">body { + width: 500px; + margin: 0 auto; +} + +p { + background: rgba(255,84,104,0.3); + border: 2px solid rgb(255,84,104); + padding: 10px; + margin: 10px; +} + +span { + background: white; + border: 1px solid black; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Normal_Flow', '100%', 500) }}</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Теперь, когда вы поняли нормальный поток и как браузер выкладывает содержимое по умолчанию, двигаемся дальше, чтобы понять как это изменить для создания макета согласно вашему дизайну.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Introduction", "Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">Введение в CSS layout</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow">Базовый поток</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Сетка(Grid)</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Потоки (Floats)">Поплавки</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Позиционирование(Positioning)</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Макет с несколькими столбцами</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">Методы устаревших макетов</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">Поддержка старых браузеров</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">Фундаментальная оценка понимания макета</a></li> +</ul> diff --git a/files/ru/learn/css/css_layout/отзывчивый_дизайн/index.html b/files/ru/learn/css/css_layout/отзывчивый_дизайн/index.html new file mode 100644 index 0000000000..978b4e43dc --- /dev/null +++ b/files/ru/learn/css/css_layout/отзывчивый_дизайн/index.html @@ -0,0 +1,328 @@ +--- +title: Отзывчивый дизайн +slug: Learn/CSS/CSS_layout/Отзывчивый_дизайн +translation_of: Learn/CSS/CSS_layout/Responsive_Design +--- +<div>{{learnsidebar}}{{PreviousMenuNext("Learn/CSS/CSS_layout/Multiple-column_Layout", "Learn/CSS/CSS_layout/Media_queries", "Learn/CSS/CSS_layout")}}</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">На заре веб-дизайна страницы создавались для экрана определенного размера.</span></span> Если у пользователя был экран большего или меньшего размера чем ожидал дизайнер, то результат мог быть от нежелательных полос прокрутки, до<span class="tlid-translation translation" lang="ru"><span title=""> слишком длинной строки и плохого использования пространства. Поскольку становились доступны много различных размеров экранов, появилась концепция <em>отзывчивого (адаптивого) веб-дизайна</em> </span></span><em>(responsive web design</em> (RWD)) — набор методов, которые позволяют веб-страницам менять свой макет и внешний вид в соответствии с разной шириной экрана, разрешением и т.д. Это та самая, идея которая изменила подход к дизайну веба для множества устройств, и в этой статье мы поможем вам понять основные методы, которые вам необходимо знать, чтобы освоить его.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Основы HTML (изучите <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), идея о том как работает CSS (изучите <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a> и <a href="/en-US/docs/Learn/CSS/Building_blocks">Устройство CSS</a>.)</p> + </td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td> + <p>Понять базовые концепции и историю отзывчивого дизайна.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Исторические_макеты_сайтов">Исторические макеты сайтов</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В какой-то момент истории при разработке веб-сайта у вас было два варианта:</span></span></p> + +<ul> + <li>Вы могли создать <em>жидкий </em>сайт, который будет растягиваться чтобы заполнить окно браузера</li> + <li>или сайт с <em>фиксированной шириной</em>, который будет иметь фиксированный размер в пикселях.</li> +</ul> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Эти два подхода, как правило, приводили к тому, что веб-сайт лучше всего выглядел на экране человека, создавшего сайт!</span></span> <span class="tlid-translation translation" lang="ru"><span title="">Жидкий сайт приводил к раздавленному дизайну на маленьких экранах (как видно ниже)</span></span> и не читаемо длинным строкам на больших.</p> + +<figure><img alt="A layout with two columns squashed into a mobile size viewport." src="https://mdn.mozillademos.org/files/16834/mdn-rwd-liquid.png" style="display: block; height: 406px; width: 300px;"> +<figcaption></figcaption> +</figure> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Посмотрите этот простой жидкий макет: <a href="https://mdn.github.io/css-examples/learn/rwd/liquid-width.html">пример</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/liquid-width.html">исходный код</a>. При просмотре примера, растягивайте и сжимайте окно браузера чтобы увидеть, как это выглядит при разных размерах.</p> +</div> + +<p>Сайт с фиксированной шириной рисковал иметь горизонтальную полосу прокрутки на экранах меньших чем ширина сайта (как видно ниже) и много белого пространства на краях дизайна на больших экранах.</p> + +<figure><img alt="A layout with a horizontal scrollbar in a mobile viewport." src="https://mdn.mozillademos.org/files/16835/mdn-rwd-fixed.png" style="display: block; height: 411px; width: 300px;"> +<figcaption></figcaption> +</figure> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Посмотрите этот простой макет с фиксированной шириной: <a href="https://mdn.github.io/css-examples/learn/rwd/fixed-width.html">пример</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/fixed-width.html">исходный код</a>. Снова изучите результат по мере изменения размера окна браузера.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Скриншоты выше сделаны используя <a href="/en-US/docs/Tools/Responsive_Design_Mode">Responsive Design Mode</a> в Firefox DevTools.</p> +</div> + +<p>Когда мобильный веб стал становиться реальностью с первыми функциональными телефонами, компании желающие охватить мобильники начали создавать в основном специальные мобильные версии своих сайтов, с различными URL (часто что-то наподобие <em>m.example.com</em> или <em>example.mobi</em>). Это означало, что необходимо было разрабатывать и поддерживать в актуальном состоянии две отдельные версии сайта.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Кроме того, эти мобильные сайты часто предлагали очень урезанный вариант.</span></span> Поскольку мобильные гаджеты стали мощнее и способными отображать целые веб-сайты, пользователей мобильных устройств раздражало, что они обнаруживали себя запертыми в мобильной версии сайта, неспособные получить доступ к информации, которая, как они знали, есть в полнофункциональной версии сайта.</p> + +<h2 id="Гибкий_макет_до_отзывчивого_дизайна">Гибкий макет до отзывчивого дизайна</h2> + +<p>Было разработано несколько подходов чтобы попытаться разрешить недостатки построения веб-сайтов жидким методом или методом с фиксированной шириной. В 2004 году Камерон Адамс написал пост <a href="http://www.themaninblue.com/writing/perspective/2004/09/21/">Resolution dependent layout</a>, описывающий метод создания дизайна который мог бы адаптироваться к разным разрешениям экрана. Этот подход требовал, чтобы JavaScript узнавал разрешение экрана и загружал корректный CSS.</p> + +<p>Зои Миккели Гилленвотер сыграла важную роль в свой работе описав и формализовав различные способы посредствам которых могут быть созданы гибкие сайты, пытаясь найти золотую середину между заполнением экрана или <span class="tlid-translation translation" lang="ru"><span title="">полностью фиксированным размером.</span></span></p> + +<h2 id="Отзывчивый_дизайн">Отзывчивый дизайн</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Термин адаптивный дизайн был </span></span><a href="https://alistapart.com/article/responsive-web-design/">Придуман Итаном Маркоттом в 2010 году</a><span class="tlid-translation translation" lang="ru"><span title=""> и описывал использование трех методов в сочетании.</span></span></p> + +<ol> + <li>Первой была идея жидких сеток, нечто что уже исследовала Гилленвотер, что можно прочитать в статье Маркотта - <a href="https://alistapart.com/article/fluidgrids/">Fluid Grids</a> (опубликовано в 2009 в A List Apart).</li> + <li>Вторым методом была идея <a href="http://unstoppablerobotninja.com/entry/fluid-images">жидких изображений</a>. Используя очень простой метод настройки свойства <code>max-width</code> на <code>100%</code>, изображения будут становиться меньше если содержащий столбец становится уже чем изначальный размер изображения, но никогда не становится больше. Это позволяет изображению уменьшаться чтобы соответствовать столбцу гибких размеров, а не перекрываться с ним, но не расти и становиться пиксельным если столбец становится шире изображения.</li> + <li>Третьим ключевым компонентом был <a href="/en-US/docs/Web/CSS/Media_Queries">media query</a>. Media Query позволяют переключать тип макета применяя только CSS то, что Камерон Адамс исследовал, используя JavaScript. Вместо того чтобы иметь один макет для всех размеров экранов, макет мог изменяться. Боковые панели можно перемещать для маленьких экранов, либо отображать альтернативную навигацию.</li> +</ol> + +<p>Очень важно понять, что <strong>адаптивный веб-дизайн </strong>— <strong>это не отдельная технология</strong>, это термин используемый, чтобы описать подход к веб-дизайну или набор лучших практик, используемых для создания макета, который может реагировать на используемое устройство для просмотра контента. <span class="tlid-translation translation" lang="ru"><span title="">В первоначальном исследовании Маркотта это означало гибкие сетки (с использованием floats) и </span></span>media query<span class="tlid-translation translation" lang="ru"><span title="">, однако почти за 10 лет, прошедших с момента написания этой статьи, адаптивная работа стала стандартом по умолчанию. Современные методы макета CSS отзывчивы по своей сути, и </span></span>у нас есть новые штучки, встроенные в веб-платформу для того, чтобы делать дизайн отзывчивых сайтов проще.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Остальная часть этой статьи укажет вам на различные функции веб-платформы, которые вы, возможно, захотите использовать при создании адаптивного сайта.</span></span></p> + +<h2 id="Media_Queries_Медиа-запросы">Media Queries (Медиа-запросы)</h2> + +<p>Отзывчивый дизайн был способен появится только благодаря media query. Спецификация Media Queries Level 3 стала Рекомендованным Кандидатом в 2009 году, что означает, <span class="tlid-translation translation" lang="ru"><span title="">что она была признана готовой к реализации в браузерах. Медиа запросы позволяют нам проводить серию тестов (например, является ли экран пользователя больше, чем определенная ширина или разрешение) и выборочно применять CSS к стилю страницы соответственно с нуждами пользователя.</span></span></p> + +<p>Например, следующий медиа запрос проверяет отображается ли текущая страница как экранная медиа (а не как печатный документ) и имеет ли область просмотра ширину как минимум 800 px. CSS будет применяться к селектору <code>.container</code> только если эти две вещи истины.</p> + +<pre class="brush: css notranslate"><code>@media screen and (min-width: 800px) { + .container { + margin: 1em 2em; + } +} </code> +</pre> + +<p>Вы можете добавлять несколько медиа запросов в пределах одной таблицы стилей, подстраивая весь ваш макет или его части так чтоб соответствовать наилучшим образом разным размерам экрана. Точки, в которых применяется media query и меняется макет, известны как <em>контрольные точки.</em></p> + +<p>Общим подходом при использовании Media Queriy является создание простого одно колоночного макета для устройств с узкими экранами (например, мобильные телефоны), затем проверка для бо'льших экранов и применение макета с несколькими столбцам, когда вы знаете, что у вас достаточно ширины экрана чтобы уместить все. Это часто называют дизайном <strong>сначала мобильный</strong> (<strong>mobile first</strong>).</p> + +<p>Узнать больше о <a href="/en-US/docs/Web/CSS/Media_Queries">Media Query</a> можно в документации MDN.</p> + +<h2 id="Гибкие_сетки">Гибкие сетки</h2> + +<p>Отзывчивые сайты не просто меняют свой макет между контрольными точками, они построены на гибких сетках. Гибкая сетка подразумевает что вам не надо заботиться о каждом возможном существующем размере устройства и строить для них идеальный макет в пикселях. Такой подход был бы невозможен имея широкое множество существующих устройств разных размеров, как и факт того, что даже на ПК люди не всегда используют браузер с развернутым до максимума окном.</p> + +<p>Используя гибкую сетку, вам всего лишь надо добавить контрольную точку и изменить дизайн в точке, когда ваш контент начинает выглядеть плохо. Например, если длина строки становится нечитаемо длинной при увеличении размера экрана, или блок становится сдавленным с двумя словами в каждой строке при сужении экрана.</p> + +<p>В первые дни отзывчивого дизайна, нашим единственным вариантом выполнения было использование <a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">floats</a>. Гибкий обтекаемый макет достигался путем присвоения каждому элементу процентной ширины удостоверившись, что итоговые значения в макете не превышают 100%. <span class="tlid-translation translation" lang="ru"><span title="">В своей оригинальной статье о плавучих сетках Маркотт подробно описал формулу для преобразования макета, созданного с использованием пикселей, в проценты.</span></span></p> + +<pre class="notranslate"><code>target / context = result </code> +</pre> + +<p>Например, если размер нашего целевого столбца — 60 пикселей, а контекст (или контейнер) в котором он находится — 960 пикселей, то мы делим 60 на 960 чтобы получить значение которое мы можем использовать в нашем CSS, после переноса десятичной точки вправо на 2 цифры.</p> + +<pre class="brush: css notranslate"><code>.col { + width: 6.25%; /* 60 / 960 = 0.0625 */ +} </code> +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Этот подход сегодня можно найти во многих местах в Интернете и он задокументирован здесь в разделе макетов в нашей статье </span></span><a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">Устаревших методов макетов</a>. В вашей работе вероятно, что вы столкнетесь с веб-сайтами, использующими этот подход, поэтому стоит понимать его, даже если вы не будете строить современные сайты используя гибкие сетки основанные на float.</p> + +<p>Следующий пример демонстрирует простой отзывчивый дизайн используя Media Query и гибкие сетки. На узких экранах макет отображает блоки, сложенные друг на друга:</p> + +<figure><img alt="A mobile view of the layout with boxes stacked on top of each other vertically." src="https://mdn.mozillademos.org/files/16836/mdn-rwd-mobile.png" style="display: block; height: 407px; width: 300px;"> +<figcaption></figcaption> +</figure> + +<p>На более широких экранах они премещаются в два столбца:</p> + +<figure><img alt="A desktop view of a layout with two columns." src="https://mdn.mozillademos.org/files/16837/mdn-rwd-desktop.png" style="display: block; height: 217px; width: 600px;"> +<figcaption></figcaption> +</figure> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Вы можете найти <a href="https://mdn.github.io/css-examples/learn/rwd/float-based-rwd.html">живой пример</a> и <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/float-based-rwd.html">исходный код</a> этого примера на GitHub.</p> +</div> + +<h2 id="Современные_технологии_макетов">Современные технологии макетов</h2> + +<p>Современные методы макетов такие как <a href="/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Макет с несколькими столбцами</a>, <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a>, и <a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Grid</a> являются отзывчивыми по умолчанию. Они все предполагают, что вы пытаетесь создать гибкую сетку и дают вам более легкий способ сделать так.</p> + +<h3 id="Multicol">Multicol</h3> + +<p>Самый старый из этих методов — это multicol, когда вы задаете <code>column-count</code>, это отражает то на сколько столбцов вы хотите разбить ваш контент. Далее браузер рассчитывает их размер, размер, который изменится согласно размеру экрана.</p> + +<pre class="brush: css notranslate"><code>.container { + column-count: 3; +} </code> +</pre> + +<p>Если вместо этого вы зададите <code>column-width</code>, то вы определите <em>минимальную </em>ширину. Браузер создаст столько столбцов той ширины, сколько будет комфортно умещаться в контейнер, а затем поделит оставшееся пространство между всеми столбцами. Поэтому число столбцов будет меняться согласно тому сколько имеется места.</p> + +<pre class="brush: css notranslate"><code>.container { + column-width: 10em; +} </code> +</pre> + +<h3 id="Flexbox">Flexbox</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В Flexbox, в качестве исходного поведения, flex элементы будут сжиматься и распределять пространство между элементами в соответствии с пространством в их контейнере. Изменяя значения </span></span><code>flex-grow</code> и <code>flex-shrink</code> <span class="tlid-translation translation" lang="ru"><span title="">вы можете указать, как вы хотите, чтобы предметы вели себя когда они сталкиваются с бо'льшим или меньшим пространством вокруг себя.</span></span></p> + +<p>В примере ниже каждый flex элемент будет принимать равное количество пространства во flex контейнере используя запись <code>flex: 1</code> как описано в главе <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox#Flexible_sizing_of_flex_items">Flexbox: Гибкое изменение размеров flex элементов</a>.</p> + +<pre class="brush: css notranslate"><code>.container { + display: flex; +} + +.item { + flex: 1; +} </code> +</pre> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: В качестве примера мы перестроили простой отзывчивый макет выше, в этот раз используя flexbox. Вы видите что нас больше не надо использовать странные процентные значения для подсчета размера столбцов: <a href="https://mdn.github.io/css-examples/learn/rwd/flex-based-rwd.html">пример</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/flex-based-rwd.html">исходный код</a>.</p> +</div> + +<h3 id="CSS_grid">CSS grid</h3> + +<p>В макете CSS Grid единицы измерения <code>fr</code> позволяют распределять доступное пространство между дорожками сетки. Следующий пример создает grid контейнер с тремя дорожками размером <code>1fr</code>. Это создаст три вертикальные дорожки, каждая занимающая одну часть свободного пространства в контейнере. <span class="tlid-translation translation" lang="ru"><span title="">Вы можете узнать больше об этом подходе к созданию сетки в теме Изучение Макета Grid в разделе </span></span><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids#Flexible_grids_with_the_fr_unit">Гибкие grids с единицами fr</a>.</p> + +<pre class="brush: css notranslate"><code>.container { + display: grid; + grid-template-columns: 1fr 1fr 1fr; +} </code> +</pre> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: версия grid макета еще проще, поскольку мы можем определить столбцы в .wrapper: <a href="https://mdn.github.io/css-examples/learn/rwd/grid-based-rwd.html">пример</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/grid-based-rwd.html">исходный код</a>.</p> +</div> + +<h2 id="Отзывчивые_изображения">Отзывчивые изображения</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Самый простой подход к отзывчивым изображениям был описан</span></span> в ранних статьях Маркотта по отзывчивому дизайну. <span class="tlid-translation translation" lang="ru"><span title="">По сути, вы берете изображение максимального размера, которое могло понадобиться, и уменьшаете его.</span></span> Этот подход до сих пор используется и в большинстве таблиц стилей вы найдете следующий CSS:</p> + +<pre class="brush: css notranslate"><code>img { + max-width: 100%; +} </code> +</pre> + +<p>Существуют очевидные недостатки к этому подходу. Изображение может быть изображено намного меньше своего исходного размера, что является пустой тратой пропускной способности — <span class="tlid-translation translation" lang="ru"><span title="">пользователь мобильных может загружать изображение, в несколько раз превышающее размер того, что он фактически видит в окне браузера. </span></span> <span class="tlid-translation translation" lang="ru"><span title="">Кроме того, вам может не понадобиться такое же соотношение сторон изображения на мобильном устройстве, как на компьютере.</span></span> Либо<span class="tlid-translation translation" lang="ru"><span title="">, учитывая меньший размер изображения на мобильном телефоне, вы можете захотеть показать совсем другое изображение, которое легче понять на маленьком экране. Такие вещи можно достичь, просто уменьшая изображение.</span></span></p> + +<p>Отзывчивые изображения, используя элемент {{htmlelement("picture")}} и атрибуты <code>srcset</code> и <code>sizes</code> элемента {{htmlelement("img")}} оба решают эти проблемы. <span class="tlid-translation translation" lang="ru"><span title="">Вы можете указать несколько размеров вместе с «подсказками» (метаданные, описывающие размер экрана и разрешение, для которых изображение лучше всего подходит), и браузер выберет наиболее подходящее изображение для каждого устройства, гарантируя, что пользователь загрузит изображение подходящего размера</span> <span title="">для устройства, которое они используют.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы также можете напрямую использовать изображения разных размеров, обеспечивая разное кадрирование или совершенно другое изображение для разных размеров экрана.</span></span></p> + +<p>Вы можете найти подробное <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">руководство по отзывчивым изображениям в разделе ищучения HTML </a>на MDN.</p> + +<h2 id="Отзывчивая_типография">Отзывчивая типография</h2> + +<p>Элементом отзывчивого дизайна, не освещенного ранее в работе, была идея отзывчивой типографии. Главным образом, она описывает изменение размера шрифта в пределах media queries для того, чтобы отображать бо'льшую или меньшую площадь экрана.</p> + +<p>В этом примере, мы хотим задать нашему заголовку первого уровня <code>4rem</code>, что значит, что он будет в четыре раза больше нашего базового размера шрифта. Это очень большой заголовок! Мы хотим этот гигантский заголовок только на экранах больших размеров, поэтому мы сначала создаем меньший заголовок, а затем используем media queries чтобы переписать его для больших экранов если мы знаем что у пользователя есть экран размером как минимум <code>1200px</code>.</p> + +<pre class="brush: css notranslate"><code>html { + font-size: 1em; +} + +h1 { + font-size: 2rem; +} + +@media (min-width: 1200px) { + h1 { + font-size: 4rem; + } +} </code> +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Мы отредактировали наш приведенный выше пример отзывчивой сетки grid, чтобы он также включал в себя адаптивный тип, используя описанный метод.</span> <span title="">Вы можете видеть, как заголовок меняет размеры, когда макет переходит в версию с двумя столбцами.</span></span></p> + +<p>В мобильных версиях заголовок меньше:</p> + +<figure><img alt="A stacked layout with a small heading size." src="https://mdn.mozillademos.org/files/16838/mdn-rwd-font-mobile.png" style="display: block; height: 407px; width: 300px;"> +<figcaption></figcaption> +</figure> + +<p>На компьютерах, однако, мы видим больший размер заголовка:</p> + +<figure><img alt="A two column layout with a large heading." src="https://mdn.mozillademos.org/files/16839/mdn-rwd-font-desktop.png" style="display: block; height: 169px; width: 600px;"> +<figcaption></figcaption> +</figure> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: смотрите этот пример в действии: <a href="https://mdn.github.io/css-examples/learn/rwd/type-rwd.html">пример</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/type-rwd.html">исходный код</a>.</p> +</div> + +<p>Такой подход к типографии показывает, что вам не надо ограничивать media queries <span class="tlid-translation translation" lang="ru"><span title="">только изменением макета страницы.</span></span> Они могут быть использоваться для <span class="tlid-translation translation" lang="ru"><span title="">настройки любого элемента, чтобы сделать его более удобным или привлекательным при других размерах экрана.</span></span></p> + +<h3 id="Using_viewport_units_for_responsive_typography">Using viewport units for responsive typography</h3> + +<p>An interesting approach is to use the viewport unit <code>vw</code> to enable responsive typography. <code>1vw</code> is equal to one percent of the viewport width, meaning that if you set your font size using <code>vw</code>, it will always relate to the size of the viewport.</p> + +<pre class="brush: css notranslate">h1 { + font-size: 6vw; +}</pre> + +<p>The problem with doing the above is that the user loses the ability to zoom any text set using the <code>vw</code> unit, as that text is always related to the size of the viewport. <strong>Therefore you should never set text using viewport units alone</strong>.</p> + +<p>There is a solution, and it involves using <code><a href="/en-US/docs/Web/CSS/calc">calc()</a></code>. If you add the <code>vw</code> unit to a value set using a fixed size such as <code>em</code>s or <code>rem</code>s then the text will still be zoomable. Essentially, the <code>vw</code> unit adds on top of that zoomed value:</p> + +<pre class="brush: css notranslate">h1 { + font-size: calc(1.5rem + 3vw); +}</pre> + +<p>This means that we only need to specify the font size for the heading once, rather than set it up for mobile and redefine it in the media queries. The font then gradually increases as you increase the size of the viewport.</p> + +<div class="blockIndicator note"> +<p>See an example of this in action: <a href="https://mdn.github.io/css-examples/learn/rwd/type-vw.html">example</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/type-vw.html">source code</a>.</p> +</div> + +<h2 id="The_viewport_meta_tag">The viewport meta tag</h2> + +<p>If you look at the HTML source of a responsive page, you will usually see the following {{htmlelement("meta")}} tag in the <code><head></code> of the document.</p> + +<pre class="brush: html notranslate"><code><meta name="viewport" content="width=device-width,initial-scale=1"></code> +</pre> + +<p>This meta tag tells mobile browsers that they should set the width of the viewport to the device width, and scale the document to 100% of its intended size, which shows the document at the mobile-optimized size that you intended.</p> + +<p>Why is this needed? Because mobile browsers tend to lie about their viewport width.</p> + +<p>This meta tag exists because when the original iPhone launched and people started to view websites on a small phone screen, most sites were not mobile optimized. The mobile browser would, therefore, set the viewport width to 960 pixels, render the page at that width, and show the result as a zoomed-out version of the desktop layout. Other mobile browsers (e.g. on Google Android) did the same thing. Users could zoom in and pan around the website to view the bits they were interested in, but it looked bad. You will still see this today if you have the misfortune to come across a site that does not have a responsive design.</p> + +<p>The trouble is that your responsive design with breakpoints and media queries won't work as intended on mobile browsers. If you've got a narrow screen layout that kicks in at 480px viewport width or less, and the viewport is set at 960px, you'll never see your narrow screen layout on mobile. By setting <code>width=device-width</code> you are overriding Apple's default <code>width=960px</code> with the actual width of the device, so your media queries will work as intended.</p> + +<p><strong>So you should <em>always</em> include the above line of HTML in the head of your documents.</strong></p> + +<p>There are other settings you can use with the viewport meta tag, however in general the above line is what you will want to use.</p> + +<ul> + <li><code>initial-scale</code>: Sets the initial zoom of the page, which we set to 1.</li> + <li><code>height</code>: Sets a specific height for the viewport.</li> + <li><code>minimum-scale</code>: Sets the minimum zoom level.</li> + <li><code>maximum-scale</code>: Sets the maximum zoom level.</li> + <li><code>user-scalable</code>: Prevents zooming if set to <code>no</code>.</li> +</ul> + +<p>You should avoid using <code>minimum-scale</code>, <code>maximum-scale</code>, and in particular setting <code>user-scalable</code> to <code>no</code>. Users should be allowed to zoom as much or as little as they need to; preventing this causes accessibility problems.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: There is a CSS @ rule designed to replace the viewport meta tag — <a href="/en-US/docs/Web/CSS/@viewport">@viewport</a> — however, it has poor browser support. When both are used the meta tag overrides @viewport.</p> +</div> + +<h2 id="Summary">Summary</h2> + +<p>Responsive design refers to a site or application design that responds to the environment in which it is viewed. It encompasses a number of CSS and HTML features and techniques and is now essentially just how we build websites by default. Consider the sites that you visit on your phone — it is probably fairly unusual to come across a site that is the desktop version scaled down, or where you need to scroll sideways to find things. This is because the web has moved to this approach of designing responsively.</p> + +<p>It has also become much easier to achieve responsive designs with the help of the layout methods you have learned in these lessons. If you are new to web development today you have many more tools at your disposal than in the early days of responsive design. It is therefore worth checking the age of any materials you are referencing. While the historical articles are still useful, modern use of CSS and HTML makes it far easier to create elegant and useful designs, no matter what device your visitor views the site with.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Multiple-column_Layout", "Learn/CSS/CSS_layout/Media_queries", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Introduction">Introduction to CSS layout</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow">Normal flow</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">Grid</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">Positioning</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">Multiple-column layout</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Responsive_Design">Responsive design</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Media_queries">Beginner's guide to media queries</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">Legacy layout methods</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">Supporting older browsers</a></li> + <li><a href="/en-US/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">Fundamental layout comprehension assessment</a></li> +</ul> diff --git a/files/ru/learn/css/css_properties/index.html b/files/ru/learn/css/css_properties/index.html new file mode 100644 index 0000000000..7b0f37346d --- /dev/null +++ b/files/ru/learn/css/css_properties/index.html @@ -0,0 +1,132 @@ +--- +title: 'CSS properties: what they are and how to use them' +slug: Learn/CSS/CSS_properties +translation_of: Learn/CSS/Building_blocks/Selectors +--- +<div class="summary"> +<p>{{Glossary("CSS")}} определяет как должна выглядеть вебстраница. Он использует предопределенные правила вместе с селекторами и свойствами для применения стилей к элементам HTML или группам элементов.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basics of {{Glossary("HTML")}}, <a href="https://developer.mozilla.org/en-US/Learn/HTML/HTML_tags">HTML elements</a>, and <a href="https://developer.mozilla.org/en-US/Learn/CSS/Using_CSS_in_a_web_page#The_link_tag">how to link HTML documents to CSS stylesheets</a>.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>Learn about different CSS selectors and properties enough to style a simple webpage.</td> + </tr> + </tbody> +</table> + +<h2 id="Summary">Summary</h2> + +<p>Разделение содержимого и стиля делает Веб разработку намного быстрее и проще. Когда вы определяете только стуктуру документа в вашем HTML файле и храните всю информацию о стиле в отдельном файле (называемом stylesheet), вы можете обновлять стили нескольких документов одновременно (а так же экономить ресурсы компьютера).</p> + +<p>CSS syntax consists of easy-to-use, intuitive keywords.</p> + +<pre class="brush: css">p { + font-family: "Times New Roman", georgia, sans-serif; + font-size: 24px; +}</pre> + +<p>In the example above, <code>p</code> is a selector that applies styles to all the <code>{{HTMLElement("p")}}</code> elements at once. The CSS properties <code>font-family</code> and <code>font-size</code> are enclosed within curly braces and the corresponding values, right after the colon, determine the styles.</p> + +<p>There are more than <a href="/en-US/docs/Web/CSS/Reference">250 properties</a> you can apply to your document. From text to layout, (almost) anything is possible.</p> + +<h2 id="Active_Learning">Active Learning</h2> + +<p><em>There is no active learning available yet. <a href="/en-US/docs/MDN/Getting_started">Please, consider contributing</a>.</em></p> + +<h2 id="Deeper_dive">Deeper dive</h2> + +<p>If properties are fairly simple to use, selectors are another story. Okay, they aren't that hard, and mastering them unleashes the full potential of CSS. In the next examples, we will introduce the most common selectors.</p> + +<p>A CSS rule consists of selectors associated with properties. Selectors specify which elements will receive the properties laid down in the rule. Multiple rules can apply to the same element; the CSS cascade (which we'll discuss later on) determines which rule ends up taking effect in the case of conflicts. For now, just remember that the rule with the most <a href="/en-US/docs/Web/CSS/Specificity">specific selector</a> overrides the rules with more generic selectors.</p> + +<h3 id="The_element_selector">The element selector</h3> + +<p>Element selectors select HTML elements by element names only. Moreover, like all CSS selectors, you can apply a common set of properties to several elements at once.</p> + +<p>For our first example, let's assume the following HTML code fragment:</p> + +<pre class="brush: html"><h1>I'm an example</h1> +<p>In this example, I'm a paragraph</p> +<p>And I'm another paragraph</p> +</pre> + +<p>In the following CSS rule, the element selector <code>p</code> applies the given styles simultaneously to all the <code>{{HTMLElement("p")}}</code> elements of our HTML document, preventing extensive rewriting. We are using the {{cssxref("font-family")}} property (which defines the font in which text appears) and the {{cssxref("font-size")}} (which defines text size).</p> + +<pre class="brush: css">p { + font-family: "Helvetica", Arial, sans-serif; + font-size : 12px; +}</pre> + +<p>The next CSS rule only applies to <code>{{HTMLElement("h1")}}</code> elements. We are using the {{cssxref("font-size")}} property to make our title twice the size of the body text, and the {{cssxref("font-weight")}} property to make the title bold.</p> + +<pre class="brush: css">h1 { + font-size : 24px; + font-weight: bold; +}</pre> + +<p>The following CSS rule applies the requisite styles to both <code>{{HTMLElement("h1")}}</code> and <code>{{HTMLElement("p")}}</code> elements, potentially removing even more duplication. (This use is called "group selector" or "chain selector". Notice the comma separating the selectors). Here we are using the {{cssxref("color")}} property to specify the same text color for both headings and paragraphs.</p> + +<pre class="brush: css">h1, p { + color: darkmagenta; +}</pre> + +<p>Here is the result of all this code:</p> + +<p>{{ EmbedLiveSample('The_element_selector') }}</p> + +<h3 id="The_id_selector">The id selector</h3> + +<p>The <code>id</code><strong> </strong>attribute of a particular HTML element uniquely identifies that element. Hence, an id selector is used only when a set of style rules applies to a single element.</p> + +<p>For our next example, let's assume the following HTML code fragment:</p> + +<pre class="brush: html"><p id="hello">Hello world!</p> </pre> + +<p>The following CSS rule applies only to that unique identified element. To make a selector into an id selector, you must put a hash character (#) in front of the id name. We are using three properties: {{cssxref("text-align")}} to center the text within the paragraph {{cssxref("border")}} to add a thin line around the paragraph, and {{cssxref("padding")}} to add some extra inner-margin between the text and the border.</p> + +<pre class="brush: css">#hello { + text-align: center; + border : 1px solid black; + padding : 8px; +}</pre> + +<p>And the result is the following:</p> + +<p>{{ EmbedLiveSample('The_id_selector') }}</p> + +<h3 id="The_class_selector">The class selector</h3> + +<p>Within HTML, the <code>class</code><strong> </strong>attribute lets you apply multiple identifiers to HTML elements. Those identifiers can be used with CSS to match groups of elements regardless of element name.</p> + +<p>For our next example, let's assume the following HTML code fragment:</p> + +<pre class="brush: html"><h1 class="hello">Hey there!</h1> +<p class="hello bye">Let's hang out together!</p> +<p class="bye">And walk over the mountain</p> +</pre> + +<p>Let's apply a CSS rule for all elements with the class <code>hello</code>. To make the selector into a class selector, put a period/full stop before the class name. We use the {{cssxref("font-style")}} property to italicize the text.</p> + +<pre class="brush: css">.hello { + font-style: italic; +}</pre> + +<p>And another one for all elements with the class <code>bye</code>. Here we are using the {{cssxref("text-decoration")}} property to draw a line through the text.</p> + +<pre class="brush: css">.bye { + text-decoration: line-through; +}</pre> + +<p>Here's what happened:</p> + +<p>{{ EmbedLiveSample('The_class_selector') }}</p> + +<h2 id="Next_step">Next step</h2> + +<p>So we've gone over the basics to get started with CSS. You can <a href="/en-US/docs/Learn/CSS/Basic_text_styling_in_CSS">learn more about text styling</a> or start exploring<a href="/en-US/docs/Web/CSS/Tutorials"> our CSS Tutorials</a> right away.</p> diff --git a/files/ru/learn/css/first_steps/getting_started/index.html b/files/ru/learn/css/first_steps/getting_started/index.html new file mode 100644 index 0000000000..30d495ad25 --- /dev/null +++ b/files/ru/learn/css/first_steps/getting_started/index.html @@ -0,0 +1,262 @@ +--- +title: Начало работы с CSS +slug: Learn/CSS/First_steps/Getting_started +tags: + - Beginner + - CSS + - Learn + - Классы + - Обучение + - Селекторы + - Синтаксис +translation_of: Learn/CSS/First_steps/Getting_started +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/First_steps/What_is_CSS", "Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps")}}</div> + +<p class="summary">В этой статье мы возьмем простой HTML-документ и применим к нему CSS, изучая некоторые практические вещи о языке.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Базовое програмное обеспечение</a>, базовые знания <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работа с файлами</a>, и базовые знания HTML (смотрите <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>.)</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Понять основы связывания CSS-документа с HTML-файлом и уметь выполнять простое форматирование текста с помощью CSS.</td> + </tr> + </tbody> +</table> + +<h2 id="Начнём_с_HTML">Начнём с HTML</h2> + +<p>Нашей отправной точкой является HTML-документ. Вы можете скопировать код снизу, если вы хотите работать на своем компьютере. Сохраните приведенный ниже код как <code>index.html</code> в папке на вашем компьютере.</p> + +<pre class="brush: html"><!doctype html> +<html lang="ru"> +<head> + <meta charset="utf-8"> + <title>Начало работы с CSS</title> +</head> + +<body> + + <h1>Я заголовок первого уровня</h1> + + <p>Это абзац. В нём есть <span>элемент span</span>, +а также <a href="http://example.com">ссылка</a>.</p> + + <p>Это второй абзац. Он содержит <em>акцентирующий</em> текст.</p> + + <ul> + <li>Элемент один</li> + <li>Элемент два</li> + <li>Элемент <em>три</em></li> + </ul> + +</body> + +</html> +</pre> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Если Вы читаете это на устройстве или в среде, где Вы не можете легко создавать файлы, не беспокойтесь — ниже представлены редакторы кода, чтобы вы могли написать код прямо здесь, на странице.</p> +</div> + +<h2 id="Добавление_CSS_в_наш_документ">Добавление CSS в наш документ</h2> + +<p>Самое первое, что нам нужно сделать, — это сообщить HTML-документу, что у нас есть некоторые правила CSS, которые мы хотим использовать. Существует три различных способа применения CSS к документу HTML, с которым Вы обычно сталкиваетесь, однако сейчас мы рассмотрим наиболее обычный и полезный способ сделать это — связать CSS с заголовком вашего документа.</p> + +<p>Создайте файл в той же папке, что и документ HTML, и сохраните его как <code>styles.css</code>. Расширение .css показывает, что это файл CSS.</p> + +<p>Чтобы связать styles.css с index.html, добавьте следующую строку где-то внутри{{htmlelement("head")}} HTML документа:</p> + +<pre class="brush: html"><link rel="stylesheet" href="styles.css"></pre> + +<p>Элемент {{htmlelement("link")}} сообщает браузеру, что у нас есть таблица стилей, используя атрибут <em>rel</em>, и местоположение этой таблицы стилей в качестве значения атрибута <em>href.</em> Вы можете проверить, работает ли CSS, добавив правило в <em>styles.css</em>. Используя Ваш редактор кода, добавьте следующее в ваш файл CSS:</p> + +<pre class="brush: css">h1 { + color: red; +}</pre> + +<p>Сохраните файлы HTML и CSS и перезагрузите страницу в веб-браузере. Заголовок первого уровня в верхней части документа теперь должен быть красным. Если это произойдет, поздравляю — Вы успешно применили CSS к документу HTML. Если этого не произойдет, внимательно проверьте, правильно ли Вы ввели всё.</p> + +<p>Вы можете продолжить работу в <code>styles.css</code> локально, или Вы можете использовать наш интерактивный редактор ниже, чтобы продолжить этот урок. Интерактивный редактор действует так, как если бы CSS на первой панели был связан с документом HTML, как это было в нашем документе выше.</p> + +<h2 id="Стилизация_HTML-элементов">Стилизация HTML-элементов</h2> + +<p>Делая наш заголовок красным, мы уже продемонстрировали, что можем нацеливать и стилизовать элемент HTML. Мы делаем это путем нацеливания на элемент<em> selector</em> — это селектор, который напрямую соответствует имени элемента HTML. Чтобы нацелиться на все абзацы в документе, Вы должны использовать селектор <code>p</code>. Чтобы сделать все абзацы зелёными, Вы должны использовать:</p> + +<pre class="brush: css">p { + color: green; +}</pre> + +<p>Вы можете выбрать несколько селекторов одновременно, разделив их запятыми. Если я хочу, чтобы все параграфы и все элементы списка были зелёными, моё правило выглядит так:</p> + +<pre class="brush: css">p, li { + color: green; +}</pre> + +<p>Попробуйте это в интерактивном редакторе ниже (отредактируйте поля кода) или в своём локальном документе CSS.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/started1.html", '100%', 900)}} </p> + +<h2 id="Изменение_поведения_элементов_по_умолчанию">Изменение поведения элементов по умолчанию</h2> + +<p>Когда мы смотрим на хорошо размеченный HTML-документ, даже такой простой, как наш пример, мы можем увидеть, как браузер делает HTML читаемым, добавив некоторые стили по умолчанию. Заголовки большие и жирные, в нашем списке есть маркеры. Это происходит потому, что в браузерах есть внутренние таблицы стилей, содержащие стили по умолчанию, которые по умолчанию применяются ко всем страницам; без них весь текст работал бы вместе, и мы должны были бы стилизовать всё с нуля. Все современные браузеры по умолчанию отображают HTML-контент практически одинаково.</p> + +<p>Однако Вам часто захочется что-то другое, кроме выбора, сделанного браузером. Это можно сделать, просто выбрав элемент HTML, который вы хотите изменить, и используя правило CSS, чтобы изменить его внешний вид. Хорошим примером является наш <code><ul></code> — неупорядоченный список. Он добавляет маркеры, и если я решу, что я не хочу эти маркеры, я могу удалить их вот так:</p> + +<pre class="brush: css">li { + list-style-type: none; +}</pre> + +<p>Попробуйте добавить это в свой CSS сейчас.</p> + +<p>Свойство <code>list-style-type</code> — это хорошее свойство, информацию о котором можно найти на MDN, чтобы увидеть, какие значения поддерживаются. Взгляните на страницу для <code><a href="/en-US/docs/Web/CSS/list-style-type">list-style-type</a></code> и Вы найдете интерактивный пример в верхней части страницы, чтобы опробовать некоторые другие значения, затем все допустимые значения будут подробно описаны ниже.</p> + +<p>Глядя на эту страницу, вы обнаружите, что помимо удаления маркеров списка Вы можете изменить их — попробуйте изменить их на квадратные маркеры, используя значение <code>square</code>.</p> + +<h2 id="Добавление_класса">Добавление класса</h2> + +<p>Пока у нас есть стилизованные элементы, основанные на их именах HTML-элементов. Это работает до тех пор, пока Вы хотите, чтобы все элементы этого типа в Вашем документе выглядели одинаково. В большинстве случаев это не так, и Вам нужно будет найти способ выбрать подмножество элементов, не меняя остальные. Самый распространенный способ сделать это — добавить класс к вашему HTML-элементу и нацелиться на этот класс.</p> + +<p>В своем HTML-документе добавьте Атрибут <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class">class</a> ко второму пункту списка. Ваш список теперь будет выглядеть так:</p> + +<pre class="brush: html; highlight[3]"><ul> + <li>Элемент один</li> + <li <strong>class="special"</strong>>Элемент два</li> + <li>Элемент <em>три</em></li> +</ul></pre> + +<p>В Вашем CSS Вы можете выбрать класс <code>special</code> к любому элементу на странице, чтобы он выгядел так же, как и этот элемент списка. Добавьте следующее в ваш файл CSS:</p> + +<pre class="brush: css">.special { + color: orange; + font-weight: bold; +}</pre> + +<p>Сохраните и обновите, чтобы увидеть результат.</p> + +<p>Вы можете захотеть, чтобы <span> в абзаце также был оранжевым и жирным. Попробуйте добавить класс "<code>special"</code>, затем перезагрузите страницу и посмотрите, что получится.</p> + +<p>Иногда Вы увидите правила с селектором, который перечисляет селектор HTML-элемента вместе с классом:</p> + +<pre class="brush: css">li.special { + color: orange; + font-weight: bold; +}</pre> + +<p>Этот синтаксис означает «предназначаться для любого элемента li, который имеет класс special». Если бы Вы сделали это, Вы бы больше не смогли применить класс к <code><span></code> или другому элементу, просто добавив к нему класс; Вы должны добавить этот элемент в список селекторов:</p> + +<pre class="brush: css">li.special, +span.special { + color: orange; + font-weight: bold; +}</pre> + +<p>Как Вы можете себе представить, некоторые классы могут быть применены ко многим элементам, и Вам не нужно постоянно редактировать свой CSS каждый раз, когда что-то новое должно принять этот стиль. Поэтому иногда лучше обойти элемент и просто обратиться к классу, если только Вы не знаете, что хотите создать некоторые специальные правила для одного элемента и, возможно, хотите убедиться, что они не применяются к другим элементам.</p> + +<h2 id="Стилизация_элементов_на_основе_их_расположения_в_документе">Стилизация элементов на основе их расположения в документе</h2> + +<p>Есть моменты, когда Вы хотите, чтобы что-то выглядело иначе, в зависимости от того, где оно находится в документе. Здесь есть несколько селекторов, которые могут Вам помочь, но сейчас мы рассмотрим только пару. В нашем документе два элемента <code><em></code> — один внутри абзаца, а другой внутри элемента списка. Чтобы выбрать только <code><em></code> который вложен в элемент <code><li></code>, я могу использовать селектор под названием <strong>descendant combinator (комбинатор-потомок)</strong>, который просто принимает форму пробела между двумя другими селекторами.</p> + +<p>Добавьте следующее правило в таблицу стилей.</p> + +<pre class="brush: css">li em { + color: rebeccapurple; +}</pre> + +<p>Этот селектор выберет любой элемент <code><em></code>, который находится внутри (потомка) <code><li></code>. Итак, в Вашем примере документа Вы должны найти, что <code><em></code> в третьем элементе списка теперь фиолетовый, но тот, который находится внутри абзаца, не изменился.</p> + +<p>Ещё можно попробовать стилизовать абзац, когда он идет сразу после заголовка на том же уровне иерархии в HTML. Для этого поместите <code>+</code> (<strong>соседний братский комбинатор</strong>) между селекторами.</p> + +<p>Попробуйте также добавить это правило в таблицу стилей:</p> + +<pre class="brush: css">h1 + p { + font-size: 200%; +}</pre> + +<p>Пример ниже включает в себя два правила выше. Попробуйте добавить правило, чтобы сделать элемент span красный, если он внутри абзаца. Вы узнаете, правильно ли Вы это сделали, так как промежуток в первом абзаце будет красным, но цвет в первом элементе списка не изменит цвет.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/started2.html", '100%', 1100)}}</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Как Вы можете видеть, CSS даёт нам несколько способов нацеливания на элементы, и мы пока только слегка изучили его! Мы будем внимательно смотреть на все эти селекторы и многое другое в нашей статье <a href="https://developer.cdn.mozilla.net/ru/docs/Learn/CSS/Building_blocks/%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B">Селекторы</a> позже в нашем курсе.</p> +</div> + +<h2 id="Стилизация_элементов_на_основе_состояния">Стилизация элементов на основе состояния</h2> + +<p>Последний тип стилей, который мы рассмотрим в этом уроке, — это возможность стилизовать элементы в зависимости от их состояния. Прямым примером этого является стиль ссылок. Когда мы создаём ссылку, мы должны нацелить элемент <code><a href="/en-US/docs/Web/HTML/Element/a"><a></a></code> (якорь). Он имеет различные состояния в зависимости от того, посещается ли он, посещается, находится над ним, фокусируется с помощью клавиатуры или в процессе нажатия (активации). Вы можете использовать CSS для нацеливания на эти разные состояния — CSS-код ниже отображает невидимые ссылки розового цвета и посещенные ссылки зелёного цвета.</p> + +<pre class="brush: css">a:link { + color: pink; +} + +a:visited { + color: green; +}</pre> + +<p>Вы можете изменить внешний вид ссылки, когда пользователь наводит на неё курсор, например, удалив подчеркивание, что достигается с помощью следующего правила:</p> + +<pre class="brush: css">a:hover { + text-decoration: none; +}</pre> + +<p>В приведённом ниже примере Вы можете поиграть с разными значениями для разных состояний ссылки. Я добавил к нему правила, приведенные выше, и теперь понимаю, что розовый цвет довольно легкий и трудно читаемый — почему бы не изменить его на лучший цвет? Можете ли Вы сделать ссылки жирным шрифтом?</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/started3.html", '100%', 900)}} </p> + +<p>Мы удалили подчеркивание на нашей ссылке при наведении курсора. Вы можете удалить подчеркивание из всех состояний ссылки. Однако стоит помнить, что на реальном сайте Вы хотите, чтобы посетители знали, что ссылка является ссылкой. Оставив подчеркивание на месте, люди могут понять, что на какой-то текст внутри абзаца можно нажимать — к такому поведению они привыкли. Как и всё в CSS, существует возможность сделать документ менее доступным с Вашими изменениями — мы постараемся выделить потенциальные подводные камни в соответствующих местах.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Вы часто будете видеть упоминание о <a href="https://developer.mozilla.org/ru/docs/Learn/%D0%94%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BD%D0%BE%D1%81%D1%82%D1%8C">доступности</a> в этих уроках и по всей MDN. Когда мы говорим о доступности, мы имеем в виду требование, чтобы наши веб-страницы были понятными и доступными для всех.</p> + +<p>Ваш посетитель вполне может быть на компьютере с мышью или сенсорной панелью или на телефоне с сенсорным экраном. Либо они могут использовать программу чтения с экрана, которая считывает содержимое документа, либо им может потребоваться использовать текст значительно большего размера, либо перемещаться по сайту только с помощью клавиатуры.</p> + +<p>Простой HTML-документ, как правило, доступен каждому — когда Вы начинаете оформлять этот документ, важно, чтобы Вы не сделали его менее доступным.</p> +</div> + +<h2 id="Сочетание_селекторов_и_комбинаторов">Сочетание селекторов и комбинаторов</h2> + +<p>Стоит отметить, что Вы можете комбинировать несколько селекторов и комбинаторов вместе. Вот пример:</p> + +<pre class="brush: css">/* выбирает любой <span> внутри <p>, который находится внутри <article> */ +article p span { ... } + +/* выбирает любой <p>, который идет сразу после <ul>, который идет сразу после <h1> */ +h1 + ul + p { ... }</pre> + +<p>Вы также можете комбинировать несколько типов вместе. Попробуйте добавить следующее в ваш код:</p> + +<pre class="brush: css">body h1 + p .special { + color: yellow; + background-color: black; + padding: 5px; +}</pre> + +<p>Это будет стиль любого элемента с классом <code>special</code>, который находится внутри <code><p></code>, который приходит сразу после <code><h1></code>, который находится внутри <code><body></code>. Уф!</p> + +<p>В оригинальном HTML, который мы предоставили, единственный элемент в стиле <code><span class="special"></code>.</p> + +<p>Не беспокойтесь, если это покажется сложным — Вы скоро начнете понимать это, когда будете писать больше на CSS.</p> + +<h2 id="Завершение">Завершение</h2> + +<p>В этом уроке мы рассмотрели несколько способов стилизации документа с использованием CSS. Мы будем развивать эти знания по мере прохождения остальных уроков. Однако Вы уже знаете достаточно, чтобы стилизовать текст, применять CSS на основе различных способов нацеливания на элементы в документе и искать свойства и значения в документации MDN.</p> + +<p>На следующем уроке мы рассмотрим структуру CSS.</p> + +<p>{{PreviousMenuNext("Learn/CSS/First_steps/What_is_CSS", "Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/%D0%A7%D1%82%D0%BE_%D1%82%D0%B0%D0%BA%D0%BE%D0%B5_CSS">Что такое CSS?</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/Getting_started">Начало работы с CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured">Как структурирован CSS</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/How_CSS_works">Как работает CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">Используя ваши новые знания</a></li> +</ol> diff --git a/files/ru/learn/css/first_steps/how_css_works/index.html b/files/ru/learn/css/first_steps/how_css_works/index.html new file mode 100644 index 0000000000..a0ff236f45 --- /dev/null +++ b/files/ru/learn/css/first_steps/how_css_works/index.html @@ -0,0 +1,163 @@ +--- +title: Как работает CSS +slug: Learn/CSS/First_steps/How_CSS_works +tags: + - Beginner + - CSS + - DOM + - DOM дерево + - Learn + - Начинающий + - Обучение + - дерево +translation_of: Learn/CSS/First_steps/How_CSS_works +--- +<p>{{LearnSidebar}}<br> + {{PreviousMenuNext("Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps/Using_your_new_knowledge", "Learn/CSS/First_steps")}}</p> + +<p class="summary">Мы уже изучили основы CSS, для чего он нужен и как создавать простые таблицы стилей. В этом уроке мы посмотрим, как браузер обрабатывает CSS и HTML и выводит содержимое на веб-страницу.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Основы компьютерной грамотности, <a href="/ru/docs/Learn/Getting_started_with_the_web/Установка_базового_программного_обеспечения">базовое программное обеспечение</a>, умение <a href="/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">умение работать с файлами</a> и начальные знания HTML (рекомендуется изучить <a href="/ru/docs/Learn/HTML/Введение_в_HTML">Введение в HTML</a>).</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Понимать основы того, как браузер анализирует CSS и HTML и что происходит когда браузер встречает неизвестные CSS стили</td> + </tr> + </tbody> +</table> + +<h2 id="Как_работает_CSS">Как работает CSS?</h2> + +<p>Когда браузер отображает документ, он должен совместить его содержимое с его стилями. Этот процесс идет в несколько этапов, о которых мы сейчас поговорим. Держите в уме, что это очень упрощенная версия того как браузер действительно загружает веб-страницу, а также то, что разные браузеры делают это по разному. Но, происходит, грубо говоря, следующее:</p> + +<ol> + <li>Браузер получает HTML-страницу (например, из Интернета)</li> + <li>Преобразует {{Glossary("HTML")}} в {{Glossary("DOM")}} (<em>Document Object Model</em>). DOM (или DOM-дерево) - это представление страницы в памяти компьютера. Подробнее на DOM мы остановимся чуть позже.</li> + <li>Затем браузер забирает все ресурсы и описания, связанные с HTML-документом, например: встроенные картинки, видео ... и стили CSS! JavaScript присоединяется чуть позже и мы пока не будем говорить об этом, чтобы все не усложнять.</li> + <li>После этого браузер анализирует полученный CSS код, сортирует описанные там правила в зависимости от их селекторов и раскладывает их в различные «корзины»: элементы, классы, идентификаторы(ID) и т.п. Основываясь на найденных селекторах браузер понимает какие правила относятся к определенным «узлам» в DOM-дереве и применяет их по мере необходимости (этот промежуточный шаг называют «формированием дерева представления» или «формированием дерева рендеринга»)</li> + <li>Дерево представления (<em>render tree</em>) формируется в том порядке, в каком оно затем должно будет отображаться, когда все правила будут применены.</li> + <li>Затем происходит визуальное отображение контента на странице (этот этап называется «отрисовкой»)</li> +</ol> + +<p>Диаграмма демонстрирует этот процесс.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/17080/Browser_simple_rendering_pipeline__ru.png" style="height: 655px; max-width: 635px; width: 1366px;"></p> + +<h2 id="DOM-дерево">DOM-дерево</h2> + +<p>DOM напоминает дерево. Каждый элемент, атрибут, отрывок текста становится {{Glossary("Node/DOM","DOM node")}} в разметке. DOM-узлы определяются их отношением с другими узлами. Некоторые родительские элементы имеют дочерние, а у дочерних элементов есть братские.</p> + +<p>Понимание DOM позволит вам разрабатывать, отлаживать и поддерживать ваш CSS, потому что именно в DOM-дереве Ваши таблицы стилей и код встречаются. Когда вы начнете работать с браузерным DevTools(инструменты для разработки) вы будете перемещаться по DOM при выборе элементов чтобы увидеть какие правила применяются.</p> + +<h2 id="Как_представлено_DOM-дерево">Как представлено DOM-дерево</h2> + +<p>Вместо длинного, нудного объяснения взглянем лучше на пример, чтобы понять, как HTML-код преобразуется в DOM.</p> + +<p>Возьмём следующий пример:</p> + +<pre class="brush: html notranslate"><p> + Let's use: + <span>Cascading</span> + <span>Style</span> + <span>Sheets</span> +</p> +</pre> + +<p>В DOM-дереве узел, соответствующий элементу <code><p></code>, — это родительский элемент. Его дочерние элементы — текст и три элемента <code><span></code>. Узлы <code>SPAN</code> также будут родителями — с текстом в качестве дочерних элементов:</p> + +<pre class="notranslate">P +├─ "Let's use:" +├─ SPAN +| └─ "Cascading" +├─ SPAN +| └─ "Style" +└─ SPAN + └─ "Sheets" +</pre> + +<p>Вот как браузер преобразует HTML-код — он загружает DOM-дерево, и в результате мы получим это:</p> + +<p>{{EmbedLiveSample('A_real_DOM_representation', '100%', 55)}}</p> + +<div class="hidden"> +<pre class="brush: css notranslate">p {margin:0;}</pre> +</div> + +<h2 id="Добавление_CSS_в_DOM">Добавление CSS в DOM</h2> + +<p>Допустим, мы добавили таблицу стилей к нашему примеру:</p> + +<pre class="brush: html notranslate"><p> + Let's use: + <span>Cascading</span> + <span>Style</span> + <span>Sheets</span> +</p></pre> + +<p>А вот CSS-код:</p> + +<pre class="brush: css notranslate">span { + border: 1px solid black; + background-color: lime; +}</pre> + +<p>Браузер загрузит HTML-код, преобразует его в DOM и только потом загрузит CSS. Так как у нас всего одно правило, браузер загрузит CSS очень быстро! Это правило будет добавлено к каждому из трёх элементов <code><span></code>. После этого информация будет отображена на экране.</p> + +<p>Новый результат:</p> + +<p>{{EmbedLiveSample('Applying_CSS_to_the_DOM', '100%', 55)}}</p> + +<p>В статье <a href="/ru/docs/Learn/CSS/Building_blocks/Debugging_CSS">Отладка CSS</a> мы будем использовать браузер DevTools для отладки CSS.</p> + +<h2 id="Что_происходит_когда_браузер_не_понимает_CSS">Что происходит, когда браузер не понимает CSS?</h2> + +<p><a href="/ru/docs/Learn/CSS/First_steps/Что_такое_CSS#Поддержка_браузера">В предыдущем уроке</a> я упомянул, что некоторые браузеры могут не поддерживать новые функции CSS. Вдобавок не все используют новейшие версии браузеров. Зная, что CSS разрабатывается всё время, Вы можете поразиться и крайне ужаснуться тому, что происходит, если браузер не распознаёт объявление или селектор. Что же произойдёт?</p> + +<p>— Да ничего: браузер просто пропустит это!</p> + +<p>Если браузер встретит свойство, которое он не понимает, он просто-напросто проигнорирует его и двинется дальше. Он сделает так, если Вы допустите опечатку или ошибку в свойстве или значении или если он не поддерживает какое-либо свойство или значение.</p> + +<p>Если же браузер встретит селектор, который он не распознаёт, то он просто пропустит данное правило и двинется дальше.</p> + +<p>Ниже я использовал британское написание слова <em>color</em>, что делает свойство некорректным. Поэтому текст не будет синим. Однако всё остальное будет работать; пропущено только недействительное свойство.</p> + +<div id="Skipping_example"> +<pre class="brush: html notranslate"><p> I want this text to be large, bold and blue.</p></pre> + +<pre class="brush: css notranslate">p { + font-weight: bold; + colour: blue; /* некорректное написание свойства цвета */ + font-size: 200%; +}</pre> +</div> + +<p>{{EmbedLiveSample('Skipping_example', '100%', 200)}}</p> + +<p>Такое поведение можно использовать, например, при добавлении новых функций CSS в качестве дополнения, причём Вы будете уверены, что ничего не сломается, если браузер не распознает элемент. Вы можете использовать два правила с одинаковыми уровнями спецификации: одно — в качестве альтернативы для случая, если браузер не поддерживает нововведение.</p> + +<p>Это хорошо применяется, если Вы хотиете использовать величину, не использующуюся везде в документе. К примеру, некоторые старые браузеры не поддерживают <code>calc()</code> как значение. Я добавлю резерв — знаение в px, затем задам ширину с помощью функции <code>calc()</code>, равной <code>100% - 50px</code>. Старые браузеры используют пиксельное значение, потому что не распознают <code>calc()</code>. Новые браузеры используют <code>calc()</code> так как эта строка появляется позже в каскаде.</p> + +<pre class="brush: css notranslate">.box { + width: 500px; + width: calc(100% - 50px); +}</pre> + +<h2 id="Завершение">Завершение</h2> + +<p>Вы почти закончили модуль; осталось только одно. В следующей статье Вы попрактикуетесь в <a href="/ru/docs/Learn/CSS/First_steps/Using_your_new_knowledge">использовании ваших новых знаний</a>.</p> + +<p>{{PreviousMenuNext("Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps/Using_your_new_knowledge", "Learn/CSS/First_steps")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="/ru/docs/Learn/CSS/First_steps/Что_такое_CSS">Что такое CSS?</a></li> + <li><a href="/ru/docs/Learn/CSS/First_steps/Getting_started">Начало работы с CSS</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps/%D0%9A%D0%B0%D0%BA_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD_CSS">Как структурирован CSS </a></li> + <li><a href="/ru/docs/Learn/CSS/First_steps/How_CSS_works">Как работает CSS</a></li> + <li><a href="/ru/docs/Learn/CSS/First_steps/Using_your_new_knowledge">Использование ваших новых знаний</a></li> +</ol> diff --git a/files/ru/learn/css/first_steps/index.html b/files/ru/learn/css/first_steps/index.html new file mode 100644 index 0000000000..2e0ed35d7e --- /dev/null +++ b/files/ru/learn/css/first_steps/index.html @@ -0,0 +1,54 @@ +--- +title: Введение в CSS +slug: Learn/CSS/First_steps +tags: + - Beginner + - CSS + - Landing + - Learn + - first steps + - Введение + - Начинающий +translation_of: Learn/CSS/First_steps +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">CSS (каскадные таблицы стилей) используется для стилизации и компоновки веб-страниц - например, для изменения шрифта, цвета, размера и интервала содержимого, разделения его на несколько столбцов или добавления анимации и других декоративных элементов. Этот модуль обеспечивает хорошее начало вашего пути к освоению CSS с основами того, как он работает, как выглядит синтаксис и как вы можете начать использовать его для добавления стилей в HTML.</p> + +<h2 id="Необходимые_условия">Необходимые условия</h2> + +<p>Перед запуском этого модуля вы должны иметь:</p> + +<ol> + <li>Базовое знакомство с использованием компьютеров и пассивным использованием Интернета (то есть, просматривая его, потребляя контент).</li> + <li>Базовая рабочая среда, описанная в разделе <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового программного обеспечения</a>, и понимание того, как создавать файлы и управлять ими, подробно описано в разделе <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a>.</li> + <li>Основное знакомство с HTML, как описано в модуле <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>.</li> +</ol> + +<div class="note"> +<p><strong>Примечание:</strong> Если вы работаете на компьютере / планшете / другом устройстве, на котором у вас нет возможности создавать свои собственные файлы, вы можете опробовать (большую часть) примеры кода в онлайн-программах кодирования, таких как JSBin или Thimble.</p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<p>Этот модуль содержит следующие статьи, в которых вы ознакомитесь со всеми основными теориями CSS и сможете проверить некоторые навыки.</p> + +<dl> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/%D0%A7%D1%82%D0%BE_%D1%82%D0%B0%D0%BA%D0%BE%D0%B5_CSS">Что такое CSS?</a></dt> + <dd><strong>{{Glossary("CSS")}}</strong> (Каскадные таблицы стилей) позволяет создавать великолепно выглядящие веб-страницы, но как же это работает? Эта статья объясняет, что такое CSS с помощью простого примера синтаксиса, а также охватывает некоторые ключевые термины о языке.</dd> + <dt><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps/Getting_started">Начало работы с CSS</a></dt> + <dd>В этой статье мы возьмем простой HTML-документ и применим к нему CSS, изучая некоторые практические вещи о языке.</dd> + <dt><a href="https://developer.cdn.mozilla.net/ru/docs/Learn/CSS/First_steps/%D0%9A%D0%B0%D0%BA_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD_CSS">Как структурирован CSS</a></dt> + <dd>Теперь, когда у вас есть представление о том, что такое CSS и как его использовать, пришло время немного углубиться в структуру самого языка. Мы уже встречали множество концепций, обсуждаемых здесь; Вы можете вернуться к этому, чтобы повторить, если вы находите какие-либо более поздние концепции запутанными.</dd> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/How_CSS_works">Как работает CSS</a></dt> + <dd>Мы изучили основы CSS — для чего он нужен и как писать простые таблицы стилей. В этом уроке мы рассмотрим, как браузер берет CSS и HTML и превращает их в веб-страницу.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">Использование ваших новых знаний</a></dt> + <dd>С учетом того, что вы узнали за последние несколько уроков, вы должны обнаружить, что вы можете форматировать простые текстовые документы с использованием CSS, чтобы добавить к ним свой собственный стиль. Эта статья дает вам шанс сделать это.</dd> +</dl> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<dl> + <dt><a href="https://teach.mozilla.org/activities/intermediate-web-lit/">Intermediate Web Literacy 1: Intro to CSS</a></dt> + <dd>Отличный базовый курс от Mozilla, в котором рассматриваются и тестируются многие навыки, о которых говорилось в модуле <em>Введение в CSS</em>. Узнайте о стилях элементов HTML на веб-странице, селекторах CSS, атрибутах и значениях.</dd> +</dl> diff --git a/files/ru/learn/css/first_steps/using_your_new_knowledge/index.html b/files/ru/learn/css/first_steps/using_your_new_knowledge/index.html new file mode 100644 index 0000000000..015846a9ff --- /dev/null +++ b/files/ru/learn/css/first_steps/using_your_new_knowledge/index.html @@ -0,0 +1,104 @@ +--- +title: Использование ваших новых знаний +slug: Learn/CSS/First_steps/Using_your_new_knowledge +tags: + - Beginner + - CSS + - Learn + - Playground + - Начинающий + - Обучение +translation_of: Learn/CSS/First_steps/Using_your_new_knowledge +--- +<p>{{LearnSidebar}}{{PreviousMenu("Learn/CSS/First_steps/How_CSS_works", "Learn/CSS/First_steps")}}</p> + +<dl> + <dd>С учетом того что вы узнали за последние несколько уроков, вы должны обнаружить, что вы можете форматировать простые текстовые документы с использованием CSS, чтобы добавить к ним свой собственный стиль. Эта статья дает вам возможность сделать это.</dd> +</dl> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Перед тем как начать, вы должны разобраться в основах CSS и HTML (смотрите <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>).</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Попрактиковать использование CSS с вашими новыми знаниями.</td> + </tr> + </tbody> +</table> + +<h2 id="Перед_началом">Перед началом</h2> + +<p>Вы можете писать код в редакторе ниже или <a href="https://github.com/mdn/css-examples/blob/master/learn/getting-started/biog-download.html/">скачать исходный код</a>, чтобы работать в вашем собственном редакторе. Это страница с кодом HTML и CSS внутри него. Если вам так удобнее, вы можете переместить CSS в отдельный файл на вашем компьютере. Или вы можете использовать онлайн-редакторы, такие как <a href="https://codepen.io/" rel="noopener">CodePen</a>, <a href="https://jsfiddle.net/" rel="noopener">jsFiddle</a> или <a href="https://glitch.com/" rel="noopener">Glitch</a>.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Если у вас не получается, попросите о помощи — читайте раздел {{anch("Помощь")}} с кодом ниже.</p> +</div> + +<h2 id="Работа_с_CSS">Работа с CSS</h2> + +<p>В следующем примере демонстрируется биография, стилизованная с помощью CSS. Каждое использованное мной свойство CSS — ссылка на соответствующую страницу MDN.</p> + +<ul> + <li>{{cssxref("font-family")}}</li> + <li>{{cssxref("color")}}</li> + <li>{{cssxref("border-bottom")}}</li> + <li>{{cssxref("font-weight")}}</li> + <li>{{cssxref("font-size")}}</li> + <li>{{cssxref("text-decoration")}}</li> +</ul> + +<p>Я использовал разные селекторы, такие как h1 и h2, а также создал класс для названия профессии для его стилизации.</p> + +<p>Измените значения свойств CSS, чтобы поменять внешний вид биографии.</p> + +<ol> + <li>Сделайте заголовок розовым, используя CSS-цвет <code>hotpink</code>.</li> + <li>Значение свойства заголовка {{cssxref("border-bottom")}} сделайте пунктирным (10px dotted) и добавьте цвет <code>purple</code>.</li> + <li>Примените к подзаголовку <code><h2></code> курсив.</li> + <li>Установите цвет <code>#eeeeee</code> для фона {{cssxref("background-color")}} маркированного списка с контактными данными и значение 5px solid purple для {{cssxref("border")}}. Используйте {{cssxref("padding")}}, чтобы отделить содержимое блока от границы.</li> + <li>Сделайте ссылки <code>зелёными</code> при наведении.</li> +</ol> + +<p>У Вас должно получиться примерно как-то так:</p> + +<p><img alt="Screenshot of how the example should look after completing the assessment." src="https://mdn.mozillademos.org/files/17035/learn-css-basics-assessment.png" style="height: 1199px; width: 1104px;"></p> + +<p>После этого попробуйте использовать селекторы, не указанные здесь, но описанные в <a href="https://developer.mozilla.org/ru/docs/Web/CSS/Reference">Руководстве по CSS</a>. Не бойтесь ошибок — практикуйтесь!</p> + +<p>Помните: тут нет неверного решения — сейчас вы предоставлены сами себе; развлекайтесь!</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/biog.html", '100%', 1600)}} </p> + +<h2 id="Помощь">Помощь</h2> + +<p>Если Вы хотите, чтобы вашу работу оценили, или вы не справляетесь, и вам нужна помощь:</p> + +<ol> + <li>Загрузите Ваш код на <a href="https://codepen.io/" rel="noopener">CodePen</a>, <a href="https://jsfiddle.net/" rel="noopener">jsFiddle</a> или <a href="https://glitch.com/" rel="noopener">Glitch</a>.</li> + <li>Напишите пост с просьбой о помощи и / или оценке на <a href="https://discourse.mozilla.org/c/mdn">форуме MDN</a>. Добавьте тег "learning" к вашему посту, чтобы нам легче было его найти. В Вашем посте должны быть: + <ul> + <li>Заголовок с описанием наподобие "Assessment wanted for CSS First Steps".</li> + <li>Описание того, что Вам нужно, — к примеру, что Вы уже пробовали, что у Вас не получается и Вам нужна помощь.</li> + <li>Ссылка на ваш код в онлайн-редакторе.</li> + <li>Ссылка на страницу о помощи, чтобы мы смогли помочь Вам с вашим вопросом.</li> + </ul> + </li> +</ol> + +<h2 id="Что_дальше">Что дальше?</h2> + +<p>Поздравляем Вас с завершением первого модуля! Теперь Вы неплохо разбираетесь в CSS и можете разобраться в таблицах стилей. В следующем модуле, <a href="/ru/docs/Learn/CSS/Building_blocks">Как устроен CSS</a>, мы глубже разберёмся в некоторых аспектах языка.</p> + +<p>{{PreviousMenu("Learn/CSS/First_steps/How_CSS_works", "Learn/CSS/First_steps")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS">Что такое CSS?</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">Начало работы с CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">Как струтурирован CSS</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/How_CSS_works">Как работает CSS</a></li> +</ol> diff --git a/files/ru/learn/css/first_steps/как_структурирован_css/index.html b/files/ru/learn/css/first_steps/как_структурирован_css/index.html new file mode 100644 index 0000000000..d2c60edcfb --- /dev/null +++ b/files/ru/learn/css/first_steps/как_структурирован_css/index.html @@ -0,0 +1,528 @@ +--- +title: Как структурирован CSS +slug: Learn/CSS/First_steps/Как_структурирован_CSS +tags: + - Beginner + - CSS + - HTML + - Learn + - Комментарии + - Обучение + - Свойство + - Структура + - значения + - отступ + - селектор + - сокращение +translation_of: Learn/CSS/First_steps/How_CSS_is_structured +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps/How_CSS_works", "Learn/CSS/First_steps")}}</div> + +<p class="summary">Теперь, когда у вас есть представление о том, чем является CSS, и о его основах, настало время посмотреть немного глубже в структуру самого языка. Нам уже встречались многие из обсуждаемых здесь концепций; вы можете вернуться к этому, чтобы разобраться, если вы обнаружите какие-либо более поздние концепции запутанными.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Базовое програмное обеспечение</a>, базовые знания <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работа с файлами</a>, и базовые знания HTML (статья <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>), и знание о том <a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/How_CSS_works">Как работает CSS</a></td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Подробно узнать основные синтаксические структуры CSS.</td> + </tr> + </tbody> +</table> + +<h2 id="Применение_CSS_к_вашему_HTML">Применение CSS к вашему HTML</h2> + +<p>Первое, что мы рассмотрим, это три метода применения CSS к документу.</p> + +<h3 id="Внешняя_таблица_стилей">Внешняя таблица стилей</h3> + +<p>В статье <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps/Getting_started">Начало работы с CSS</a> мы связывали внешнюю таблицу стилей с нашей страницей. Это самый распространенный и полезный способ крепления CSS к документу, так вы можете привязать CSS сразу к нескольким страницам, что позволяет стилизовать их всё с той же таблицей стилей. В большинстве случаев различные страницы сайта будут выглядеть почти так же, поэтому вы можете использовать один и тот же набор правил для основного вида.</p> + +<p>Внешняя таблица стилей - это когда у вас есть CSS отдельным файлом с расширением <code>.css</code>, и ссылка на него из HTML-элемента <code><link></code>:</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Я пробую писать CSS</title> + <link rel="stylesheet" href="styles.css"> + </head> + <body> + <h1>Привет!</h1> + <p>Это мой первый опыт в CSS</p> + </body> +</html></pre> + +<p>Файл CSS может выглядеть следующим образом:</p> + +<pre class="brush: css notranslate">h1 { + color: blue; + background-color: yellow; + border: 1px solid black; +} + +p { + color: red; +}</pre> + +<p>Атрибут <code>href</code> элемента {{htmlelement("link")}} должен ссылаться на файл в файловой системе.</p> + +<p>В приведенном выше примере файл CSS находится в той же папке, что и HTML-документ, но вы можете поместить его куда-нибудь ещё и настроить относительный путь, например:</p> + +<pre class="brush: html notranslate"><!-- Файл находится внутри под-директории <em>styles</em>, находящейся в текущей директории --> +<link rel="stylesheet" href="styles/style.css"> + +<!-- Файл — внутри под-директории <em>styles</em> внутри под-под-директории <em>general</em> и так далее --> +<link rel="stylesheet" href="styles/general/style.css"> + +<!-- Вверх на один уровень в директории, затем направиться в под-директорию <em>styles</em> --> +<link rel="stylesheet" href="../styles/style.css"></pre> + +<h3 id="Внутренняя_таблица_стилей">Внутренняя таблица стилей</h3> + +<p>Внутренняя таблица стилей, где у вас нет внешнего файла CSS, но вместо этого CSS помещён внутри элемента {{htmlelement("style")}}, содержащейся внутри HTML {{htmlelement("head")}}.</p> + +<p>Таким образом, HTML будет выглядеть вот так:</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Я пробую писать CSS</title> + <style> + h1 { + color: blue; + background-color: yellow; + border: 1px solid black; + } + + p { + color: red; + } + </style> + </head> + <body> + <h1>Привет!</h1> + <p>Это мой первый опыт в CSS</p> + </body> +</html></pre> + +<p>Это может быть полезно в некоторых обстоятельствах (возможно, вы работаете с системой управления контентом, где вы не можете изменить CSS-файлы непосредственно), но это менее эффективно, чем внешние таблицы стилей: CSS будет необходимо прописывать отдельно для каждой страницы и изменять, если требуются изменения.</p> + +<h3 id="Встроенные_стили">Встроенные стили</h3> + +<p>Встроенные стили являются правилами CSS, которые влияют только на один элемент, содержащиеся в атрибуте <code>style</code>:</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Я пробую писать CSS</title> + </head> + <body> + <h1 style="color: blue;background-color: yellow;border: 1px solid black;">Привет!</h1> + <p style="color:red;">Это мой первый опыт в CSS</p> + </body> +</html></pre> + +<p><strong>Пожалуйста, не делайте этого! </strong>Это очень плохо для технического обслуживания (вам, возможно, придётся обновить одну и ту же информацию несколько раз в одном документе), а также смешивает ваши презентационные данные CSS с структурной информацией HTML, что делает код трудным для чтения и понимания. Хранение различных типов кода отделено делает работу гораздо более лёгкой для всех, кто работает над кодом.</p> + +<p>Есть несколько мест, где встроенные стили являются более распространенными или даже желательными. Вам, возможно, придется прибегнуть к использованию их, если ваша рабочая среда сильно ограничена (возможно, ваша CMS позволяет редактировать только HTML-тело). Вы также увидите, как они использовали много в HTML электронной почте, чтобы получить совместимость с таким количеством почтовых клиентов, со скольким это возможно.</p> + +<h2 id="Игра_с_CSS_в_этой_статье">Игра с CSS в этой статье</h2> + +<p>Существует много возможностей, чтобы поиграть с CSS в этой статье. Для этого мы рекомендуем создать новый каталог / папку на вашем компьютере и внутри него создать копии следующих двух файлов:</p> + +<p>index.html:</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html lang="ru"> + <head> + <meta charset="utf-8"> + <title>Я пробую писать CSS</title> + <link rel="stylesheet" href="styles.css"> + </head> + <body> + + <p>Пишите сюда свой код</p> + + </body> +</html></pre> + +<p>styles.css:</p> + +<pre class="brush: css notranslate">/* Пишите сюда свой код */ + +p { + color: red; +}</pre> + +<p>Затем, когда вы столкнетесь с CSS и захотите поэкспериментировать со стилями, измените содержимое <code><body></code> HTML-документа и начинайте добавлять CSS-стили внутри вашего файла CSS.</p> + +<p>Если вы не используете систему, в которой вы можете легко создавать файлы, вы можете вместо этого использовать интерактивный редактор ниже чтобы экспериментировать.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/experiment-sandbox.html", '100%', 800)}} </p> + +<p>Читайте дальше и получайте удовольствие!</p> + +<h2 id="Селекторы">Селекторы</h2> + +<p>Говоря о CSS, нельзя не упомянуть о селекторах, о некоторых типах которых мы уже говорили в руководстве <a href="/ru/docs/Learn/CSS/First_steps/Getting_started">Начало работы с CSS</a>. Селектор — это то, как мы обозначаем что-либо в нашем HTML-документе, чтобы стилизовать его. Если стиль не применился, то это, скорее всего, потому, что селектор в таблицах стилей не совпал с тем, что в HTML-документе.</p> + +<p>Каждое CSS-правило начинается с одного или нескольких селекторов, отделяемых друг от друга запятыми, чтобы дать понять браузеру, к чему применять стили. В следующем примере перечислены стандартные селекторы:</p> + +<pre class="brush: css notranslate">h1 /* это селектор тегов */ +a:link /* это селектор ссылок */ +.manythings /* это селектор классов (классы применяются тогда, когда необходимо применить правило к нескольким элементам) */ +#onething /* это селектор идентификаторов (они применяются, когда правило относится к одному элементу) */ +* /* уневерсальный селектор */ +.box p /* селектор потомков */ +.box p:first-child /* селектор потомков + селектор псевдоклассов */ +h1, h2, .intro /* пречисление селекторов */ +</pre> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Вы узнаете больше о селекторах в руководстве <a href="/ru/docs/Web/CSS/CSS_%D0%A1%D0%B5%D0%BB%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B">CSS-селекторы</a> в следующем модуле.</p> +</div> + +<h3 id="Спецификация">Спецификация</h3> + +<p>Иногда может случаться такое, что два селектора будут относиться к одному и тому же элементу HTML. Смотрите: в примере ниже я задал правило для элемента <code>p</code> — он будет синим; также я задал класс, который сделает элемент красным:</p> + +<pre class="brush: css notranslate">.special { + color: red; +} + +p { + color: blue; +}</pre> + +<p>А теперь допустим, что в нашем HTML-коде у нас есть абзац <code>p</code> с классом <code>special</code>. Оба правила могут быть добавлены: так какое же одержит верх? Как вы думаете, какого цвета будет надпись?</p> + +<pre class="brush: html notranslate"><p class="special">Какого же я цвета?</p></pre> + +<p>В языке CSS есть правила, которые определяют, какое правило "выиграет" в случае подобного столкновения — они называются <strong>каскадами</strong>, или <strong>спецификациями</strong>. В примере ниже мы задали два правила для селектора <code>p</code>, но в итоге текст будет синим: объвление, делающее надпись синей, появилось позже того, которое делает её красной. Это каскад в действии.</p> + +<pre class="brush: css notranslate">p { + color: red; +} + +p { + color: blue; +}</pre> + +<p>А в примере с селектором класса и селектором тега победит селектор класса — даже если он объявлен раньше.</p> + +<p><strong>Попрактикуйтесь сами — добавьте два правила для параграфа <code>p { ... }</code> в вашу таблицу стилей. Затем добавьте класс к одному элементу <code>p</code> и попробуйте применить к нему какой-нибудь стиль.</strong></p> + +<p>Понимание каскадов, или правил, улучшается с практикой. В статье <a href="/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Каскад и наследование</a> я хорошенько объясню, как определить уровень спецификации. А пока что запомните, что иногда CSS не применяется так, как вы того хотели бы, так как у чего-то в таблице стилей больший уровень спецификации.</p> + +<h2 id="Свойства_и_значения">Свойства и значения</h2> + +<p>Если говорить в общем, CSS строится на двух его составляющих:</p> + +<dl> + <dt><strong>Свойства</strong> </dt> + <dd>Определяют, какую характеристику вы желаете изменить (например, <code><a href="/en-US/docs/Web/CSS/font-size">font-size</a></code>, <code><a href="/en-US/docs/Web/CSS/width">width</a></code>, <code><a href="/en-US/docs/Web/CSS/background-color">background-color</a></code>).</dd> +</dl> + +<dl> + <dt>Значения </dt> + <dd>Это величина свойства, определяющая, как и/или насколько вы желаете изменить свойство.</dd> +</dl> + +<p>На изображении внизу выделены свойство и его значение. Здесь свойство — <code>color</code>, а его значение — <code>blue</code>.</p> + +<p><img alt="A declaration highlighted in the CSS" src="https://mdn.mozillademos.org/files/16498/declaration.png" style="border: 1px solid #cccccc; display: block; height: 218px; margin: 0 auto; width: 471px;"></p> + +<p>Свойство вкупе со значением называется <em>CSS-объявлением</em>. CSS-объявления помещаются внутри <em>блока объявлений CSS</em>. Ниже показан наш CSS-код с выделенным блоком объявлений.</p> + +<p><img alt="A highlighted declaration block" src="https://mdn.mozillademos.org/files/16499/declaration-block.png" style="border: 1px solid #cccccc; display: block; height: 218px; margin: 0 auto; width: 471px;"></p> + +<p>Наконец блок объявлений воссоединяется с <em>селекторами</em>, образуя <em>CSS-правила</em>. Наше изображение содержит два правила — одно для селектора <code>h1</code>, другое для селектора <code>p</code>. Правило для <code>h1</code> выделено.</p> + +<p><img alt="The rule for h1 highlighted" src="https://mdn.mozillademos.org/files/16500/rules.png" style="border: 1px solid #cccccc; display: block; height: 218px; margin: 0 auto; width: 471px;"></p> + +<p>Установление значений для CSS-свойств — вот суть языка CSS. Движок CSS определяет, какие объявления применять к каждому элементу на странице, чтобы соответствующим образом размещать и стилизовать его. Необходимо запомнить, что и свойства, и значения чувствительны к регистру. Пара свойство–значение разделяется двоеточием (<code>:</code>).</p> + +<p><strong>Попробуйте подобрать нужные значения к следующим свойствам, а свойства добавить в ваш код: </strong></p> + +<ul> + <li><strong>{{cssxref("font-size")}}</strong></li> + <li><strong>{{cssxref("width")}}</strong></li> + <li><strong>{{cssxref("background-color")}}</strong></li> + <li><strong>{{cssxref("color")}}</strong></li> + <li><strong>{{cssxref("border")}}</strong></li> +</ul> + +<div class="warning"> +<p><strong>Важно</strong>: Если свойство или значение не определено, то объявление считается <em>недействительным</em> — и будет попросту проигнорировано.</p> +</div> + +<div class="warning"> +<p><strong>Важно</strong>: В CSS (и прочих веб-стандартах) американское написание является стандартом. Например, <code>color</code> надо <em>всегда</em> писать <code>color</code>; британский вариант <code>colour</code> не будет работать.</p> +</div> + +<h3 id="Функции">Функции</h3> + +<p>Чаще всего значения принимают форму числа или ключевого слова; существуют способы создавать функции для значений. Для примера можно взять функцию <code>calc()</code>. Она позволяет вам совершать лёгкие математические вычисления внутри CSS, например:</p> + +<div id="calc_example"> +<pre class="brush: html notranslate"><div class="outer"><div class="box">The inner box is 90% - 30px.</div></div></pre> + +<pre class="brush: css notranslate">.outer { + border: 5px solid black; +} + +.box { + padding: 10px; + width: calc(90% - 30px); + background-color: rebeccapurple; + color: white; +}</pre> +</div> + +<p>В результате получим это:</p> + +<p>{{EmbedLiveSample('calc_example', '100%', 200)}}</p> + +<p>Функция состоит из названия и скобок, внутри который помещается выражение с допустимыми для данной функции знаками. В примере выше я задал значение ширины блока равной 90% внешнего блока минус 30px. Не могу же я сказать, чему равны 90% блока?!</p> + +<p>В следующем примере будут различные значения для свойства {{cssxref("<transform>")}} <code>rotate()</code>.</p> + +<div id="transform_example"> +<pre class="brush: html notranslate"><div class="box"></div></pre> + +<pre class="brush: css notranslate">.box { + margin: 30px; + width: 100px; + height: 100px; + background-color: rebeccapurple; + transform: rotate(0.8turn) +}</pre> +</div> + +<p>Результат этого кода будет:</p> + +<p>{{EmbedLiveSample('transform_example', '100%', 200)}}</p> + +<p><strong>Найдите несколько значений для следующих свойств, а свойства добавьте в ваш файл: </strong></p> + +<ul> + <li><strong>{{cssxref("transform")}}</strong></li> + <li><strong>{{cssxref("background-image")}}, в частности со значениями градиента</strong></li> + <li><strong>{{cssxref("color")}},в частности со значениями rgb/rgba/hsl/hsla</strong></li> +</ul> + +<h2 id="правила">@правила</h2> + +<p>До сих пор не сталкивались мы с правилами <code><a href="/en-US/docs/Web/CSS/At-rule">@rules</a></code> (произносится как <em>эт-рулс</em>, от английского "at-rules"). Это особые правила, дающие CSS инструкции, как вести себя. У некоторых правил <code>@rules</code> простые названия и значения. Чтобы, к примеру, импортировать ещё одну таблицу стилей в основной CSS-файл, нужно использовать <code>@import</code>:</p> + +<pre class="brush: css notranslate">@import 'styles2.css';</pre> + +<p>Чаще других встречается <code>@rules</code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;"> под названием </span></font><code>@media</code>: оно позволяет вам использовать <a href="https://developer.mozilla.org/ru/docs/Web/CSS/Media_Queries/Using_media_queries">медиа-запросы</a>, чтобы применять CSS в определённых случаях, только если выполняются те или иные условия (например, при изменении размеров окна или при просмотре сайта с иного типа устройства).</p> + +<p>Ниже у нас CSS-файл, в котором значение заднего фона элемента <code><body></code> равно <code>pink</code>. Однако после мы добавили правило <code>@media</code>, которое делает задний фон элемента синим, при условии если ширина окна не менее 30em.</p> + +<pre class="brush: css notranslate">body { + background-color: pink; +} + +@media (min-width: 30em) { + body { + background-color: blue; + } +}</pre> + +<p>Вы столкнётесь и с другими правилами <code>@rules</code> в продолжение следующих уроков.</p> + +<p><strong>Добавьте правило, которое изменяет стиль элемента, основываясь на ширине окна. Измените ширину окна, чтобы увидеть результат.</strong></p> + +<h2 id="Стенография">Стенография</h2> + +<p>Некоторые свойства вроде {{cssxref("font")}}, {{cssxref("background")}}, {{cssxref("padding")}}, {{cssxref("border")}} и {{cssxref("margin")}} называются <em>стенографическими свойствами</em>, — они позволяют установать несколько значений свойств в одной строке, ускоряя запись и делая её аккуратной.</p> + +<p>К примеру, это строка (комментарий не в счёт):</p> + +<pre class="brush: css notranslate">/* В четырёхзначных стенографиях наподобие padding и margin значения добавляются + в порядке верх–право–низ–лево (по часовой стрелке сверху). В трёхзначных стенограммах + значения добавляются в порядке верх(низ)–право–лево. + В двузначных стенограммах значения добавляются + от верхнего/нижнего края к левому/правому краю */ +padding: 10px 15px 15px 5px;</pre> + +<p>делает то же самое, что и эти четыре, вместе взятые:</p> + +<pre class="brush: css notranslate">padding-top: 10px; +padding-right: 15px; +padding-bottom: 15px; +padding-left: 5px; +</pre> + +<p>или эти:</p> + +<pre class="brush: cpp notranslate">padding-block-start: 10px +padding-inline-end: 15px; +padding-block-end: 15px; +padding-inline-start: 5px;</pre> + +<p>в то время как строка:</p> + +<pre class="brush: css notranslate">background: red url(bg-graphic.png) 10px 10px repeat-x fixed;</pre> + +<p>делает то же, что и эти строки:</p> + +<pre class="brush: css notranslate">background-color: red; +background-image: url(bg-graphic.png); +background-position: 10px 10px; +background-repeat: repeat-x; +background-scroll: fixed;</pre> + +<p>Мы не будем проходить это сейчас — вы можете найти эти и многие другие стенографии в <a href="/ru/docs/Web/CSS/Reference">Руководстве по CSS</a>.</p> + +<p><strong>Добавьте вышеупоминутые объвления в ваш код. Попробуйте изменить значения и посмотреть на результат.</strong></p> + +<div class="blockIndicator warning"> +<p><strong>Осторожно</strong>: Стенографии позволяют пропускать некоторые величины, и это может отразиться на результате недолжным образом.</p> +</div> + +<h2 id="Комментарии">Комментарии</h2> + +<p>Как и в HTML, вы можете делать комментарии, чтобы прояснить тот или иной отрывок кода.</p> + +<p>Комментарии в CSS начинаются с <code>/*</code> и окачиваются с <code>*/</code>. В примере ниже я отметил комментариями различные разделы кода. Это очень полезно для навигации — комментарии легче искать.</p> + +<pre class="brush: css notranslate">/* Работаю над основными элементами */ +/* -------------------------------------------------------------------------------------------- */ +body { + font: 1em/150% Helvetica, Arial, sans-serif; + padding: 1em; + margin: 0 auto; + max-width: 33em; +} + +@media (min-width: 70em) { + /* Позволяет определить размер шрифта. На широких экранах + больше размер шрифта для удобства чтения */ + body { + font-size: 130%; + } +} + +h1 {font-size: 1.5em;} + +/* Работаю над элементами, вложенными в DOM */ +/* -------------------------------------------------------------------------------------------- */ +div p, #id:first-line { + background-color: red; + background-style: none +} + +div p{ + margin: 0; + padding: 1em; +} + +div p + p { + padding-top: 0; +}</pre> + +<p>Отделяя комментариями участки кода, не нуждающиеся в проверке, вы можете выискивать ошибку (если такая есть). Ниже я отделил правило для селектора <code>.special</code>.</p> + +<pre class="brush: css notranslate">/*.special { + color: red; +}*/ + +p { + color: blue; +}</pre> + +<p><strong>Добавьте комментарии в ваш CSS-код, чтобы приноровиться к ним.</strong></p> + +<h2 id="Отступы">Отступы</h2> + +<p>Под отступами подразумеваются пробелы, табуляция и перенос на новую строку. Как и в HTML, браузер будет стараться игнорировать большие отступы в CSS-коде; к тому же большие отступы пагубны для читаемости кода.</p> + +<p>В примере ниже каждое объявление (а также начало/окончание правила) находится на своей строке — это, возможно, наилучший вариант написания CSS-кода: он понятен и аккуратен:</p> + +<pre class="brush: css notranslate">body { + font: 1em/150% Helvetica, Arial, sans-serif; + padding: 1em; + margin: 0 auto; + max-width: 33em; +} + +@media (min-width: 70em) { + body { + font-size: 130%; + } +} + +h1 { + font-size: 1.5em; +} + +div p, +#id:first-line { + background-color: red; + background-style: none +} + +div p { + margin: 0; + padding: 1em; +} + +div p + p { + padding-top: 0; +} +</pre> + +<p id="Very_compact">То же самое вы можете написать, не добавляя большие отступы, — коды идентичны; но я уверен, вы согласитесь, что это очень тяжело прочитать:</p> + +<pre class="brush: css notranslate">body {font: 1em/150% Helvetica, Arial, sans-serif; padding: 1em; margin: 0 auto; max-width: 33em;} +@media (min-width: 70em) { body {font-size: 130%;} } + +h1 {font-size: 1.5em;} + +div p, #id:first-line {background-color: red; background-style: none} +div p {margin: 0; padding: 1em;} +div p + p {padding-top: 0;} +</pre> + +<p>Как вы будете оформлять код — решать вам; хотя, работая в команде, вы обнаружите, что она придерживается тех правил форматирования, которые в ней утверждены.</p> + +<p>Внимательно делайте отступы в свойствах и значениях. К примеру, такие объявления будут работать:</p> + +<pre class="brush: css notranslate">margin: 0 auto; +padding-left: 10px;</pre> + +<p>А такие объявления не действительны:</p> + +<pre class="brush: css notranslate">margin: <strong>0auto</strong>; +<strong>padding- left</strong>: 10px;</pre> + +<p>Всегда отделяйте друг от друга значения, а свойства пишите без пробелов через дефис.</p> + +<p><strong>Добавьте отступы в ваш код и посмотрите, что повлияет на код, а что нет.</strong></p> + +<h2 id="Что_дальше">Что дальше?</h2> + +<p>Полезно знать, как браузер делает из HTML и CSS готовую страницу, поэтом следующая ваша статья — <a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/How_CSS_works">Как работает CSS</a> — мы рассмотрим этот процесс.</p> + +<p>{{PreviousMenuNext("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps/How_CSS_works", "Learn/CSS/First_steps")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/First_steps/%D0%A7%D1%82%D0%BE_%D1%82%D0%B0%D0%BA%D0%BE%D0%B5_CSS">Что такое CSS?</a></li> + <li><a href="/ru/docs/Learn/CSS/First_steps/Getting_started">Начало работы с CSS</a></li> + <li><a href="/ru/docs/Learn/CSS/First_steps/%D0%9A%D0%B0%D0%BA_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD_CSS">Как структурирован CSS</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/How_CSS_works">Как работает CSS</a></li> + <li><a href="/ru/docs/Learn/CSS/First_steps/Using_your_new_knowledge">Использование ваших новых знаний</a></li> +</ol> diff --git a/files/ru/learn/css/first_steps/что_такое_css/index.html b/files/ru/learn/css/first_steps/что_такое_css/index.html new file mode 100644 index 0000000000..6b5bdf8924 --- /dev/null +++ b/files/ru/learn/css/first_steps/что_такое_css/index.html @@ -0,0 +1,130 @@ +--- +title: Что такое CSS? +slug: Learn/CSS/First_steps/Что_такое_CSS +tags: + - Beginner + - CSS + - Learn + - Введение в CSS + - Начинающий + - Обучение + - Синтаксис + - Спецификации +translation_of: Learn/CSS/First_steps/What_is_CSS +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First steps")}}</div> + +<p class="summary"><strong>{{Glossary("CSS")}}</strong> (Каскадные таблицы стилей) позволяет создавать великолепно выглядящие веб-страницы, но как же это работает? Эта статья объясняет, что такое CSS, с помощью простого примера синтаксиса, а также охватывает некоторые ключевые термины о языке.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требуемые знания:</th> + <td>Базовые компьютерные знания, <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">установка базового програмного обеспечения</a>, базовые знания <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работа с файлами</a> и базовые знания HTML (<a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>).</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Узнать, что такое CSS.</td> + </tr> + </tbody> +</table> + +<p>В модуле <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Основы HTML</a> мы рассмотрели, что такое HTML и как он используется для разметки документов. Эти документы будут доступны для чтения в веб-браузере. Заголовки будут выглядеть больше, чем обычный текст, абзацы разбиваются на новую строку и будут иметь пространство между друг другом. Ссылки выделены цветом и подчеркнуты, чтобы отличить их от остального текста. То, что Вы видите, — это стили браузера по умолчанию — самые основные стили, которые браузер применяет к HTML, чтобы гарантировать, что он будет в основном читабельным, даже если автор страницы не указал явный стиль.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/17072/Basic_styling__ru.png" style="border: 1px solid #cccccc; height: 678px; width: 1385px;"></p> + +<p>Тем не менее, интернет был бы скучным, если бы все сайты выглядели так. Используя CSS, Вы можете до мелочей контролировать, как элементы HTML выглядят в браузере, представляя вашу разметку, используя любой понравившийся Вам дизайн.</p> + +<h2 id="Для_чего_нужен_CSS">Для чего нужен CSS?</h2> + +<p>Как мы уже упоминали ранее, CSS — это язык для определения того, как документы представляются пользователям — как они оформляются, размещаются и т. д.</p> + +<p><strong>Документ</strong> обычно представляет собой текстовый файл, структурированный с использованием языка разметки: {{Glossary("HTML")}} — самый распространенный язык разметки, но Вы также можете встретить другие языки разметки, такие как {{Glossary("SVG")}} или {{Glossary("XML")}}.</p> + +<p><strong>Представление</strong> документа пользователю означает преобразование его в форму, используемую Вашей аудиторией<strong>.</strong> {{Glossary("browser","Browsers")}}, такие как {{Glossary("Mozilla Firefox","Firefox")}}, {{Glossary("Google Chrome","Chrome")}} или {{Glossary("Microsoft Edge","Edge")}} , предназначены для визуального представления документов, например, на экране компьютера, проектора или принтера.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Браузер иногда называют {{Glossary("User agent","user agent")}}, что в основном означает компьютерную программу, которая представляет человека внутри компьютерной системы. Браузеры — это основной тип пользовательского агента, о котором мы думаем, когда говорим о CSS, но он не единственный. Доступны и другие пользовательские агенты, например, те, которые преобразуют документы HTML и CSS в файлы PDF для печати.</p> +</div> + +<p>CSS может использоваться для очень простой стилизации текста документа, например, изменение <a href="https://developer.mozilla.org/ru/docs/Web/CSS/color_value">цвета</a> и <a href="https://developer.mozilla.org/ru/docs/Web/CSS/font-size">размера</a> заголовков и ссылок. Он может быть использован для создания макета, например, <a href="/en-US/docs/Web/CSS/Layout_cookbook/Column_layouts">превращение одного столбца текста в макет</a> с основной областью контента и боковой панелью для соответствующей информации. Это может даже использоваться для эффектов, таких как <a href="https://developer.mozilla.org/ru/docs/Web/CSS/CSS_Animations">анимация</a>. Посмотрите на ссылки в этом параграфе для конкретных примеров.</p> + +<h2 id="Синтаксис_CSS">Синтаксис CSS</h2> + +<p>CSS — это язык на основе правил: Вы задаёте правила, определяющие группы стилей, которые должны применяться к определённым элементам или группам элементов на Вашей веб-странице. Например:</p> + +<p>«Я хочу, чтобы основной заголовок на моей странице отображался крупным красным текстом».</p> + +<p>В следующем коде показано очень простое правило CSS, которое будет соответствовать стилю, описанному выше:</p> + +<pre class="brush: css">h1 { + color: red; + font-size: 5em; +}</pre> + +<p>Правило открывается с помощью {{Glossary("CSS Selector", "селектора")}} . Этот селектор выбирает HTML-элемент, который мы собираемся стилизовать. В этом случае мы используем заголовки первого уровня — ({{htmlelement("h1")}}).</p> + +<p>Затем у нас есть набор фигурных скобок <code>{ }</code>. Внутри них будет один или несколько <strong>объявлений</strong>, которые принимают форму пары <strong>свойства</strong> и его <strong>значения</strong>. Каждая пара указывает свойство элемента(-ов), который(-е) мы выбираем, а затем значение, которое мы хотели бы присвоить свойству.</p> + +<p>Перед двоеточием у нас есть свойство, а после двоеточия — значение. CSS-{{Glossary("property/CSS","свойства")}} имеют разные допустимые значения в зависимости от того, какое свойство указывается. В нашем примере мы имеем свойство <code>color</code>, которое может принимать различные <a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#Color">цветовые значения</a>. У нас также есть свойство <code>font-size</code>. Это свойство может принимать различные <a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#Numbers_lengths_and_percentages">значения размера</a>, как и свойства.</p> + +<p>Таблица стилей CSS будет содержать много таких правил, написанных одно за другим.</p> + +<pre class="brush: css">h1 { + color: red; + font-size: 5em; +} + +p { + color: black; +}</pre> + +<p>Вы обнаружите, что Вы быстро изучаете некоторые значения, тогда как другие Вам нужно искать. Страницы отдельных свойств в MDN дают Вам быстрый способ поиска свойств и их значений, когда Вы забыли или хотите узнать, что ещё Вы можете использовать в качестве значения.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Вы можете найти ссылки на все страницы свойств CSS (вместе с другими функциями CSS), перечисленные в MDN <a href="/en-US/docs/Web/CSS/Reference">Руководстве по CSS</a>. Кроме того, Вы должны привыкнуть к поиску "MDN <em>css-feature-name</em>" в Вашем бразере, когда Вам нужно узнать больше информации о функции CSS. Например, попробуйте поискать «mdn color» и «mdn font-size»!</p> +</div> + +<h2 id="CSS-модули">CSS-модули</h2> + +<p>Поскольку существует множество вещей, которые можно стилизовать с помощью CSS, язык разбит на модули. По мере изучения MDN Вы увидите ссылки на эти модули, а многие страницы документации организованы вокруг определенного модуля. Например, вы можете взглянуть на ссылку MDN в модуле <a href="/en-US/docs/Web/CSS/CSS_Backgrounds_and_Borders">Свойства фона и границ</a>, чтобы узнать, какова его цель и какие различные свойства и другие функции он содержит. Вы также найдёте ссылки на спецификацию CSS, которая определяет технологию (см. ниже).</p> + +<p>На этом этапе вам не нужно слишком беспокоиться о том, как структурирован CSS, однако это может упростить поиск информации, если, например, вы знаете, что определённое свойство может быть найдено среди других похожих вещей, и поэтому, вероятно, в той же спецификации.</p> + +<p>Для конкретного примера давайте вернемся к модулю Свойства фона и границ — Вы можете подумать, что это логично для свойств <code><a href="/en-US/docs/Web/CSS/background-color">background-color</a></code> и <code><a href="/en-US/docs/Web/CSS/border-color">border-color</a></code>, которые будут определены в этом модуле. И Вы правы.</p> + +<h3 id="Технические_характеристики_CSS">Технические характеристики CSS</h3> + +<p>Все технологии веб-стандартов (HTML, CSS, JavaScript и т. д.) определены в гигантских документах, называемых спецификациями, которые публикуются организациями по стандартизации (такие как {{glossary("W3C")}}, {{glossary("WHATWG")}}, {{glossary("ECMA")}} или {{glossary("Khronos")}}) и определяют, как эти технологии должны вести себя.</p> + +<p>CSS ничем не отличается — он разработан группой в W3C, которая называется <a href="https://www.w3.org/Style/CSS/">CSS Working Group</a>. Эта группа состоит из представителей производителей браузеров и других компаний, которые заинтересованы в CSS. Есть также другие люди, известные как приглашенные эксперты, которые выступают как независимые голоса; они не связаны с членами организации.</p> + +<p>Новые функции CSS разрабатываются или определяются рабочей группой CSS. Иногда потому, что конкретный браузер заинтересован в том, чтобы иметь какие-то возможности, иногда потому, что веб-дизайнеры и разработчики запрашивают функцию, а иногда потому, что сама рабочая группа определила требование. CSS постоянно развивается, появляются новые функции. Тем не менее, ключевым моментом в CSS является то, что все работают очень усердно, чтобы никогда не менять вещи таким образом, чтобы это сломало старые сайты. Веб-сайт, созданный в 2000 году, с использованием ограниченного CSS, доступного в то время, должен всё ещё использоваться в браузере сегодня!</p> + +<p>Как новичок в CSS, вполне вероятно, что Вы найдете CSS-спецификации ошеломляющими — они предназначены для инженеров, чтобы использовать их для реализации поддержки функций в пользовательских агентах, а не для веб-разработчиков, чтобы читать, чтобы понимать CSS. Многие опытные разработчики предпочитают обращаться к документации MDN или другим учебникам. Однако стоит знать, что они существуют, понимать взаимосвязь между используемым CSS, поддержкой браузера (см. ниже) и спецификациями.</p> + +<h2 id="Поддержка_браузера">Поддержка браузера</h2> + +<p>После того как CSS был указан, он будет полезен для разработки веб-страниц, только если один или несколько браузеров его реализовали. Это означает, что код был написан для превращения инструкции в нашем CSS-файле во что-то, что может быть выведено на экран. Мы рассмотрим этот процесс подробнее на уроке <a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">Как работает CSS</a><a href="/ru/docs/">.</a> Это необычно для всех браузеров, чтобы реализовать функцию одновременно, и поэтому обычно есть пробел, где вы можете использовать некоторую часть CSS в одних браузерах, а не в других. По этой причине полезно проверять состояние реализации. На каждой странице свойств в MDN Вы можете видеть статус интересующего Вас свойства, чтобы Вы могли определить, сможете ли Вы использовать её на веб-сайте.</p> + +<p>Ниже приведена диаграмма данных для CSS свойства <code><a href="/en-US/docs/Web/CSS/font-family">font-family</a></code>:</p> + +<p>{{Compat("css.properties.font-family")}}</p> + +<h2 id="Что_дальше">Что дальше?</h2> + +<p>Теперь, когда у вас есть некоторое представление о том, что такое CSS, давайте перейдем к <a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/Getting_started">Началу работы с CSS</a>, где Вы можете начать писать CSS самостоятельно.</p> + +<p>{{NextMenu("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ol> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/%D0%A7%D1%82%D0%BE_%D1%82%D0%B0%D0%BA%D0%BE%D0%B5_CSS">Что такое CSS?</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps">Начало работы с CSS</a></li> + <li><a href="https://developer.cdn.mozilla.net/ru/docs/Learn/CSS/First_steps/%D0%9A%D0%B0%D0%BA_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD_CSS">Как структурирован CSS</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/How_CSS_works">Как работает CSS</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps/Using_your_new_knowledge">Использование ваших новых знаний</a></li> +</ol> diff --git a/files/ru/learn/css/index.html b/files/ru/learn/css/index.html new file mode 100644 index 0000000000..1e4d325d61 --- /dev/null +++ b/files/ru/learn/css/index.html @@ -0,0 +1,65 @@ +--- +title: CSS +slug: Learn/CSS +tags: + - Beginner + - CSS + - Debugging + - Landing + - NeedsContent + - Topic + - TopicStub + - length +translation_of: Learn/CSS +--- +<p>{{LearnSidebar}}</p> + +<p class="summary">Каскадные таблицы стилей, или CSS, — это технология, которую следует изучать непосредственно после HTML. В отличие от HTML, который служит для определения структуры и семантики содержимого, CSS отвечает за его внешний вид и отображение. К примеру, с помощью CSS можно изменять шрифт, цвет, размер, межстрочный интервал, разделять содержимое на колонки, а также добавлять анимацию и другие декоративные элементы.</p> + +<h2 id="План_обучения">План обучения </h2> + +<p>Прежде чем браться за CSS, Вам стоит разобраться с основами HTML. Мы рекомендуем изучить модуль <a href="/ru/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>. После его прохождения переходите к:</p> + +<ul> + <li>изучению CSS, начиная с модуля <a href="/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>;</li> + <li>далее — к более продвинутой теме <a href="/ru/docs/Learn/HTML#Модули">HTML-модули</a></li> + <li>после этого — к модулю <a href="/ru/docs/Learn/JavaScript">JavaScript</a> и тому, как его использовать, чтобы добавить Вашим веб-страницам динамического функционала.</li> +</ul> + +<p>Мы рекомендуем изучать HTML и CSS одновременно. HTML гораздо интереснее в сочетании с CSS и изучать эти языки раздельно было бы ошибочно.</p> + +<p>В данном разделе содержится информация, которая требует самой базовой ознакомленности с компьютером и интернетом. В статье <a href="/ru/docs/Learn/Getting_started_with_the_web/Installing_basic_software">Установка рабочего пространства</a> подробно описано необходимое ПО и способы его установки, необходимо также будет уметь создавать и управлять файлами, в чём поможет статья <a href="/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a>, которая включена в полное руководство для новичка <a href="/ru/docs/Learn/Getting_started_with_the_web">Основы веб</a>.</p> + +<p>Перед тем как начинать данный раздел, мы рекомендуем пройти руководство <a href="/ru/docs/Learn/Getting_started_with_the_web">Основы веб</a>, хотя это вовсе не обязательно; большая часть того, что Вы найдёте в статье об основах CSS также встречается в разделе<a href="/ru/docs/Learn/CSS/First_steps"> Введение в CSS</a>, хотя и более детально.</p> + +<h2 id="Модули">Модули</h2> + +<p>Этот раздел содержит модули в порядке, наиболее подходящем для работы с ними. Лучше всего начать с самого первого.</p> + +<dl> + <dt><a href="/ru/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a></dt> + <dd>CSS (каскадные таблицы стилей) используется для стилизации и компоновки веб-страниц, — например, для изменения шрифта, цвета, размера и интервала содержимого, разделения его на несколько столбцов или добавления анимации и других декоративных элементов. Этот модуль обеспечивает хорошее начало Вашего пути к освоению CSS с основами того, как он работает, как выглядит синтаксис и как Вы можете начать использовать его для добавления стилей в HTML.</dd> + <dt><a href="/ru/docs/Learn/CSS/Styling_text">Дизайн текста</a></dt> + <dd>Здесь мы рассмотрим основы стилизации текста, в том числе изменение шрифта, жирности, курсивного написания, межстрочного и межбуквенного интервалов, теней и других особенностей текста. Завершается модуль демонстрацией применения пользовательских шрифтов на вашей странице, оформлением списков и ссылок.</dd> + <dt><a href="/ru/docs/Learn/CSS/Styling_boxes">Стилизация блоков</a></dt> + <dd>Далее мы рассмотрим дизайн блоков, один из основных шагов к разметке веб-страницы. В этом модуле мы кратко рассмотрим работу с блочными элементами, а затем ознакомимся с приемами управления блоками, установив такие свойства, как поля, оступы и границы, настроим фоновые цвет и изображение, а также рассмотрим более сложные функции, такие как тени и фильтры.</dd> + <dt><a href="/ru/docs/Learn/CSS/CSS_layout">Размещение элементов с помощью CSS</a></dt> + <dd>К текущему моменту мы познакомились с основами CSS. Мы знаем, как оформлять текст, как оформлять и изменять блоки, в которых находится ваш контент. Пришло время узнать, как разместить ваши блоки в нужных местах в зависимости от области просмотра и тому подобного. Мы уже знаем достаточно, чтобы погрузиться в изучение разметки с помощью CSS, в то, как изменять отображение в зависимости от особенностей экрана, как иcпользовать современные методы разметки, такие как Flexbox и CSS grid, и некоторые традиционные методы разметки, которые все ещё применяются.</dd> + <dt>Адаптивный дизайн (TBD)</dt> + <dd><span id="result_box" lang="ru"><span>В настоящее время существоет множество устройств, способных осуществлять просмотр веб-страниц, адаптивный веб-дизайн (RWD - Responsive Web Design) стал основным навыком веб-разработки.</span> <span>В этом модуле рассказывается об основных принципах и инструментах RWD, объясняется, как применять различные CSS к документу в зависимости от таких функций устройства, как ширина экрана, ориентация и разрешение, а также изучить имеющиеся возможности отображения различных видео и изображений в зависимости от характеристик используемого пользователем устройства.</span></span></dd> +</dl> + +<h2 id="Решаем_часто_встречающиеся_проблемы_в_CSS">Решаем часто встречающиеся проблемы в CSS</h2> + +<p>В разделе <strong><a href="/ru/docs/Learn/CSS/Как">Использование CSS для решения общих проблем</a></strong> даны ссылки на разделы, объясняющие, как следует использовать CSS для решения самых распространенных проблем при создании веб-страницы.</p> + +<p>В самом начале Вы будете применять цвет к тексту и фону HTML-элементов, изменять их размер, форму, местоположение, добавлять и стилизовать границы. Однако с уверенным знанием даже основ CSS Вы сможете сделать практически что угодно. Одним из плюсов изучения CSS является то, что Вы быстро начнёте понимать, можно или нельзя что-то сделать средствами CSS, даже если Вы еще не уверены, как это сделать. </p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<dl> + <dt><a href="/ru/docs/Web/CSS">CSS на MDN</a></dt> + <dd>Основная точка входа для CSS документации на MDN с подробными ссылками на дополнительные учебники.</dd> + <dt><a href="/ru/docs/Web/CSS/Reference">CSS-справочник</a></dt> + <dd><span id="result_box" lang="ru"><span>Комплексный</span> <span>справочник по</span> <span>всем многочисленным</span> <span>особенностям</span> <span>языка</span> <span>CSS,</span></span> — если Вы, к примеру, хотите знать, какие значения может иметь свойство, то Вам сюда.</dd> +</dl> diff --git a/files/ru/learn/css/introduction_to_css/ponimanie_osnov_css/index.html b/files/ru/learn/css/introduction_to_css/ponimanie_osnov_css/index.html new file mode 100644 index 0000000000..9009c684d8 --- /dev/null +++ b/files/ru/learn/css/introduction_to_css/ponimanie_osnov_css/index.html @@ -0,0 +1,123 @@ +--- +title: Понимание основ CSS +slug: Learn/CSS/Introduction_to_CSS/Ponimanie_osnov_CSS +translation_of: Learn/CSS/Building_blocks/Fundamental_CSS_comprehension +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/CSS/Introduction_to_CSS/Debugging_CSS", "Learn/CSS/Introduction_to_CSS")}}</div> + +<p class="summary">Вы многое прошли в этом модуле, и должно быть вас посетило это прекрасное чувство, что дошли до конца! Последний шаг перед тем, как двигаться дальше, это попытка пройти проверку по материалам модуля — это включает в себя ряд соответствующих упражнений, которые должны быть выполнены для того, чтобы создать заключительный проект — визитка, карточка игрока, профиль в социльной сети.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительно:</th> + <td>Перед попыткой пройти проверку вы должны проработать все статьи в этом модуля.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Проверка понимания основной теории, синтаксиса и техник CSS.</td> + </tr> + </tbody> +</table> + +<h2 id="Отправной_пункт">Отправной пункт</h2> + +<p>Чтобы начать проверку, вы должны:</p> + +<ul> + <li>Перейти и скачать <a href="https://github.com/mdn/learning-area/blob/master/css/introduction-to-css/fundamental-css-comprehension/index.html">HTML файл для упражнения</a> и <a href="https://github.com/mdn/learning-area/blob/master/css/introduction-to-css/fundamental-css-comprehension/chris.jpg">связанный файл изображения</a>, сохранить их в новую директорию на локальном компьютере. Если вы хотите использовать свой собственный файл изображения и вписать свое имя, то пожалуйста — только убедитесь, что изображение квадратное.</li> + <li>Скачайте <a href="https://github.com/mdn/learning-area/blob/master/css/introduction-to-css/fundamental-css-comprehension/style-resources.txt">текстовый файл с исходным CSS</a> — в нем содержится набор исходных селекторов и наборов правил, которые вы должны изучить и объединить, чтобы пройти часть этой проверки.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Вместо этого вы можете использовать для проверки такие сайты как <a class="external external-icon" href="http://jsbin.com/">JSBin</a> или <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a>. Вы можете скопировать HTML и заполнить CSS в одном из этих онлайн редакторов и использовать <a href="http://mdn.github.io/learning-area/css/introduction-to-css/fundamental-css-comprehension/chris.jpg">этот URL</a> чтобы указать элементу <code><img></code> файл изображения. Если используемый онлайн-редактор не имеет отдельной панели для CSS, вы можете поместить его в элемент <code><style></code> в заголовке документа.</p> +</div> + +<h2 id="Краткое_описание_проекта">Краткое описание проекта</h2> + +<p>Вам предоставили некоторый исходный HTML и изображение, и нужно написать необходимые CSS-правила, чтобы стилизовать это в маленькую онлайн-визитку, которая может, возможно, стать картой игрока или профилем в социальных сетях. Следующие разделы описывают, что вам нужно сделать.</p> + +<p>Первоначальные настройки:</p> + +<ul> + <li>Прежде всего, создайте новый файл в той же директории, что и ваши HTML и файл изображения. Назовите его как-нибудь образно, например <code>style.css</code>.</li> + <li>Подключите ваш CSS к вашему файлу HTML с помощью элемента <code><link></code>.</li> + <li>Первые два набора правил в исходном файле CSS ваши бесплатно! После того, как вы закончите радоваться своей удаче, скопируйте и вставьте их в верхнюю часть вашего нового файла CSS. Используйте их в качестве теста, чтобы убедиться, что ваш CSS правильно применяется к HTML.</li> + <li>Над этими двумя правилами добавьте CSS-комментарий, что это набор общих стилей для всей страницы. "Общие стили страницы" подойдут. Также добавьте еще три комментария в нижней части CSS-файла, чтобы отметить стили, соответствующие для настройки контейнера карты, стили, соответствующие для верхнего и нижнего колонтитулов, а также стили, соответствующие для основного содержимого визитной карточки. Отныне новые стили, добавленные в таблицу стилей, должны быть размещены в соответствующем месте.</li> +</ul> + +<p>Позаботимся о селекторах и наборах правил, предоставленных в файле CSS:</p> + +<ul> + <li>Далее мы хотели бы, чтобы вы посмотрели на четыре селектора и рассчитали специфичность для каждого из них. Запишите их где-нибудь, где они могут быть найдены позже, например, в комментарии в верхней части CSS.</li> + <li>Теперь пришло время сопоставить правильный селектор и правильный набор правил! У вас есть четыре пары селекторов и набора правил для сопоставления в ваших ресурсах CSS. Сделайте это сейчас и добавьте их в файл CSS. Вам нужно сделать: + <ul> + <li>Задайте основному контейнеру карты фиксированную ширину/высоту, сплошной цвет фона, границу и радиус границы (закругленные углы!), помимо прочего.</li> + <li>Задайте заголовку градиент фона, который идет от темного к светлому, плюс закругленные углы, которые вписываются в закругленные углы, заданные для главного контейнера карты.</li> + <li>Задайте для футера градиент фона, переходящий от светлого к темному, а также скругленные углы, которые вписываются в скругленные углы контейнера основной карты.</li> + <li>Сместите изображение вправо, чтобы оно прилипло к правой стороне основного содержимого визитной карточки, и придайте ему максимальную высоту 100% (хитрый трюк, который гарантирует, что он будет растягиваться/сжиматься, чтобы оставаться на той же высоте, что и его родительский контейнер, независимо от того, какой высоты он становится).</li> + </ul> + </li> + <li>Осторожно! В предоставленных наборах правил есть две ошибки. Используя любую технику, которую вы знаете, отследите их и исправьте, прежде чем двигаться дальше.</li> +</ul> + +<p>Какие новые наборы правил надо написать:</p> + +<ul> + <li>Напишите набор правил, предназначенный как для заголовка, так и для футера карты, задавая им вычисленную общую высоту 50 пикселей (включая высоту содержимого 30 пикселей и внутренние отступы (padding) 10 пикселей со всех сторон.) Но выразите это в <code>em</code>s.</li> + <li><code>margin</code> по умолчанию, применяемый браузером к элементам <code><h2></code> и <code><p></code>, будет мешать нашему дизайну, поэтому напишите правило, которое устанавливает этот параметр для указанных элементов равным 0.</li> + <li>Чтобы изображение не вылезало за пределы основного содержимого визитки (элемент <code><article></code>), нужно задать ему определенную высоту. Установите высоту <code><article></code> в 120px, но выраженную в <code>em</code>s. Также задайте ему полупрозрачный черный цвет фона, в результате получится чуть более темный оттенок, который позволяет цвету фона немного просвечивать красным цветом.</li> + <li>Напишите набор правил, который задает тегу <code><h2></code> удобный размер шрифта 20px (но выраженный в <code>em</code>s) и соответствующую высоту строки, чтобы поместить ее в центр поля содержимого заголовка. Напомним, что высота окна содержимого (content box) должна быть 30px — это дает вам все числа, необходимые для вычисления высоты строки.</li> + <li>Напишите набор правил, который задает тегу <code><p></code> внутри нижнего колонтитула удобный размер шрифта 15px (но выраженный в <code>em</code>s) и соответствующую высоту строки, чтобы поместить его в центр окна содержимого нижнего колонтитула. Напомним, что высота окна содержимого должна быть 30px — это дает вам все числа, необходимые для вычисления высоты строки.</li> + <li>В качестве последнего штриха задайте параграфу внутри <code><article></code> соответствующее значение отступа (padding), чтобы его левый край выровнялся с тегом <code><h2></code> и нижним параграфом, и установите его цвет достаточно светлым, чтобы его было легко читать.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Имейте в виду, что второй набор правил устанавливает <code>font-size: 10px;</code> для элемента<code><html></code> — это означает, что для любых потомков <code><html></code> <code>em</code> будет равен 10px, а не 16px, как это задано по умолчанию. (Это, конечно, при условии, что у потомков, о которых идет речь, нет предков, находящихся в иерархии между ними и <code><html></code>, на которых установлен другой размер шрифта. Это может повлиять на необходимые значения, хотя в этом простом примере это не проблема).</p> +</div> + +<p>Другие вещи для размышления:</p> + +<ul> + <li>Вы получите бонусные баллы, если напишите объявления своего CSS в отдельных строках, чтобы обеспечить максимальную читаемость.</li> + <li>Вы должны включить <code>.card</code> в начале цепочки селекторов во всех ваших правилах, чтобы эти правила не мешали стилизации каких-либо других элементов, в случае если визитная карточка должна быть помещена на страницу с загрузкой другого контента.</li> +</ul> + +<h2 id="Советы_и_подсказки">Советы и подсказки</h2> + +<ul> + <li>Вам не нужно каким-либо образом редактировать HTML, за исключением подключения к нему CSS.</li> + <li>При попытке определить значение em вам нужно представить определенную величину в пикселях. Подумайте о том, какой размер базового шрифта имеет корневой элемент (<code><html></code>), и на сколько его нужно умножить, чтобы получить желаемое значение. Это даст вам значение <code>em</code>, по крайней мере, в таком простом случае как этот.</li> +</ul> + +<h2 id="Образец">Образец</h2> + +<p>На следующем снимке экрана показан образец того, как должен выглядеть готовый дизайн:</p> + +<p><img alt="A view of the finished business card, show a reader header and footer, and a darker center panel containing the main details and image." src="https://mdn.mozillademos.org/files/12616/business-card.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="Проверка">Проверка</h2> + +<p>Если вы проходите эту проверку в рамках организованного курса, у вас должна быть возможность отдать свою работу своему учителю/наставнику для оценки. Если вы самообучаетесь, то вы можете получить руководство по оценке достаточно простым путем: спросив в <a href="https://discourse.mozilla.org/t/fundamental-css-comprehension-assessment/24682">теме обсуждения об этом упражнении</a>, или в канале <a href="irc://irc.mozilla.org/mdn">#mdn</a> IRC на <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Но сначала попробуйте выполнить упражнение — вы ничего не выиграете путем обмана!</p> + +<p>{{PreviousMenu("Learn/CSS/Introduction_to_CSS/Debugging_CSS", "Learn/CSS/Introduction_to_CSS")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS">Вступление в CSS</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/How_CSS_works">Как работает CSS</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Syntax">Синтаксис CSS</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Selectors">Введение в селекторы</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Simple_selectors">Простые селекторы</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Attribute_selectors">Селекторы по атрибутам</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Pseudo-classes_and_pseudo-elements">Псевдоклассы и псевдоэлементы</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Combinators_and_multiple_selectors">Комбинаторы и множественные селекторы</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Values_and_units">CSS значения и единицы</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance">Каскадность и наследование</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Box_model">Блочная модель</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Debugging_CSS">Отладка CSS</a></li> + <li><a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Fundamental_CSS_comprehension">Задание: Основы понимания CSS</a></li> +</ul> diff --git a/files/ru/learn/css/styling_text/fundamentals/index.html b/files/ru/learn/css/styling_text/fundamentals/index.html new file mode 100644 index 0000000000..5d80571f6f --- /dev/null +++ b/files/ru/learn/css/styling_text/fundamentals/index.html @@ -0,0 +1,735 @@ +--- +title: Основы стилизирования текста и шрифта +slug: Learn/CSS/Styling_text/Fundamentals +translation_of: Learn/CSS/Styling_text/Fundamentals +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/CSS/Styling_text/Styling_lists", "Learn/CSS/Styling_text")}}</div> + +<p class="summary"><span class="seoSummary">В данной статье мы начнем путь к овладению стилизацией текста при помощи {{glossary("CSS")}}.</span> Мы подробно изучим основы стилизации текста и шрифта, такие как толщина, начертание, семейство, стенография, выравнивание текста и другие эффекты, а также рассмотрим междустрочный и межбуквенный интервалы.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовые компьютерные знания, Основы HTML (раздел <a href="/ru/docs/Learn/HTML/Введение_в_HTML">Введение в HTML</a>), основы CSS (раздел <a href="/ru/docs/Learn/CSS/First_steps">Введение в CSS</a>).</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Изучить основные свойства и техники, необходимые для стилизации текста на веб-страницах.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_участвует_в_стилизации_текста_в_CSS">Что участвует в стилизации текста в CSS?</h2> + +<p>Как вы уже проверили в своей работе с HTML и CSS, текст внутри элемента выкладывается в поле содержимого элемента. Он начинается в левом верхнем углу области содержимого (или в правом верхнем углу, в случае содержимого языка RTL) и течет к концу строки. Как только он достигает конца, он переходит к следующей строке и продолжает, затем к следующей строке, пока все содержимое не будет помещено в коробку. Текстовое содержимое эффективно ведет себя как ряд встроенных элементов, размещенных на соседних строках и не создающих разрывы строк до тех пор, пока не будет достигнут конец строки, или если вы не принудите разрыв строки вручную с помощью элемента {{htmlelement("br")}}.</p> + +<div class="note"> +<p><strong>Примечание:</strong> если приведенный выше абзац оставляет вас в замешательстве, то не имеет значения — вернитесь и просмотрите нашу статью о модели коробки, чтобы освежить теорию модели коробки, прежде чем продолжить.</p> +</div> + +<p>Свойства CSS, используемые для стилизации текста, обычно делятся на две категории, которые мы рассмотрим отдельно в этой статье:</p> + +<ul> + <li><strong>Font styles</strong>: Свойства, влияющие на шрифт, применяемый к тексту, влияющие на то, какой шрифт применяется, насколько он велик, является ли он полужирным, курсивным и т. д.</li> + <li><strong>Text layout styles</strong>: Свойства, влияющие на интервал и другие особенности компоновки текста, позволяющие манипулировать, например, пространством между строками и буквами, а также тем, как текст выравнивается в поле содержимого.</li> +</ul> + +<div class="note"> +<p><strong>Примечание:</strong> имейте в виду, что текст внутри элемента все затронуты как одна единая сущность. Вы не можете выбирать и стилизовать подразделы текста, если вы не обернете их в соответствующий элемент (например, {{htmlelement ("span")}} или {{htmlelement ("strong")}}), или использовать текстовый псевдоэлемент, такой как ::first-letter (выделяет первую букву текста элемента),:: first-line (выделяет первую строку текста элемента) или ::selection (выделяет текст, выделенный в данный момент курсором.)</p> +</div> + +<h2 id="Шрифты">Шрифты</h2> + +<p>Давайте сразу перейдем к рассмотрению свойств для стилизации шрифтов. В этом примере мы применим некоторые различные свойства CSS к одному и тому же образцу HTML, который выглядит следующим образом:</p> + +<pre class="brush: html notranslate"><h1>Tommy the cat</h1> + +<p>Well I remember it as though it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p></pre> + +<p>You can find the <a href="http://mdn.github.io/learning-area/css/styling-text/fundamentals/">finished example on GitHub</a> (see also <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/fundamentals/index.html">the source code</a>.)</p> + +<h3 id="Color">Color</h3> + +<p>The {{cssxref("color")}} property sets the color of the foreground content of the selected elements (which is usually the text, but can also include a couple of other things, such as an underline or overline placed on text using the {{cssxref("text-decoration")}} property).</p> + +<p><code>color</code> can accept any <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Colors">CSS color unit</a>, for example:</p> + +<pre class="brush: css notranslate">p { + color: red; +}</pre> + +<p>This will cause the paragraphs to become red, rather than the standard browser default black, like so:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Tommy the cat</h1> + +<p>Well I remember it as though it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p></pre> +</div> + +<p>{{ EmbedLiveSample('Color', '100%', 230) }}</p> + +<h3 id="Font_families">Font families</h3> + +<p>To set a different font on your text, you use the {{cssxref("font-family")}} property — this allows you to specify a font (or list of fonts) for the browser to apply to the selected elements. The browser will only apply a font if it is available on the machine the website is being accessed on; if not, it will just use a browser {{anch("Default fonts", "default font")}}. A simple example looks like so:</p> + +<pre class="brush: css notranslate">p { + font-family: arial; +}</pre> + +<p>This would make all paragraphs on a page adopt the arial font, which is found on any computer.</p> + +<h4 id="Web_safe_fonts">Web safe fonts</h4> + +<p>Speaking of font availability, there are only a certain number of fonts that are generally available across all systems and can therefore be used without much worry. These are the so-called <strong>web safe fonts</strong>.</p> + +<p>Most of the time, as web developers we want to have more specific control over the fonts used to display our text content. The problem is to find a way to know which font is available on the computer used to see our web pages. There is no way to know this in every case, but the web safe fonts are known to be available on nearly all instances of the most used operating systems (Windows, macOS, the most common Linux distributions, Android, and iOS).</p> + +<p>The list of actual web safe fonts will change as operating systems evolve, but it's reasonable to consider the following fonts web safe, at least for now (many of them have been popularized thanks to the Microsoft <em><a href="https://en.wikipedia.org/wiki/Core_fonts_for_the_Web">Core fonts for the Web</a></em> initiative in the late 90s and early 2000s):</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Name</th> + <th scope="col" style="white-space: nowrap;">Generic type</th> + <th scope="col">Notes</th> + </tr> + </thead> + <tbody> + <tr> + <td>Arial</td> + <td>sans-serif</td> + <td>It's often considered best practice to also add <em>Helvetica</em> as a preferred alternative to <em>Arial</em> as, although their font faces are almost identical, <em>Helvetica</em> is considered to have a nicer shape, even if <em>Arial</em> is more broadly available.</td> + </tr> + <tr> + <td>Courier New</td> + <td>monospace</td> + <td>Some OSes have an alternative (possibly older) version of the <em>Courier New</em> font called <em>Courier</em>. It's considered best practice to use both with <em>Courier New</em> as the preferred alternative.</td> + </tr> + <tr> + <td style="white-space: nowrap;">Georgia</td> + <td>serif</td> + <td></td> + </tr> + <tr> + <td style="white-space: nowrap;">Times New Roman</td> + <td>serif</td> + <td>Some OSes have an alternative (possibly older) version of the <em>Times New Roman</em> font called <em>Times</em>. It's considered best practice to use both with <em>Times New Roman</em> as the preferred alternative.</td> + </tr> + <tr> + <td>Trebuchet MS</td> + <td>sans-serif</td> + <td>You should be careful with using this font — it isn't widely available on mobile OSes.</td> + </tr> + <tr> + <td>Verdana</td> + <td>sans-serif</td> + <td></td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Note</strong>: Among various resources, the <a href="http://www.cssfontstack.com/">cssfontstack.com</a> website maintains a list of web safe fonts available on Windows and macOS operating systems, which can help you make your decision about what you consider safe for your usage.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: There is a way to download a custom font along with a webpage, to allow you to customize your font usage in any way you want: <strong>web fonts</strong>. This is a little bit more complex, and we will be discussing this in a <a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">separate article</a> later on in the module.</p> +</div> + +<h4 id="Default_fonts">Default fonts</h4> + +<p>CSS defines five generic names for fonts: <code>serif</code><font face="Open Sans, Arial, sans-serif">, </font><code>sans-serif</code>,<font face="Open Sans, Arial, sans-serif"> </font><code>monospace</code>, <code>cursive</code> and <code>fantasy</code>. Those are very generic and the exact font face used when using those generic names is up to each browser and can vary for each operating system they are running on. It represents a <em>worst case scenario</em> where the browser will try to do its best to provide at least a font that looks appropriate. <code>serif</code>, <code>sans-serif</code> and <code>monospace</code> are quite predictable and should provide something reasonable. On the other hand, <code>cursive</code> and <code>fantasy</code> are less predictable and we recommend using them very carefully, testing as you go.</p> + +<p>The five names are defined as follows:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Term</th> + <th scope="col">Definition</th> + <th scope="col">Example</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>serif</code></td> + <td>Fonts that have serifs (the flourishes and other small details you see at the ends of the strokes in some typefaces)</td> + <td><span style="font-family: serif;">My big red elephant</span></td> + </tr> + <tr> + <td><code>sans-serif</code></td> + <td>Fonts that don't have serifs.</td> + <td><span style="font-family: sans-serif;">My big red elephant</span></td> + </tr> + <tr> + <td><code>monospace</code></td> + <td>Fonts where every character has the same width, typically used in code listings.</td> + <td><span style="font-family: monospace;">My big red elephant</span></td> + </tr> + <tr> + <td><code>cursive</code></td> + <td>Fonts that are intended to emulate handwriting, with flowing, connected strokes.</td> + <td><span style="font-family: cursive;">My big red elephant</span></td> + </tr> + <tr> + <td><code>fantasy</code></td> + <td>Fonts that are intended to be decorative.</td> + <td><span style="font-family: fantasy;">My big red elephant</span></td> + </tr> + </tbody> +</table> + +<h4 id="Font_stacks">Font stacks</h4> + +<p>Since you can't guarantee the availability of the fonts you want to use on your webpages (even a web font <em>could</em> fail for some reason), you can supply a <strong>font stack</strong> so that the browser has multiple fonts it can choose from. This simply involves a <code>font-family</code> value consisting of multiple font names separated by commas, e.g.</p> + +<pre class="brush: css notranslate">p { + font-family: "Trebuchet MS", Verdana, sans-serif; +}</pre> + +<p>In such a case, the browser starts at the beginning of the list and looks to see if that font is available on the machine. If it is, it applies that font to the selected elements. If not, it moves on to the next font, and so on.</p> + +<p>It is a good idea to provide a suitable generic font name at the end of the stack so that if none of the listed fonts are available, the browser can at least provide something approximately suitable. To emphasise this point, paragraphs are given the browser's default serif font if no other option is available — which is usually Times New Roman — this is no good for a sans-serif font!</p> + +<div class="note"> +<p><strong>Note</strong>: Font names that have more than one word — like <code>Trebuchet MS</code> — need to be surrounded by quotes, for example <code>"Trebuchet MS"</code>.</p> +</div> + +<h4 id="A_font-family_example">A font-family example</h4> + +<p>Let's add to our previous example, giving the paragraphs a sans-serif font:</p> + +<pre class="brush: css notranslate">p { + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> + +<p>This gives us the following result:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Tommy the cat</h1> + +<p>Well I remember it as though it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p></pre> +</div> + +<p>{{ EmbedLiveSample('A_font-family_example', '100%', 220) }}</p> + +<h3 id="Font_size">Font size</h3> + +<p>In our previous module's <a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">CSS values and units</a> article, we reviewed length and size units. Font size (set with the {{cssxref("font-size")}} property) can take values measured in most of these units (and others, such as <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Percentages">percentages</a>), however the most common units you'll use to size text are:</p> + +<ul> + <li><code>px</code> (pixels): The number of pixels high you want the text to be. This is an absolute unit — it results in the same final computed value for the font on the page in pretty much any situation.</li> + <li><code>em</code>s: 1 <code>em</code> is equal to the font size set on the parent element of the current element we are styling (more specifically, the width of a capital letter M contained inside the parent element.) This can become tricky to work out if you have a lot of nested elements with different font sizes set, but it is doable, as you'll see below. Why bother? It is quite natural once you get used to it, and you can use <code>em</code> to size everything, not just text. You can have an entire website sized using <code>em</code>, which makes maintenance easy.</li> + <li><code>rem</code>s: These work just like <code>em</code>, except that 1 <code>rem</code> is equal to the font size set on the root element of the document (i.e. {{htmlelement("html")}}), not the parent element. This makes doing the maths to work out your font sizes much easier, although if you want to support really old browsers, you might struggle — <code>rem</code> is not supported in Internet Explorer 8 and below.</li> +</ul> + +<p>The <code>font-size</code> of an element is inherited from that element's parent element. This all starts with the root element of the entire document — {{htmlelement("html")}} — the <code>font-size</code> of which is set to 16<code>px</code> as standard across browsers. Any paragraph (or another element that doesn't have a different size set by the browser) inside the root element will have a final size of 16 <code>px</code>. Other elements may have different default sizes, for example an {{htmlelement("h1")}} element has a size of 2 <code>em</code> set by default, so it will have a final size of 32 <code>px</code>.</p> + +<p>Things become more tricky when you start altering the font size of nested elements. For example, if you had an {{htmlelement("article")}} element in your page, and set its <code>font-size</code> to 1.5 <code>em</code> (which would compute to 24 <code>px</code> final size), and then wanted the paragraphs inside the <code><article></code> elements to have a computed font size of 20 <code>px</code>, what <code>em</code> value would you use?</p> + +<pre class="brush: html notranslate"><!-- document base font-size is 16px --> +<article> <!-- If my font-size is 1.5em --> + <p>My paragraph</p> <!-- How do I compute to 20px font-size? --> +</article></pre> + +<p>You would need to set its <code>em</code> value to 20/24, or 0.83333333 <code>em</code>. The maths can be complicated, so you need to be careful about how you style things. It is best to use <code>rem</code> where you can, to keep things simple, and avoid setting the <code>font-size</code> of container elements where possible.</p> + +<h4 id="A_simple_sizing_example">A simple sizing example</h4> + +<p>When sizing your text, it is usually a good idea to set the base <code>font-size</code> of the document to 10 <code>px</code>, so that then the maths is a lot easier to work out — required <code>(r)em</code> values are then the pixel font size divided by 10, not 16. After doing that, you can easily size the different types of text in your document to what you want. It is a good idea to list all your <code>font-size</code> rulesets in a designated area in your stylesheet, so they are easy to find.</p> + +<p>Our new result is like so:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Tommy the cat</h1> + +<p>Well I remember it as though it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> +</div> + +<pre class="brush: css notranslate">html { + font-size: 10px; +} + +h1 { + font-size: 5rem; +} + +p { + font-size: 1.5rem; + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> + +<p>{{ EmbedLiveSample('A_simple_sizing_example', '100%', 260) }}</p> + +<h3 id="Font_style_font_weight_text_transform_and_text_decoration">Font style, font weight, text transform, and text decoration</h3> + +<p>CSS provides four common properties to alter the visual weight/emphasis of text:</p> + +<ul> + <li>{{cssxref("font-style")}}: Used to turn italic text on and off. Possible values are as follows (you'll rarely use this, unless you want to turn some italic styling off for some reason): + <ul> + <li><code>normal</code>: Sets the text to the normal font (turns existing italics off.)</li> + <li><code>italic</code>: Sets the text to use the <em>italic version of the font</em> if available; if not available, it will simulate italics with oblique instead.</li> + <li><code>oblique</code>: Sets the text to use a simulated version of an italic font, created by <span style="font-style: oblique;">slanting the normal version</span>.</li> + </ul> + </li> + <li>{{cssxref("font-weight")}}: Sets how bold the text is. This has many values available in case you have many font variants available (such as <em>-light</em>, <em>-normal</em>, <em>-bold</em>, <em>-extrabold</em>, <em>-black</em>, etc.), but realistically you'll rarely use any of them except for <code>normal</code> and <code>bold</code>: + <ul> + <li><code>normal</code>, <code>bold</code>: Normal and <strong style="font-weight: bold;">bold</strong> font weight</li> + <li><code>lighter</code>, <code>bolder</code>: Sets the current element's boldness to be one step lighter or heavier than its parent element's boldness.</li> + <li><code>100</code>–<code>900</code>: Numeric boldness values that provide finer grained control than the above keywords, if needed. </li> + </ul> + </li> + <li>{{cssxref("text-transform")}}: Allows you to set your font to be transformed. Values include: + <ul> + <li><code>none</code>: Prevents any transformation.</li> + <li><code>uppercase</code>: Transforms <span style="text-transform: uppercase;">all text to capitals</span>.</li> + <li><code>lowercase</code>: Transforms all text to lower case.</li> + <li><code>capitalize</code>: Transforms all words to <span style="text-transform: capitalize;">have the first letter capitalized</span>.</li> + <li><code>full-width</code>: Transforms all glyphs to be <span style="text-transform: full-width;">written inside a fixed-width square</span>, similar to a monospace font, allowing aligning of e.g. Latin characters along with Asian language glyphs (like Chinese, Japanese, Korean).</li> + </ul> + </li> + <li>{{cssxref("text-decoration")}}: Sets/unsets text decorations on fonts (you'll mainly use this to unset the default underline on links when styling them.) Available values are: + <ul> + <li><code>none</code>: Unsets any text decorations already present.</li> + <li><code>underline</code>: <u>Underlines the text</u>.</li> + <li><code>overline</code>: <span style="text-decoration: overline;">Gives the text an overline</span>.</li> + <li><code>line-through</code>: Puts a <s style="text-decoration: line-through;">strikethrough over the text</s>.</li> + </ul> + You should note that {{cssxref("text-decoration")}} can accept multiple values at once, if you want to add multiple decorations simultaneously, for example <span style="text-decoration: underline overline;"><code>text-decoration: underline overline</code></span>. Also note that {{cssxref("text-decoration")}} is a shorthand property for {{cssxref("text-decoration-line")}}, {{cssxref("text-decoration-style")}}, and {{cssxref("text-decoration-color")}}. You can use combinations of these property values to create interesting effects, for example <span style="text-decoration: line-through red wavy;"><code>text-decoration: line-through red wavy</code>.</span></li> +</ul> + +<p>Let's look at adding a couple of these properties to our example:</p> + +<p>Our new result is like so:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Tommy the cat</h1> + +<p>Well I remember it as though it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> +</div> + +<pre class="brush: css notranslate">html { + font-size: 10px; +} + +h1 { + font-size: 5rem; + text-transform: capitalize; +} + +h1 + p { + font-weight: bold; +} + +p { + font-size: 1.5rem; + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> + +<p>{{ EmbedLiveSample('Font_style_font_weight_text_transform_and_text_decoration', '100%', 260) }}</p> + +<h3 id="Text_drop_shadows">Text drop shadows</h3> + +<p>You can apply drop shadows to your text using the {{cssxref("text-shadow")}} property. This takes up to four values, as shown in the example below:</p> + +<pre class="brush: css notranslate">text-shadow: 4px 4px 5px red;</pre> + +<p>The four properties are as follows:</p> + +<ol> + <li>The horizontal offset of the shadow from the original text — this can take most available CSS <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Length_and_size">length and size units</a>, but you'll most commonly use <code>px</code>; positive values move the shadow right, and negative values left. This value has to be included.</li> + <li>The vertical offset of the shadow from the original text; behaves basically just like the horizontal offset, except that it moves the shadow up/down, not left/right. This value has to be included.</li> + <li>The blur radius — a higher value means the shadow is dispersed more widely. If this value is not included, it defaults to 0, which means no blur. This can take most available CSS <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Length_and_size">length and size units</a>.</li> + <li>The base color of the shadow, which can take any <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Colors">CSS color unit</a>. If not included, it defaults to <code>black</code>.</li> +</ol> + +<h4 id="Multiple_shadows">Multiple shadows</h4> + +<p>You can apply multiple shadows to the same text by including multiple shadow values separated by commas, for example:</p> + +<pre class="brush: css notranslate">text-shadow: 1px 1px 1px red, + 2px 2px 1px red;</pre> + +<p>If we applied this to the {{htmlelement("h1")}} element in our Tommy the cat example, we'd end up with this:</p> + +<div class="hidden"> +<h5 id="Hidden_example1">Hidden example1</h5> + +<pre class="brush: html notranslate"><h1>Tommy the cat</h1> + +<p>Well I remember it as though it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> + +<pre class="brush: css notranslate">html { + font-size: 10px; +} + +h1 { + font-size: 5rem; + text-transform: capitalize; + text-shadow: 1px 1px 1px red, + 2px 2px 1px red; +} + +h1 + p { + font-weight: bold; +} + +p { + font-size: 1.5rem; + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_example1', '100%', 260) }}</p> + +<div class="note"> +<p><strong>Note</strong>: You can see more interesting examples of <code>text-shadow</code> usage in the Sitepoint article <a href="http://www.sitepoint.com/moonlighting-css-text-shadow/">Moonlighting with CSS text-shadow</a>.</p> +</div> + +<h2 id="Text_layout">Text layout</h2> + +<p>With basic font properties out the way, let's now have a look at properties we can use to affect text layout.</p> + +<h3 id="Text_alignment">Text alignment</h3> + +<p>The {{cssxref("text-align")}} property is used to control how text is aligned within its containing content box. The available values are as follows, and work in pretty much the same way as they do in a regular word processor application:</p> + +<ul> + <li><code>left</code>: Left-justifies the text.</li> + <li><code>right</code>: Right-justifies the text.</li> + <li><code>center</code>: Centers the text.</li> + <li><code>justify</code>: Makes the text spread out, varying the gaps in between the words so that all lines of text are the same width. You need to use this carefully — it can look terrible, especially when applied to a paragraph with lots of long words in it. If you are going to use this, you should also think about using something else along with it, such as {{cssxref("hyphens")}}, to break some of the longer words across lines.</li> +</ul> + +<p>If we applied <code>text-align: center;</code> to the {{htmlelement("h1")}} in our example, we'd end up with this:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Tommy the cat</h1> + +<p>Well I remember it as though it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> + +<pre class="brush: css notranslate">html { + font-size: 10px; +} + +h1 { + font-size: 5rem; + text-transform: capitalize; + text-shadow: 1px 1px 1px red, + 2px 2px 1px red; + text-align: center; +} + +h1 + p { + font-weight: bold; +} + +p { + font-size: 1.5rem; + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Text_alignment', '100%', 260) }}</p> + +<h3 id="Line_height">Line height</h3> + +<p>The {{cssxref("line-height")}} property sets the height of each line of text — this can take most <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Length_and_size">length and size units</a>, but can also take a unitless value, which acts as a multiplier and is generally considered the best option — the {{cssxref("font-size")}} is multiplied to get the <code>line-height</code>. Body text generally looks nicer and is easier to read when the lines are spaced apart; the recommended line height is around 1.5 – 2 (double spaced.) So to set our lines of text to 1.6 times the height of the font, you'd use this:</p> + +<pre class="brush: css notranslate">line-height: 1.6;</pre> + +<p>Applying this to the {{htmlelement("p")}} elements in our example would give us this result:</p> + +<div class="hidden"> +<h5 id="Hidden_example2">Hidden example2</h5> + +<pre class="brush: html notranslate"><h1>Tommy the cat</h1> + +<p>Well I remember it as though it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> + +<pre class="brush: css notranslate">html { + font-size: 10px; +} + +h1 { + font-size: 5rem; + text-transform: capitalize; + text-shadow: 1px 1px 1px red, + 2px 2px 1px red; + text-align: center; +} + +h1 + p { + font-weight: bold; +} + +p { + font-size: 1.5rem; + color: red; + font-family: Helvetica, Arial, sans-serif; + line-height: 1.6; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_example2', '100%', 300) }}</p> + +<h3 id="Letter_and_word_spacing">Letter and word spacing</h3> + +<p>The {{cssxref("letter-spacing")}} and {{cssxref("word-spacing")}} properties allow you to set the spacing between letters and words in your text. You won't use these very often, but might find a use for them to get a certain look, or to improve the legibility of a particularly dense font. They can take most <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Length_and_size">length and size units</a>.</p> + +<p>So as an example, we could apply some word- and letter-spacing to the first line of each {{htmlelement("p")}} element in our example:</p> + +<pre class="brush: css notranslate">p::first-line { + letter-spacing: 4px; + word-spacing: 4px; +}</pre> + +<p>Let's add some to our example, like so:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><h1>Tommy the cat</h1> + +<p>Well I remember it as though it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> + +<pre class="brush: css notranslate">html { + font-size: 10px; +} + +h1 { + font-size: 5rem; + text-transform: capitalize; + text-shadow: 1px 1px 1px red, + 2px 2px 1px red; + text-align: center; + letter-spacing: 2px; +} + +h1 + p { + font-weight: bold; +} + +p::first-line { + letter-spacing: 4px; + word-spacing: 4px; +} + +p { + font-size: 1.5rem; + color: red; + font-family: Helvetica, Arial, sans-serif; + line-height: 1.6; + letter-spacing: 1px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Letter_and_word_spacing', '100%', 330) }}</p> + +<h3 id="Other_properties_worth_looking_at">Other properties worth looking at</h3> + +<p>The above properties give you an idea of how to start styling text on a webpage, but there are many more properties you could use. We just wanted to cover the most important ones here. Once you've become used to using the above, you should also explore the following:</p> + +<p>Font styles:</p> + +<ul> + <li>{{cssxref("font-variant")}}: Switch between small caps and normal font alternatives.</li> + <li>{{cssxref("font-kerning")}}: Switch font kerning options on and off.</li> + <li>{{cssxref("font-feature-settings")}}: Switch various <a href="https://en.wikipedia.org/wiki/OpenType">OpenType</a> font features on and off.</li> + <li>{{cssxref("font-variant-alternates")}}: Control the use of alternate glyphs for a given font-face.</li> + <li>{{cssxref("font-variant-caps")}}: Control the use of alternate capital glyphs.</li> + <li>{{cssxref("font-variant-east-asian")}}: Control the usage of alternate glyphs for East Asian scripts, like Japanese and Chinese.</li> + <li>{{cssxref("font-variant-ligatures")}}: Control which ligatures and contextual forms are used in text.</li> + <li>{{cssxref("font-variant-numeric")}}: Control the usage of alternate glyphs for numbers, fractions, and ordinal markers.</li> + <li>{{cssxref("font-variant-position")}}: Control the usage of alternate glyphs of smaller sizes positioned as superscript or subscript.</li> + <li>{{cssxref("font-size-adjust")}}: Adjust the visual size of the font independently of its actual font size.</li> + <li>{{cssxref("font-stretch")}}: Switch between possible alternative stretched versions of a given font.</li> + <li>{{cssxref("text-underline-position")}}: Specify the position of underlines set using the <code>text-decoration-line</code> property <code>underline</code> value.</li> + <li>{{cssxref("text-rendering")}}: Try to perform some text rendering optimization.</li> +</ul> + +<p>Text layout styles:</p> + +<ul> + <li>{{cssxref("text-indent")}}: Specify how much horizontal space should be left before the beginning of the first line of the text content.</li> + <li>{{cssxref("text-overflow")}}: Define how overflowed content that is not displayed is signaled to users.</li> + <li>{{cssxref("white-space")}}: Define how whitespace and associated line breaks inside the element are handled.</li> + <li>{{cssxref("word-break")}}: Specify whether to break lines within words.</li> + <li>{{cssxref("direction")}}: Define the text direction (This depends on the language and usually it's better to let HTML handle that part as it is tied to the text content.)</li> + <li>{{cssxref("hyphens")}}: Switch on and off hyphenation for supported languages.</li> + <li>{{cssxref("line-break")}}: Relax or strengthen line breaking for Asian languages.</li> + <li>{{cssxref("text-align-last")}}: Define how the last line of a block or a line, right before a forced line break, is aligned.</li> + <li>{{cssxref("text-orientation")}}: Define the orientation of the text in a line.</li> + <li>{{cssxref("overflow-wrap")}}: Specify whether or not the browser may break lines within words in order to prevent overflow.</li> + <li>{{cssxref("writing-mode")}}: Define whether lines of text are laid out horizontally or vertically and the direction in which subsequent lines flow.</li> +</ul> + +<h2 id="Font_shorthand">Font shorthand</h2> + +<p>Many font properties can also be set through the shorthand property {{cssxref("font")}}. These are written in the following order: {{cssxref("font-style")}}, {{cssxref("font-variant")}}, {{cssxref("font-weight")}}, {{cssxref("font-stretch")}}, {{cssxref("font-size")}}, {{cssxref("line-height")}}, and {{cssxref("font-family")}}.</p> + +<p>Among all those properties, only <code>font-size</code> and <code>font-family</code> are required when using the <code>font</code> shorthand property.</p> + +<p>A forward slash has to be put in between the {{cssxref("font-size")}} and {{cssxref("line-height")}} properties.</p> + +<p>A full example would look like this:</p> + +<pre class="brush: css notranslate">font: italic normal bold normal 3em/1.5 Helvetica, Arial, sans-serif;</pre> + +<h2 id="Active_learning_Playing_with_styling_text">Active learning: Playing with styling text</h2> + +<p>In this active learning session, we don't have any specific exercises for you to do: we'd just like you to have a good play with some font/text layout properties, and see what you can produce! You can either do this using offline HTML/CSS files, or enter your code into the live editable example below.</p> + +<p>If you make a mistake, you can always reset it using the <em>Reset</em> button.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><div class="body-wrapper" style="font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;"> + <h2>HTML Input</h2> + <textarea id="code" class="html-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"> +<p>Some sample text for your delight</p> + </textarea> + + <h2>CSS Input</h2> + <textarea id="code" class="css-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"> +p { + +} +</textarea> + + <h2>Output</h2> + <div class="output" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"></div> + <div class="controls"> + <input id="reset" type="button" value="Reset" style="margin: 10px 10px 0 0;"> + </div> +</div> +</pre> + +<pre class="brush: js notranslate">const htmlInput = document.querySelector(".html-input"); +const cssInput = document.querySelector(".css-input"); +const reset = document.getElementById("reset"); +let htmlCode = htmlInput.value; +let cssCode = cssInput.value; +const output = document.querySelector(".output"); + +const styleElem = document.createElement('style'); +const headElem = document.querySelector('head'); +headElem.appendChild(styleElem); + +function drawOutput() { + output.innerHTML = htmlInput.value; + styleElem.textContent = cssInput.value; +} + +reset.addEventListener("click", function() { + htmlInput.value = htmlCode; + cssInput.value = cssCode; + drawOutput(); +}); + +htmlInput.addEventListener("input", drawOutput); +cssInput.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 800) }}</p> + +<h2 id="Test_your_skills!">Test your skills!</h2> + +<p>You've reached the end of this article, and already did some skill testing in our Active Learning section, but can you remember the most important information going forward? You can find an assessment to verify that you've retained this information at the end of the module — see <a href="/en-US/docs/Learn/CSS/Styling_text/Typesetting_a_homepage">Typesetting a community school homepage</a>.</p> + +<p>This assessment tests all the knowledge discussed in this module, so you might want to read the other articles before moving on to it.</p> + +<h2 id="Summary">Summary</h2> + +<p>We hoped you enjoyed playing with text in this article! The next article will give you all you need to know about styling HTML lists.</p> + +<p>{{NextMenu("Learn/CSS/Styling_text/Styling_lists", "Learn/CSS/Styling_text")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Fundamental text and font styling</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">Styling lists</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_links">Styling links</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">Web fonts</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Typesetting_a_homepage">Typesetting a community school homepage</a></li> +</ul> diff --git a/files/ru/learn/css/styling_text/index.html b/files/ru/learn/css/styling_text/index.html new file mode 100644 index 0000000000..8a696e55df --- /dev/null +++ b/files/ru/learn/css/styling_text/index.html @@ -0,0 +1,60 @@ +--- +title: Стилизирование текста +slug: Learn/CSS/Styling_text +tags: + - CSS + - CodingScripting + - Module + - NeedsTranslation + - Text + - TopicStub + - letter + - line + - Начинающий + - Ссылки + - Текст + - Шрифты + - веб шрифты + - лендинг + - примеры кода + - списки + - тени + - шрифт +translation_of: Learn/CSS/Styling_text +--- +<p id="Перед_стартом"> {{LearnSidebar}}</p> + +<p>Разобравшись с основами синтаксиса CSS, следующей темой над которой вам следует сосредоточиться, это стилизация текста — одна из наиболее распространенных вещей, которые вы будете делать с помощью CSS. В этой теме мы рассмотрим основные принципы оформления, включая выбор и определение шрифтов, использование курсива и жирного шрифта, отступов, теней и других средств придания уникальности вашему тексту. В завершение темы мы рассмотрим использование на вашей странице пользовательских шрифтов, а также оформление списков и ссылок</p> + +<h2 id="Необходимые_условия">Необходимые условия</h2> + +<p>Перед началом работы с этим модулем, вы должны уже иметь базовые знания HTML, как это описано во <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>, и с основами CSS, как описано в <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a>.</p> + +<div class="note"> +<p><strong>Замечание</strong>: В случае, если вы работаете на компьютере, планшете или ином устройстве, на котором у вас нет возможности создавать свои собственные файлы, вы можете попробовать выполнить примеры кода (по крайней мере, большинство из них) в специальных онлайн-программах, таких как <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководство">Руководство</h2> + +<p>Данный модуль состоит из следующих далее статей, которые дадут вам всё необходимое для оформления текстового HTML-контента.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Основы стилизирования текcта и шрифта</a></dt> + <dd>В этой статье мы детально изучим стилизирование текста и шрифта, включая параметры weight, family, style, font shorthand, text alignment и прочие эффекты, а так же line и letter spacing.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">Стилизирование списков</a></dt> + <dd>Списки, по большей части, ведут себе так же, как и любой другой текст, но они имеют некоторые особые CSS свойства о которых нужно знать, и<br> + некоторые методы которые стоит принять во внимание. Эта статья все разъясняет.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_links">Стилизирование ссылок</a></dt> + <dd>При стилизации ссылок важно понимать, как эффективно использовать псевдоклассы для стилизации состояний ссылок, и как стилизовать ссылки для использования в общих разнообразных функциях интерфейса, таких как навигационные меню и вкладки. Мы рассмотрим все эти темы в этой статье.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">Веб-шрифты</a></dt> + <dd>Здесь мы подробно рассмотрим веб-шрифты — они позволяют загружать пользовательские шрифты вместе с вашей веб-страницей, чтобы обеспечить более разнообразный, индивидуальный стиль текста.</dd> +</dl> + +<h2 id="Проверка">Проверка</h2> + +<p>Следующие задания проверят ваше понимание методов стилизации текста, описанных в вышеприведенных руководствах.</p> + +<dl> + <dt><a href="/en-US/Learn/CSS/Styling_text/Typesetting_a_homepage">Вёрстка домашней страницы муниципальной школы</a></dt> + <dd>В этом задании мы проверим ваше понимание стилизации текста, <span class="samTranslation"><span class="sourceSample">заставив</span> вас</span> оформить текст для домашней страницы общеобразовательной школы.</dd> +</dl> diff --git a/files/ru/learn/css/styling_text/styling_links/index.html b/files/ru/learn/css/styling_text/styling_links/index.html new file mode 100644 index 0000000000..29ecf37729 --- /dev/null +++ b/files/ru/learn/css/styling_text/styling_links/index.html @@ -0,0 +1,420 @@ +--- +title: Стилизация ссылок +slug: Learn/CSS/Styling_text/Styling_links +translation_of: Learn/CSS/Styling_text/Styling_links +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/Styling_text/Styling_lists", "Learn/CSS/Styling_text/Web_fonts", "Learn/CSS/Styling_text")}}</div> + +<p class="summary">При стилизации ссылок, важно понимать как использовать псевдо-классы, чтобы стилизировать состояния ссылок эфективно, и как стилизировать ссылки для использования в общих разнообразных функциях интерфейса: таких как например навигационное меню и вкладки. Мы расмотрим все эти темы в этой статье.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Для изучения вам потребуется:</th> + <td>Основы компьютерной грамотности, базовые знания HTML (изучите <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), основы CSS (изучите <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a>), <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Styling_text/Fundamentals">базовые знания о текстах и шрифтах CSS</a>.</td> + </tr> + <tr> + <th scope="row">Вы узнаете:</th> + <td>Изучите как стилизуются ссылки и как использовать ссылки эффективно в общих задачах UI (пользовательских интерфейсах), например, в меню навигации.</td> + </tr> + </tbody> +</table> + +<h2 id="Давайте_посмотрим_на_некоторые_ссылки">Давайте посмотрим на некоторые ссылки</h2> + +<p>Мы рассматривали как реализуются ссылки в вашем HTML в соответствии с лучшими практиками в <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создании гиперссылок</a>. <span class="tlid-translation translation" lang="ru"><span title="">В этой статье мы будем опираться на эти знания, показывая вам лучшие практики по оформлению ссылок.</span></span></p> + +<h3 id="Состояния_ссылок">Состояния ссылок</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Первое, что нужно понять, это концепция состояний ссылок </span></span>— разные состояния в которых могут существовать ссылки, которые могут быть стилизованы используя различные <a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Pseudo-classes">псевдоклассы</a>:</p> + +<ul> + <li><strong>Link (не посещенная)</strong>: <span class="tlid-translation translation" lang="ru"><span title="">Состояние по умолчанию, в котором находится ссылка</span></span>, когда она не находится в каком-либо другом состоянии. Она может быть специфически стилизована используя псевдокласс {{cssxref(":link")}}.</li> + <li><strong>Visited</strong>: Ссылка, когда она уже была посещена (существует в истории браузера), стилизуется используя псевдокласс {{cssxref(":visited")}}.</li> + <li><strong>Hover</strong>: Ссылка, когда на нее наведен курсор мыши, стилизуется используя псевдокласс {{cssxref(":hover")}}</li> + <li><strong>Focus</strong>: Ссылка, когда она была сфокусирована (например когда пользователь переместился на нее используя клавишу <kbd>Tab</kbd> или наподобие или программно сфокусирована используя {{domxref("HTMLElement.focus()")}}) — стилизуется используя псевдокласс {{cssxref(":focus")}}.</li> + <li><strong>Active</strong>: Ссылка, когда она активируется (например при клике по ней), стилизуется используя псевдокласс {{cssxref(":active")}}</li> +</ul> + +<h3 id="Стили_по_умолчанию">Стили по умолчанию</h3> + +<p>Следующий пример показывает, как будет вести себя ссылка по умолчанию (CSS просто увеличивает и центрирует текст чтоб больше выделить его).</p> + +<pre class="brush: html"><p><a href="https://mozilla.org">A link to the Mozilla homepage</a></p> +</pre> + +<pre class="brush: css">p { + font-size: 2rem; + text-align: center; +}</pre> + +<p>{{ EmbedLiveSample('Стили_по_умолчанию', '100%', 120) }}</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы заметите несколько вещей при изучении стилей по умолчанию</span></span>:</p> + +<ul> + <li>Ссылки подчеркнуты.</li> + <li>Не посещенные ссылки синие.</li> + <li>Посещенные ссылки фиолетовые</li> + <li>Наведение курсора мыши на ссылку меняют указатель мыши на иконку маленькой руки.</li> + <li>Сфокусированные ссылки имеют контур вокруг себя — <span class="tlid-translation translation" lang="ru"><span title="">вы можете сфокусироваться на ссылках на этой странице с помощью клавиатуры, нажав клавишу табуляции (на </span></span>Mac, вам может понадобиться включить опцию <em>Full Keyboard Access: All controls </em>нажав <kbd>Ctrl</kbd> + <kbd>F7</kbd><span style='font-family: "Times New Roman",serif; font-size: 12.0pt; line-height: 200%;'>,</span> прежде чем это будет работать<span class="tlid-translation translation" lang="ru"><span title="">).</span></span></li> + <li>Активные ссылки красные (попробуйте удерживать кнопку мыши на ссылке, когда вы кликните по ней).</li> +</ul> + +<p>Довольно интересно, что эти стили по умолчанию приблизительно такие же какими они были в первые дни браузеров в середине 1990-ых. Это потому, что пользователи знают и привыкли ожидать такого поведения — если бы ссылки были стилизованы по-разному, это бы путало много людей. Это не значит, что вы недолжны стилизовать ссылки совсем, просто вы не должны уходить слишком далеко от ожидаемого поведения. По крайней мере вы должны:</p> + +<ul> + <li>Использовать нижнее подчеркивание для ссылок, но не для других вещей. Если вы не хотите подчеркивать ссылки, то хотя бы выделите их каким-либо другим путем.</li> + <li>Сделать так чтобы они как-нибудь реагировали на наведение/фокусировку на них и немного отличались после активации.</li> +</ul> + +<p>Стили по умолчанию могут быть выключены/изменены, используя следующие свойства CSS:</p> + +<ul> + <li>{{cssxref("color")}} для цвета текста.</li> + <li>{{cssxref("cursor")}} для стиля курсора мыши — вы не должны отключать эту опцию только если у вас нет на это веской причины.</li> + <li>{{cssxref("outline")}} для контура текста (контур схож с границей, единственное отличие — это то, что границы занимают место в блоке, а контур — нет; он просто располагается поверх фона). Контур <span class="tlid-translation translation" lang="ru"><span title="">является полезным вспомогательным средством</span></span>, так что подумайте хорошо, прежде чем отключать его; по крайней мере вы должны удвоить стили, заданные для состояния hover, а также состояния фокусировки.</li> +</ul> + +<div class="note"> +<p><strong>Обратите внимание</strong>: Вы не ограничены только перечисленными выше свойствами чтобы стилизовать ссылки — <span class="tlid-translation translation" lang="ru"><span title="">вы можете использовать любые свойства, которые вам нравятся. </span></span> <span class="tlid-translation translation" lang="ru"><span title="">Просто постарайтесь не сходить с ума слишком сильно!</span></span></p> +</div> + +<h3 id="Стилизация_некоторых_ссылок">Стилизация некоторых ссылок</h3> + +<p>Мы уже рассмотрели состояния по умолчанию в некоторых деталях, давайте взглянем на типичный набор стилей ссылок.</p> + +<p>Чтобы начать, мы выпишем наши пустые наборы правил:</p> + +<pre class="brush: css">a { + +} + + +a:link { + +} + +a:visited { + +} + +a:focus { + +} + +a:hover { + +} + +a:active { + +}</pre> + +<p>Этот порядок важен так как стили ссылок опираются друг на друга, например стили в первом правиле будут применяться ко всем последующим правилам и когда ссылка будет активирована, она также будет находиться под "наведением" (hover). Если вы введете их в неправильном порядке, стили не будут работать правильно. Чтобы запомнить этот порядок вы можете попробовать использовать мнемонику типа <strong>L</strong>o<strong>V</strong>e <strong>F</strong>ears <strong>HA</strong>te.</p> + +<p>А теперь давайте добавим еще немного информации <span class="tlid-translation translation" lang="ru"><span title="">чтобы правильно оформить этот стиль:</span></span></p> + +<pre class="brush: css">body { + width: 300px; + margin: 0 auto; + font-size: 1.2rem; + font-family: sans-serif; +} + +p { + line-height: 1.4; +} + +a { + outline: none; + text-decoration: none; + padding: 2px 1px 0; +} + +a:link { + color: #265301; +} + +a:visited { + color: #437A16; +} + +a:focus { + border-bottom: 1px solid; + background: #BAE498; +} + +a:hover { + border-bottom: 1px solid; + background: #CDFEAA; +} + +a:active { + background: #265301; + color: #CDFEAA; +}</pre> + +<p>Также мы дадим некий пример HTML к которому применяется CSS:</p> + +<pre class="brush: html"><p>There are several browsers available, such as <a href="https://www.mozilla.org/en-US/firefox/">Mozilla +Firefox</a>, <a href="https://www.google.com/chrome/index.html">Google Chrome</a>, and +<a href="https://www.microsoft.com/en-us/windows/microsoft-edge">Microsoft Edge</a>.</p></pre> + +<p>Объединение этих двух дает нам такой результат:</p> + +<p>{{ EmbedLiveSample('Стилизация_некоторых_ссылок', '100%', 150) }}</p> + +<p>Итак, что мы сделали тут? Это определенно выглядит иначе чем стилизация по умолчанию, но <span class="tlid-translation translation" lang="ru"><span title="">все еще дает достаточно знакомый опыт для пользователей, чтобы знать, что происходит:</span></span></p> + +<ul> + <li>Первые два правила не так интересны в этом обсуждении.</li> + <li>Третье правило использует селектор <code>a</code> чтобы избавиться от подчеркивания текста и контура фокуса по умолчанию (которые все равно варьируют в зависимости от браузера), а также добавляет малое количество padding к каждой ссылке — все это станет ясно позже.</li> + <li>Далее, мы используем селекторы <code>a:link</code> и <code>a:visited</code> чтобы настроить пару цветовых вариаций не посещенных и посещенных ссылок, так чтоб они отличались.</li> + <li>Следующие два правила используют <code>a:focus</code> и <code>a:hover</code> настраивают сфокусированные и наведенные (hovered) ссылки таким образом чтобы они имели разные фоновые цвета, плюс нижнее подчеркивание чтобы ссылка выделялась еще больше. Два пункта на которые надо обратить внимание: + <ul> + <li>Нижнее подчеркивание создано используя {{cssxref("border-bottom")}}, а не {{cssxref("text-decoration")}} — некоторые люди предпочитают это потому что первый имеет лучшие варианты стилизации, чем второй, и отрисован немного ниже, так что не срезает нижние элементы слов будучи подчеркнутыми (например хвосты у букв как "р" и "у").</li> + <li>Значение {{cssxref("border-bottom")}} установлено на <code>1px solid</code>, без определенного цвета. Это позволяет границам принимать тот же цвет что и элементы текста, что полезно в случае как этом, где текст имеет разные цвета в каждом случае.</li> + </ul> + </li> + <li>Наконец, <code>a:active</code> используется чтобы дать ссылкам инвертированную цветовую схему в то время когда они активированы, чтобы было ясно что происходит что то важное!</li> +</ul> + +<h3 id="Активное_изучение_Стилизуйте_ссылки_самостояельно">Активное изучение: Стилизуйте ссылки самостояельно</h3> + +<p>В этой секции активного изучения, мы бы хотели, чтобы взяли наш набор пустых правил и добавили ваши собственные объявления так чтобы ссылки выглядели действительно круто. Используйте свое воображение, не сковывайтесь. Мы уверены, что вы можете придумать что-то более крутое и все еще так же функциональное, как и наш пример выше.</p> + +<p>Если вы допустите ошибку, вы всегда можете сделать сброс используя кнопку <em>Reset</em>. Если вы действительно застряли нажмите кнопку <em>Show solution</em> чтобы вставить пример, который мы показали выше.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html"><div class="body-wrapper" style="font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;"> + <h2>HTML Input</h2> + <textarea id="code" class="html-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"><p>There are several browsers available, such as <a href="https://www.mozilla.org/en-US/firefox/">Mozilla + Firefox</a>, <a href="https://www.google.com/chrome/index.html">Google Chrome</a>, and +<a href="https://www.microsoft.com/en-us/windows/microsoft-edge">Microsoft Edge</a>.</p></textarea> + + <h2>CSS Input</h2> + <textarea id="code" class="css-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;">a { + +} + +a:link { + +} + +a:visited { + +} + +a:focus { + +} + +a:hover { + +} + +a:active { + +}</textarea> + + <h2>Output</h2> + <div class="output" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"></div> + <div class="controls"> + <input id="reset" type="button" value="Reset" style="margin: 10px 10px 0 0;"> + <input id="solution" type="button" value="Show solution" style="margin: 10px 0 0 10px;"> + </div> +</div> +</pre> + +<pre class="brush: js">var htmlInput = document.querySelector(".html-input"); +var cssInput = document.querySelector(".css-input"); +var reset = document.getElementById("reset"); +var htmlCode = htmlInput.value; +var cssCode = cssInput.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +var styleElem = document.createElement('style'); +var headElem = document.querySelector('head'); +headElem.appendChild(styleElem); + +function drawOutput() { + output.innerHTML = htmlInput.value; + styleElem.textContent = cssInput.value; +} + +reset.addEventListener("click", function() { + htmlInput.value = htmlCode; + cssInput.value = cssCode; + drawOutput(); +}); + +solution.addEventListener("click", function() { + htmlInput.value = htmlCode; + cssInput.value = 'p {\n font-size: 1.2rem;\n font-family: sans-serif;\n line-height: 1.4;\n}\n\na {\n outline: none;\n text-decoration: none;\n padding: 2px 1px 0;\n}\n\na:link {\n color: #265301;\n}\n\na:visited {\n color: #437A16;\n}\n\na:focus {\n border-bottom: 1px solid;\n background: #BAE498;\n}\n\na:hover {\n border-bottom: 1px solid;\n background: #CDFEAA;\n}\n\na:active {\n background: #265301;\n color: #CDFEAA;\n}'; + drawOutput(); +}); + +htmlInput.addEventListener("input", drawOutput); +cssInput.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 800) }}</p> + +<h2 id="Добавление_иконок_в_ссылки">Добавление иконок в ссылки</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Обычной практикой является добавление иконок в ссылки, чтобы предоставить больше индикатора того, на какой контент указывает ссылка. Давайте рассмотрим очень простой пример, который добавляет иконку к внешним ссылкам (ссылки, которые ведут на другие сайты). Такая ссылка обычно выглядит как маленькая стрела торчащая из коробочки </span></span>— например, мы будем использовать <a href="https://icons8.com/web-app/741/external-link">этот отличный образец с сайта icons8.com</a>.</p> + +<p>Давайте взглянем на HTML и CSS которые дадут нам эффект, который мы хотим. Во-первых, немного простого HTML который будет стилизован:</p> + +<pre class="brush: html"><p>For more information on the weather, visit our <a href="weather.html">weather page</a>, +look at <a href="https://en.wikipedia.org/wiki/Weather">weather on Wikipedia</a>, or check +out <a href="http://www.extremescience.com/weather.htm">weather on Extreme Science</a>.</p></pre> + +<p>Далее, CSS:</p> + +<pre class="brush: css">body { + width: 300px; + margin: 0 auto; + font-family: sans-serif; +} + +p { + line-height: 1.4; +} + +a { + outline: none; + text-decoration: none; + padding: 2px 1px 0; +} + +a:link { + color: blue; +} + +a:visited { + color: purple; +} + +a:focus, a:hover { + border-bottom: 1px solid; +} + +a:active { + color: red; +} + +a[href*="http"] { + background: url('https://mdn.mozillademos.org/files/12982/external-link-52.png') no-repeat 100% 0; + background-size: 16px 16px; + padding-right: 19px; +}</pre> + +<p>{{ EmbedLiveSample('Добавление_иконок_в_ссылки', '100%', 150) }}</p> + +<p>Итак, что же тут происходит? Мы пропустим большую часть CSS так как это та же информация, которую вы рассматривали ранее. Однако, последнее правило интересное — тут мы вставляем пользовательское фоновое изображение во внешнюю ссылку схожим способом как мы делали <a href="/en-US/Learn/CSS/Styling_text/Styling_lists#Using_a_custom_bullet_image">пользовательские маркеры для пунктов списка</a> в последней статье — в этот раз, однако, мы используем короткую запись {{cssxref("background")}} вместо индивидуальных свойств. Мы задаем путь к изображению, которое хотим вставить, устанавливаем <code>no-repeat</code> чтобы мы получили только одну копию вставленного и затем устанавливаем позицию на 100% до правого края изображения и 0 пикселей от верхнего края.</p> + +<p>Также мы используем {{cssxref("background-size")}} для того чтобы указать размер в котором бы хотим чтобы было показано фоновое изображение — полезно иметь иконку большего размера и далее менять его размер так, как нужно для адаптивного (отзывчивого) веб-дизайна. Однако это работает только в IE9 и следующих версиях так что, если вам нужна поддержка тех старых браузеров вам просто придется менять размер изображения и вставлять его как есть.</p> + +<p>Наконец, мы задаем некоторый {{cssxref("padding-right")}} для ссылки чтобы добавить пространство в котором появляется фоновое изображение, таким образом, чтобы мы не накладывали его на текст.</p> + +<p>И последнее слово — как мы выбрали только внешние ссылки? Ну, если вы пишете свои <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">HTML ссылки</a> правильно, то вы должны были использовать только абсолютные URL для внешних ссылок — гораздо эффективнее использовать относительные ссылки для связи с другими частями вашего сайта. Текст "http" таким образом должен появляться только во внешних ссылках и можем выбрать его при помощи <a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Attribute_selectors">селектора атрибутов</a>: <code>a[href*="http"]</code> выбирает элементы {{htmlelement("a")}}, но только если они имеют атрибут {{htmlattrxref("href","a")}} со значением содержащим "http" где-то внутри него.</p> + +<p>Ну вот и все — попробуте посетить секцию активного изучения выше и испытайте этот новый метод!</p> + +<div class="note"> +<p><strong>Обратите вниманиеe</strong>: Не переживайте если вы еще не знакомы с <a href="/en-US/docs/Learn/CSS/Styling_boxes">фоном </a>и <a href="/en-US/docs/Web/Apps/Progressive/Responsive/responsive_design_building_blocks">адаптивным (отзывчивым) веб-дизайном</a>; это объяснено в других местах</p> +</div> + +<h2 id="Стилизация_ссылок_в_виде_кнопок">Стилизация ссылок в виде кнопок</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Инструменты, которые вы исследовали в этой статье</span></span> также могут быть использованы другим способом. Например, такие состояния как hover могут быть использованы для стилизации множества различных элементов, не только ссылок — вы можете захотеть стилизовать состояние hover параграфов, элементов списка или других вещей.</p> + +<p>Дополнительно, ссылки очень часто стилизуют так, чтоб они выглядели и вели себя как кнопки при определенных обстоятельствах — навигационное меню веб-сайтов обычно размечено как список, содержащий ссылки, который легко может быть стилизован так чтоб выглядел как набор кнопок управления или вкладок которые обеспечивают пользователя доступом к другим частям сайта. Давайте изучим как.</p> + +<p>Для начала HTML:</p> + +<pre class="brush: html"><ul> + <li><a href="#">Home</a></li><li><a href="#">Pizza</a></li><li><a href="#">Music</a></li><li><a href="#">Wombats</a></li><li><a href="#">Finland</a></li> +</ul></pre> + +<p>А теперь наш CSS:</p> + +<pre class="brush: css">body,html { + margin: 0; + font-family: sans-serif; +} + +ul { + padding: 0; + width: 100%; +} + +li { + display: inline; +} + +a { + outline: none; + text-decoration: none; + display: inline-block; + width: 19.5%; + margin-right: 0.625%; + text-align: center; + line-height: 3; + color: black; +} + +li:last-child a { + margin-right: 0; +} + +a:link, a:visited, a:focus { + background: yellow; +} + +a:hover { + background: orange; +} + +a:active { + background: red; + color: white; +}</pre> + +<p>Что дает нам следующий результат:</p> + +<p>{{ EmbedLiveSample('Стилизация_ссылок_в_виде_кнопок', '100%', 100) }}</p> + +<p>Давайте объясним, что тут происходит, фокусируясь на самых интересных частях:</p> + +<ul> + <li>Наше второе правило удаляет заданный по умолчанию {{cssxref("padding")}} у элемента {{htmlelement("ul")}} и устанавливает его ширину так, чтобы охватить 100% внешнего контейнера (в этом случае {{htmlelement("body")}}).</li> + <li>Элементы {{htmlelement("li")}} по умолчанию в норме являются блочными (см. <a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Types_of_CSS_boxes">типы блоков CSS</a> чтобы вспомнить), что значит что они будут располагаться на своих собственных строках. В этом случае мы создаем горизонтальный список ссылок, поэтому в третьем правиле задаем свойству {{cssxref("display")}} значение inline, <span class="tlid-translation translation" lang="ru"><span title="">что приводит к тому, что элементы списка располагаются в одной строке друг с другом </span></span>— теперь они ведут себя как строчные элементы.</li> + <li>четвертое правило — которое стилизует элемент {{htmlelement("a")}} — самое сложное; давайте пройдемся по нему шаг за шагом: + <ul> + <li>как в предыдущем примере, мы начинаем отключать настройки по умолчанию для {{cssxref("text-decoration")}} и {{cssxref("outline")}} — мы не хотим, чтоб они портили нам вид.</li> + <li>Далее мы устанавливаем {{cssxref("display")}} на <code>inline-block</code> — элементы {{htmlelement("a")}} являются строчными по умолчанию и, поскольку мы не хотим чтобы они вываливались на свои собственные строки как если бы это получалось со значением <code>block</code>, мы хотим иметь возможность менять их размер. <code>inline-block</code> позволяет нам делать это.</li> + <li>Теперь только изменение размера! Мы хотим заполнить всю ширину элемента {{htmlelement("ul")}}, оставить немного margin между каждой кнопкой (не без зазора с правого края) и мы имеем 5 кнопок, которые надо разместить и которые должны иметь одинаковый размер. Для того чтобы это сделать мы задаем {{cssxref("width")}} на 19.5%, а {{cssxref("margin-right")}} на 0.625%. Вы заметите что вся эта эта ширина составляет 100.625%, что может сделать так что последняя кнопка перекроет <code><ul></code> и выпадет вниз на следующую строку. <span class="tlid-translation translation" lang="ru"><span title="">Тем не менее, мы возвращаемся к 100%, используя следующее правило</span></span>, которое выбирает только последний <code><a></code> в списке и удаляет его margin. Сделано!</li> + <li>Последние три объявления довольно просты и в основном просто для косметических целей. Мы центрируем текст внутри каждой ссылки, задаем {{cssxref("line-height")}} на 3 чтобы кнопки имели некую высоту (что также имеет приемущество в центрировании текста по вертикали) и задаем для текста черный цвет.</li> + </ul> + </li> +</ul> + +<div class="note"> +<p><strong>Обратите внимание</strong>: Вы могли заметить что элементы списка в HTML все находятся на одной строке друг с другом — так сделано потому, что <span class="tlid-translation translation" lang="ru"><span title="">это сделано потому, что пробелы/разрывы строк между элементами встроенного блока создают пробелы на странице, точно также как пробелы между словами и такие пробелы могли бы нарушить расположение нашего горизонтального меню навигации. Вы можете найти больше информации об этой проблеме (и решения) на </span></span><a href="https://css-tricks.com/fighting-the-space-between-inline-block-elements/">Fighting the space between inline block elements</a>.</p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>Мы надеемся эта статья снабдила вас всем что вам надо знать о ссылках — на данный момент! Последняя статья в нашем модуле стилизации текста детализирует как использовать пользовательские шрифты на вашем веб-сайте или как они больше известны веб-шрифты.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Styling_text/Styling_lists", "Learn/CSS/Styling_text/Web_fonts", "Learn/CSS/Styling_text")}}</p> diff --git a/files/ru/learn/css/styling_text/веб_шрифты/index.html b/files/ru/learn/css/styling_text/веб_шрифты/index.html new file mode 100644 index 0000000000..f6ca27747f --- /dev/null +++ b/files/ru/learn/css/styling_text/веб_шрифты/index.html @@ -0,0 +1,203 @@ +--- +title: Веб-шрифты +slug: Learn/CSS/Styling_text/Веб_шрифты +translation_of: Learn/CSS/Styling_text/Web_fonts +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/Styling_text/Styling_links", "Learn/CSS/Styling_text/Typesetting_a_homepage", "Learn/CSS/Styling_text")}}</div> + +<p class="summary">В первой статье модуля, мы изучали основные функции CSS доступные для стилизации шрифтов и текста. В этой статье мы продвинемся дальше изучая веб-шрифты в деталях — они позволяют вам загружать пользовательские шрифты вместе с вашей веб-страницей, <span class="tlid-translation translation" lang="ru"><span title="">чтобы обеспечить более разнообразный, индивидуальный стиль текста.</span></span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные требования:</th> + <td>Основная компьютерная грамотность, основы HTML (изучите <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), основы CSS (изучите <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a>), <a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Основы CSS текста и шрифта</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td> + <p>Изучить как применять веб-шрифты к веб-странице, использовать сторонний сервис или писать код самостоятельно.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Краткое_повторение_семейств_шрифтов">Краткое повторение семейств шрифтов</h2> + +<p>Как мы рассматривали в <a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Фундаментальной стилизации текста и шрифта</a>, шрифты примененные к вашему HTML могут контролироваться при помощи свойства {{cssxref("font-family")}}. Оно принимает одно и более имен семейств шрифтов и браузер следует по списку пока не найдет тот шрифт, который является доступным в системе, под управлением которой он работает:</p> + +<pre class="brush: css notranslate">p { + font-family: Helvetica, "Trebuchet MS", Verdana, sans-serif; +}</pre> + +<p>Эта система работает хорошо, но традиционно выбор шрифтов веб-разработчиков была ограниченной. Существует только горсть шрифтов которые вы можете гарантировать, что они являются доступными во всех распространенных системах — так называемые <a href="/en-US/Learn/CSS/Styling_text/Fundamentals#Web_safe_fonts">Безопасные веб-шрифты</a>. <span class="tlid-translation translation" lang="ru"><span title="">Вы можете использовать стек шрифта для указания предпочтительных шрифтов</span></span>, за которыми следует веб-безопасные альтернативы, за которыми следует системный шрифт по умолчанию, <span class="tlid-translation translation" lang="ru"><span title="">но это добавляет дополнительной работы с точки зрения тестирования, чтобы убедиться, что ваш дизайн выглядит хорошо с каждым из шрифтов и т. д.</span></span></p> + +<h2 id="Веб-шрифты">Веб-шрифты</h2> + +<p>Но есть альтернатива, которая работает очень хорошо начиная с 6-ой версии IE. Веб-шрифты — это функция CSS позволяющая вам указывать файлы шрифтов, загружаемые вместе с вашим веб-сайтом по мере доступа к нему, <span class="tlid-translation translation" lang="ru"><span title="">это означает, что любой браузер, поддерживающий веб-шрифты, может иметь в своем распоряжении именно те шрифты, которые вы укажете.</span></span> Замечательно! Требуемый синтаксис выглядит примерно так:</p> + +<p>Во-первых, у вас есть блок {{cssxref("@font-face")}} в начале CSS, который указывает файл(-ы) шрифтов для загрузки:</p> + +<pre class="brush: css notranslate">@font-face { + font-family: "myFont"; + src: url("myFont.woff"); +}</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Ниже вы можете использовать имя семейства шрифтов, указанное внутри @font-face, чтобы применить свой собственный шрифт ко всему, что вам нравится, как обычно:</span></span></p> + +<pre class="brush: css notranslate">html { + font-family: "myFont", "Bitstream Vera Serif", serif; +}</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Синтаксис становится немного сложнее, чем этот;</span> <span title="">мы вдадимся в подробности ниже.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Есть две важные вещи, которые нужно иметь в виду о веб-шрифтах:</span></span></p> + +<ol> + <li>Браузеры поддерживают разные форматы шрифтов, поэтому вам будут нужны несколько форматов шрифтов для приличной кросс-браузерной поддержки. Например, большинство современных браузеров поддерживают WOFF/WOFF2 (Web Open Font Format versions 1 and 2), наиболее эффективный формат, но старые версии IE поддерживают только шрифты EOT (Embedded Open Type) и вам возможно понадобиться включать версию SVG шрифта для поддержки старых версий браузеров iPhone и Android. Ниже мы покажем вам как генерировать требуемый код.</li> + <li>В основном шрифты не бесплатны для использования. Вы должны платить за них и/или соблюдать другие условия лицензии такие <span class="tlid-translation translation" lang="ru"><span title="">как указание создателя шрифта в коде (или на вашем сайте). Вы не должны красть шрифты и использовать их без должного указания авторства.</span></span></li> +</ol> + +<div class="note"> +<p><strong>Обратите внимание</strong>: Веб-шрифты как технология поддерживается в Internet Explorer начиная с 4 версии!</p> +</div> + +<h2 id="Активное_изучение_пример_веб-шрифта">Активное изучение: пример веб-шрифта</h2> + +<p>Имея это в виду, давайте создадим базовый пример веб-шрифта из первых принципов. <span class="tlid-translation translation" lang="ru"><span title="">Сложно продемонстрировать это на встроенном живом примере</span></span>, поэтому вместо, мы бы хотели, чтобы следовали детальным шагам в секциях ниже, чтобы понять идею процесса</p> + +<p>Вы должны использовать файлы <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/web-fonts/web-font-start.html">web-font-start.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/web-fonts/web-font-start.css">web-font-start.css</a> как отправную точку добавляя в них ваш код (см. <a href="http://mdn.github.io/learning-area/css/styling-text/web-fonts/web-font-start.html">живой пример</a>). Сейчас сделайте копию этих файлов в новой директории на вашем компьютере. В файле <code>web-font-start.css</code> вы найдете некоторый минимальный CSS для работы с базовым макетом и версткой примера.</p> + +<h3 id="Поиск_шрифтов">Поиск шрифтов</h3> + +<p>В этом примере мы будем использовать два веб-шрифта, один для заголовков, и другой для основного текста. Для того чтобы начать нам необходимо найти файлы шрифтов, которые содержат эти шрифты. Шрифты созданы шрифтовыми "цехами" и хранятся в разных форматах фалов. Как правило существует три типа сайтов, где вы можете получить шрифты:</p> + +<ul> + <li>Бесплатный дистрибьютер шрифтов: <span class="tlid-translation translation" lang="ru"><span title="">это сайт, который предоставляет бесплатные шрифты для скачивания</span></span> (<span class="tlid-translation translation" lang="ru"><span title="">могут существовать некоторые условия лицензии, например, указание создателя шрифта)</span></span>. Примеры включают <a href="https://www.fontsquirrel.com/">Font Squirrel</a>, <a href="http://www.dafont.com/">dafont</a>, и <a href="https://everythingfonts.com/">Everything Fonts</a>.</li> + <li>Платный дистрибьютер шрифтов: это сайт, который предоставляет шрифты за плату, например <a href="http://www.fonts.com/">fonts.com</a> или <a href="http://www.myfonts.com/">myfonts.com</a>. Также вы можете купить шрифты напрямую у производителя шрифтов, например <a href="https://www.linotype.com/">Linotype</a>, <a href="http://www.monotype.com">Monotype</a>, или <a href="http://www.exljbris.com/">Exljbris</a>.</li> + <li>Сервис онлайн шрифтов: это сайт, который предоставляет вам шрифты, делая весь процесс проще. Смотрите раздел {{anch("Использование онлайн-сервиса шрифтов")}} для более подробной информации.</li> +</ul> + +<p>Давайте найдем какие-нибудь шрифты! Отправляйтесь на <a href="https://www.fontsquirrel.com/">Font Squirrel</a> и выберите два шрифта — симпатичный интересный шрифт для заголовков (может быть симпатично выглядящий или шрифт с засечками) и немного менее кричащий и более читабельный шрифт для параграфов. Когда вы найдете каждый шрифт, нажмите на кнопку загрузки и сохраните файлы в той же директории, где ранее вы сохранили файлы HTML и CSS. Не имеет значения являются ли они TTF (True Type Fonts) или OTF (Open Type Fonts).</p> + +<p>В любом случае распакуйте архив со шрифтом (веб-шрифты обычно распространяются в ZIP файлах, содержащих файл(-ы) шрифта и лицензионную информацию). Вы можете обнаружить несколько файлов шрифтов в упаковке (архиве) — некоторые шрифты распространяются как семейство с различными доступными вариантами, например тонкий, средний, жирный, курсив, тонкий курсив и т.д. <span class="tlid-translation translation" lang="ru"><span title="">В этом примере мы просто хотим, чтобы вы позаботились о едином файле шрифта для каждого варианта.</span></span></p> + +<div class="note"> +<p><strong>Обратите внимание</strong>: В разделе "Find fonts" в колонке справа, вы можете кликать по различным тегам и классификациям чтобы отфильтровать отображаемые варианты для выбора.</p> +</div> + +<h3 id="Генерация_требуемого_кода">Генерация требуемого кода</h3> + +<p>Теперь вам надо будет сгенерировать требуемый код (и форматы шрифтов). Для каждого шрифта проделайте следующие шаги.</p> + +<ol> + <li><span class="tlid-translation translation" lang="ru"><span title="">Убедитесь, что вы выполнили все лицензионные требования если вы собираетесь использовать это в коммерческих и/или веб проектах.</span></span></li> + <li>Перейдите на Fontsquirrel <a href="https://www.fontsquirrel.com/tools/webfont-generator">Webfont Generator</a>.</li> + <li>Выгрузите два ваших файла шрифтов используя кнопку <em>Upload Fonts.</em></li> + <li>Поставьте галочку отмеченную "Yes, the fonts I'm uploading are legally eligible for web embedding".</li> + <li>Кликните по <em>Download your kit</em>.</li> +</ol> + +<p>После того как генератор закончит обработку, вы должны получить ZIP файл к загрузке — сохраните его в той же директории что и ваши HTML и CSS.</p> + +<h3 id="Реализация_кода_в_вашем_демо">Реализация кода в вашем демо</h3> + +<p>Теперь распакуйте набор веб-шрифта, который вы только что сгенерировали. Внутри распакованной папки вы увидите три полезных элемента:</p> + +<ul> + <li>несколько версий каждого шрифта (например <code>.ttf</code>, <code>.woff</code>, <code>.woff2</code> и т.д.; <span class="tlid-translation translation" lang="ru"><span title="">предоставленные шрифты будут обновляться со временем по мере изменения требований поддержки браузера</span></span>). Как упомянуто выше, несколько шрифтов нужны для кросс-браузерной поддержки — это метод Fontsquirrel быть уверенными что вы получили все что вам надо.</li> + <li>Демо файл HTML для каждого шрифта — загрузите их в ваш браузер чтобы посмотреть, как будет выглядеть шрифт в разных контекстах использования.</li> + <li>Файл <code>stylesheet.css</code>, который содержит сгенерированный @font-face код который вам нужен.</li> +</ul> + +<p>Для внедрения их в ваше демо следуйте следующим шагам:</p> + +<ol> + <li>Переименуйте распакованную папку на что-нибудь легкое и простое, например <code>fonts</code>.</li> + <li>Откройте файл <code>stylesheet.css</code> и скопируйте содержимое обоих <code>@font-face</code> блоков в ваш файл <code>web-font-start.css</code> — вам надо вставить их в самый верх, до любого вашего CSS, так как шрифты должны быть импортированы до того, как вы сможете использовать их на вашем сайте.</li> + <li>Каждый из функций <code>url()</code> указывает на файл шрифта который мы хотим импортировать в наш CSS — мы должны убедиться в том, что пути к файлам верные, поэтому добавьте <code>fonts/</code> в начало каждого пути (настройте так как необходимо).</li> + <li>Теперь вы можете использовать эти шрифты в ваших стеках шрифтов, как и любой веб-безопасный или по умолчанию системный шрифт. Например:</li> +</ol> + +<pre class="brush: css notranslate">font-family: 'zantrokeregular', serif;</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы должны получить демо-страницу с какими-то реализованными симпатичными шрифтами. Поскольку различные шрифты создаются в разных размерах, вам может понадобиться настроить размер, интервалы и т.д., чтобы отладить внешний вид.</span></span></p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/12984/web-font-example.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<div class="note"> +<p><strong>Обратите внимание</strong>: Если у вас возникли какие-либо проблемы с тем что что-то не работает, смело сравнивайте файлы вашей версии с нашей законченной — см. <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/web-fonts/web-font-finished.html">web-font-finished.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/web-fonts/web-font-finished.css">web-font-finished.css</a> (<a href="http://mdn.github.io/learning-area/css/styling-text/web-fonts/web-font-finished.html">run the finished example live</a>).</p> +</div> + +<h2 id="Использование_онлайн-сервиса_шрифтов">Использование онлайн-сервиса шрифтов</h2> + +<p>Онлайн-сервисы шрифтов обычно хранят и обслуживают шрифты для вас, поэтому вам не надо переживать о написании <code>@font-face</code> кода и обычно необходимо просто вставить строчку или две простого кода в ваш сайт для того чтобы все работало. Примеры включают <a href="https://fonts.adobe.com/">Adobe Fonts</a> и <a href="http://www.typography.com/cloud/welcome/">Cloud.typography</a>. Большинство из этих услуг на основе подписки, за исключением <a href="https://www.google.com/fonts">Google Fonts</a>, полезный бесплатный сервис, особенно для быстрого тестирования работы и написания демо.</p> + +<p>Большинство из этих сервисов легки в использовании, поэтому мы не будем освещать их в деталях. Давайте кратко рассмотрим Google fonts, чтобы вы понимали идею. И снова, используйте копии <code>web-font-start.html</code> и <code>web-font-start.css</code> в качестве отправной точки.</p> + +<ol> + <li>Отправляйтесь на <a href="https://www.google.com/fonts">Google Fonts</a>.</li> + <li>Используйте фильтры с правой стороны чтобы отобразить типы шрифтов, которые вы хотите выбрать и выберите пару шрифтов, которые вам понравятся.</li> + <li>Для выбора семейства шрифтов нажмите на кнопку ⊕ рядом с ним.</li> + <li>Когда вы выбрали семейства шрифтов, нажмите на панель <em>[Number] Families Selected</em> в низу страницы.</li> + <li>На полученном экране, сначала вам надо скопировать строку показанного HTML кода и вставить ее в head вашего HTML файла. Вставьте его выше существующего {{htmlelement("link")}} элемента для того, чтоб шрифт импортировался до того, как вы начнете пользоваться им в вашем CSS.</li> + <li>Далее вам надо скопировать CSS-объявления<span class="tlid-translation translation" lang="ru"><span title="">, перечисленные в вашем CSS, чтобы применить пользовательские шрифты к вашему HTML.</span></span></li> +</ol> + +<div class="note"> +<p><strong>Обратите внимание</strong>: Вы можете найти законченные версии <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/web-fonts/google-font.html">google-font.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/web-fonts/google-font.css">google-font.css</a>, если вам необходимо сверить вашу работу с нашей (<a href="http://mdn.github.io/learning-area/css/styling-text/web-fonts/google-font.html">см. live</a>).</p> +</div> + +<h2 id="font-face_более_детально">@font-face более детально</h2> + +<p>Давайте исследуем тот <code>@font-face</code> синтаксис, который fontsquirrel сгенерировал для вас. Это то, как выглядит один из этих блоков:</p> + +<pre class="brush: css notranslate">@font-face { + font-family: 'ciclefina'; + src: url('fonts/cicle_fina-webfont.eot'); + src: url('fonts/cicle_fina-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/cicle_fina-webfont.woff2') format('woff2'), + url('fonts/cicle_fina-webfont.woff') format('woff'), + url('fonts/cicle_fina-webfont.ttf') format('truetype'), + url('fonts/cicle_fina-webfont.svg#ciclefina') format('svg'); + font-weight: normal; + font-style: normal; +}</pre> + +<p>Это называется "пуленепробиваемым @font-face синтаксисом", после публикации Пола Айриша (Paul Irish), с самого начала, когда <code>@font-face</code> начал получать популярность (<a href="https://www.paulirish.com/2009/bulletproof-font-face-implementation-syntax/">Bulletproof @font-face Syntax</a>). Давайте пройдемся по нему, чтобы посмотреть, что он делает:</p> + +<ul> + <li><code>font-family</code>: В этой строке указывается имя, которое вы хотите использовать для обозначения шрифта. Вы можете указать его как угодно, если вы используете его последовательно в вашем CSS.</li> + <li><code>src</code>: В этой строке указывается путь к файлам шрифтов которые будут импортированы в ваш CSS (<code>url</code> путь) и формат каждого файла шрифта (<code>format</code> часть). Последняя часть в каждом случае опциональна, но полезно объявлять его, потому что это позволяет браузерам быстрее находить шрифт, который они могут использовать. Могут быть перечислены несколько объявлений, разделенных запятыми — браузер будет искать среди них и использовать первый который найдет и тот который он понимает — поэтому лучше всего ставить новые, лучшие форматы такие как WOFF2 в начало, а старые, не такие хорошие форматы как TTF в конец. Единственное исключение это EOT шрифты — они размещены первыми чтобы исправить пару багов в старых версиях IE который постарается использовать первую вещь, которую найдет, даже если он не умеет использовать этот шрифт.</li> + <li>{{cssxref("font-weight")}}/{{cssxref("font-style")}}: В этих строках указывается какую толщину имеет шрифт и является ли он курсивом или нет. Если вы импортируете несколько значений толщины одного и того же шрифта вы можете указать какая у них толщина/стиль и затем использовать разные значения {{cssxref("font-weight")}}/{{cssxref("font-style")}} для выбора между ними, <span class="tlid-translation translation" lang="ru"><span title="">вместо того, чтобы называть всех разных членов семейства шрифтов разными именами. </span></span><a href="http://www.456bereastreet.com/archive/201012/font-face_tip_define_font-weight_and_font-style_to_keep_your_css_simple/">@font-face совет: установите font-weight и font-style так чтобы ваш CSS был простым</a> от Роджера Джонсона (Roger Johansson) покажет, что делать более детально.</li> +</ul> + +<div class="note"> +<p><strong>Обратите внимание</strong>: Вы также можете указать определенные значения {{cssxref("font-variant")}} и {{cssxref("font-stretch")}} для ваших веб-шрифтов. В новых браузерах вы также можете указать значение {{cssxref("unicode-range")}}, <span class="tlid-translation translation" lang="ru"><span title="">который является конкретным диапазоном символов</span></span>, которые вы хотите использовать из веб-шрифта — в поддерживающих браузерах, будут загружены только указанные символы, сохраняя от ненужной загрузки. <a href="https://24ways.org/2011/creating-custom-font-stacks-with-unicode-range/">Creating Custom Font Stacks with Unicode-Range</a> от Drew McLellan предоставляет некоторые полезные идеи того как это использовать</p> +</div> + +<h2 id="Переменные_шрифты">Переменные шрифты</h2> + +<p>В браузерах доступна новая технология, называемая переменными шрифтами — это шрифты, которые позволяют включить в единственный файл много разных вариантов дизайнов шрифтов, вместо того чтобы иметь отдельные файлы шрифтов для каждой ширины, толщины или стиля. <span class="tlid-translation translation" lang="ru"><span title="">Они несколько продвинуты для нашего курса для начинающих</span></span>, <span class="tlid-translation translation" lang="ru"><span title="">но если вы хотите расширить свои знания и посмотреть на них, прочитайте наше </span></span><a href="/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide">Руководство по переменным шрифтам</a>.</p> + +<h2 id="Испытайте_свои_навыки!">Испытайте свои навыки!</h2> + +<p>Вы достигли конца этой статьи и уже испытали некоторые навыки в наших разделах активного изучения, но сможете ли вы вспомнить самую важную информацию продвигаясь дальше? Вы можете найти задание для проверки того что вы усвоили информацию к конце модуля — см. <a href="/en-US/docs/Learn/CSS/Styling_text/Typesetting_a_homepage">Задание: стилизация школьного сайта</a>.</p> + +<h2 id="Заключение">Заключение</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Теперь, когда вы ознакомились с нашими статьями об основах стилизации текста, пришло время проверить ваше понимание нашей оценкой модуля «Задание: стилизация школьного сайта».</span></span></p> + +<p>{{PreviousMenuNext("Learn/CSS/Styling_text/Styling_links", "Learn/CSS/Styling_text/Typesetting_a_homepage", "Learn/CSS/Styling_text")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Фундаментальная стилизация текста и шрифта</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">Стилизация списков</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_links">Стилизация ссылок</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">Веб-шрифты</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Typesetting_a_homepage">Задание: Стилизация школьного сайта</a></li> +</ul> diff --git a/files/ru/learn/css/styling_text/задание_colon__стилизирование_школьного_сайта/index.html b/files/ru/learn/css/styling_text/задание_colon__стилизирование_школьного_сайта/index.html new file mode 100644 index 0000000000..4f77ee31bc --- /dev/null +++ b/files/ru/learn/css/styling_text/задание_colon__стилизирование_школьного_сайта/index.html @@ -0,0 +1,126 @@ +--- +title: 'Задание: Стилизирование школьного сайта' +slug: 'Learn/CSS/Styling_text/Задание:_Стилизирование_школьного_сайта' +translation_of: Learn/CSS/Styling_text/Typesetting_a_homepage +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/CSS/Styling_text/Web_fonts", "Learn/CSS/Styling_text")}}</div> + +<p class="summary">В этой оценке мы проверим ваше понимание всех методов стилизации текста, которые мы рассмотрели в этом модуле дав вам задание стилизовать текст домашней страницы общественной школы. Вы можете просто развлечься, выполняя задание.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные требования:</th> + <td>Вы должны были изучить все статьи в этом модуле, прежде чем приступать к оценке.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Проверить понимание методов CSS по стилизации текста.</td> + </tr> + </tbody> +</table> + +<h2 id="Отправная_точка">Отправная точка</h2> + +<p>Чтобы начать эту оценку, вам необходимо:</p> + +<ul> + <li>Перейти и взять файлы <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/typesetting-a-homepage-start/index.html">HTML</a> и <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/typesetting-a-homepage-start/style.css">CSS</a> для упражнения, а также предоставленную <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/typesetting-a-homepage-start/external-link-52.png">иконку внешней ссылки</a>.</li> + <li>Сделайте их копии на вашем компьютере.</li> +</ul> + +<p>В качестве альтернативы, вы можете пользоваться сайтами как <a class="external external-icon" href="http://jsbin.com/">JSBin</a> или <a href="https://glitch.com/">Glitch</a> чтобы выполнить оценку. Вы можете вставить HTML и заполнить CSS в одном из этих онлайн-редакторов и использовать <a href="http://mdn.github.io/learning-area/css/styling-text/typesetting-a-homepage-start/external-link-52.png">этот URL</a> чтобы указать фоновое изображение. Если же онлайн-редактор, которым вы пользуетесь, не имеет отдельной CSS панели, тогда вводите его в элемент <code><style></code> в head документа.</p> + +<div class="blockIndicator note"> +<p><strong>Обратите внимание</strong>: Если вы застрянете, то попросите помощи — см. секцию {{anch("Оценка или дальнейшая помощь")}} в конце этой страницы.</p> +</div> + +<h2 id="Краткое_описание_проекта">Краткое описание проекта</h2> + +<p>Вам предоставлен некоторый "сырой" HTML для домашней страницы воображаемого общественного колледжа, плюс немного CSS который стилизует страницу в макет с тремя колонками и обеспечивает еще каким-то другим элементарным стилем. Вы должны писать ваш дополнительный CSS после комментария в низу CSS файла, чтобы убедиться, что вы с легкостью заметите части проделанные вами. Не переживайте если некоторые селекторы повторяются; мы отпустим вас с этим случаем.</p> + +<p>Шрифты:</p> + +<ul> + <li>Во-первых, загрузите парочку бесплатных для использования шрифтов. Так как это колледж, шрифты должны быть выбраны так чтоб они придавали достаточной серьезности, формальности и чувства заслуживающего доверия — может подойти шрифт с засечками (serif) для всего основного текста, в сочетании с шрифтами sans-serif или serif для заголовков.</li> + <li>Используйте подходящий сервис для генерации пуленепробиваемого <code>@font-face</code> кода для этих двух шрифтов.</li> + <li>Примените ваш основной шрифт для всей страницы и шрифт заголовка для заголовков.</li> +</ul> + +<p>Общая стилизация текста:</p> + +<ul> + <li>Дайте всей странице <code>font-size</code> <code>10px</code>.</li> + <li>Дайте вашему заголовку и другим типам элементов подходящие размеры шрифта задаваемые используя соответсвующие относительные единицы.</li> + <li>Дайте основному тексту подходящую <code>line-height</code>.</li> + <li>Отцентрируйте ваш заголовок верхнего уровня на странице.</li> + <li>Дайте вашим заголовкам немного <code>letter-spacing</code> чтобы они не были слишком сжатыми, позвольте буквам немного дышать.</li> + <li>Дайте основному тексту немного <code>letter-spacing</code> и <code>word-spacing</code>, при необходимости.</li> + <li>Дайте первым параграфам после каждого заголовка в <code><section></code> немного отступа, скажем 20px.</li> +</ul> + +<p>Ссылки:</p> + +<ul> + <li>Дайте состояниям link, visited, focus, и hover какой-нибудь цвет, который будет сочетается с цветом горизонтальных линий на верху и в низу страницы.</li> + <li>Сделайте так чтобы ссылки были подчеркнутыми по умолчанию, но, чтобы подчеркивание исчезало, когда вы фокусируетесь или наводите мышь на них.</li> + <li>Удалите установленный по умолчанию контурный фокус со ВСЕХ ссылок на странице.</li> + <li>Дайте состоянию active заметно отличимый стиль так чтоб он красиво выделялся, но чтоб он все еще вписывался в общий дизайн страницы.</li> + <li>Сделайте так чтоб внешние ссылки имели иконку внешней ссылки, вставленную рядом с ними.</li> +</ul> + +<p>Списки:</p> + +<ul> + <li>Убедитесь, что интервалы ваших списков и пунктов списка совпадают со стилизацией всей страницы. Все элементы списка должны иметь ту же <code>line-height</code> что и строки параграфов, и каждый список должен иметь те же интервалы сверху и снизу которые имеются между параграфами.</li> + <li>Дайте элементам списка симпатичные маркеры, соответствующие дизайну страницы. Выберете ли вы пользовательские изображения для маркеров или что-то другое — зависит от вас.</li> +</ul> + +<p>Меню навигации:</p> + +<ul> + <li>Стилизуйте ваше меню навигации так чтоб оно соответствовало внешнему виду страницы.</li> +</ul> + +<h2 id="Советы_и_подсказки">Советы и подсказки</h2> + +<ul> + <li>Вам не надо как-либо редактировать HTML в этом упражнении.</li> + <li>Вам не надо обязательно делать меню навигации в виде кнопок, но надо чтоб они были более-менее высокими, чтобы они не выглядели глупо на краю страницы; также помните, что вам надо сделать его вертикальным меню навигации.</li> +</ul> + +<h2 id="Пример">Пример</h2> + +<p>Следующий скриншот показывает пример того, как может выглядеть законченный дизайн.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/12994/example2.png" style="display: block; height: 1106px; margin: 0px auto; width: 1533px;"></p> + +<h2 id="Оценка_или_дальнейшая_помощь">Оценка или дальнейшая помощь</h2> + +<p>Если вы хотите, чтобы вашу работу оценили, или вы застряли и хотите попросить помощи:</p> + +<ol> + <li>Разместите свою работу в онлайн редакторе в которым можно поделиться работами в таком как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, или <a href="https://glitch.com/">Glitch</a>.</li> + <li>Напишите пост с просьбой оценки и/или помощи на <a href="https://discourse.mozilla.org/c/mdn/learn">MDN Discourse forum Learning category</a>. Ваш пост должен включать: + <ul> + <li>Описательный заголовок такой как "Требуется оценка верстки домашней страницы общественный школы".</li> + <li>Детали о том, что вы уже попытались сделать и что бы вы хотели, чтобы мы сделали, например, если вы застряли и вам нужна помощь, либо вы хотите оценку.</li> + <li>Ссылку на онлайн редактор (как упомянуто выше в пункте 1) с примером, который нуждается в оценке или с которым нужна помощь. Это хорошая практика чтобы вникнуть — очень сложно помочь кому-либо с проблемным кодом если вы не видите их код.</li> + <li>Ссылку на актуальную задачу или страницу оценки, чтобы мы могли найти вопрос, по которому вам нужна помощь.</li> + </ul> + </li> +</ol> + +<p>{{PreviousMenu("Learn/CSS/Styling_text/Web_fonts", "Learn/CSS/Styling_text")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Фундаментальная стилизация текста и шрифта</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">Стилизация списков</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_links">Стилизация ссылок</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">Веб-шрифты</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Typesetting_a_homepage">Задании: Стилизация школьного сайта</a></li> +</ul> diff --git a/files/ru/learn/css/styling_text/стилизация_списков/index.html b/files/ru/learn/css/styling_text/стилизация_списков/index.html new file mode 100644 index 0000000000..b749acb5cc --- /dev/null +++ b/files/ru/learn/css/styling_text/стилизация_списков/index.html @@ -0,0 +1,389 @@ +--- +title: Стилизация списков +slug: Learn/CSS/Styling_text/Стилизация_списков +translation_of: Learn/CSS/Styling_text/Styling_lists +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/Styling_text/Fundamentals", "Learn/CSS/Styling_text/Styling_links", "Learn/CSS/Styling_text")}}</div> + +<p class="summary"><a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Lists">Списки</a>, по-большому счету, ведут себя также как любой другой текст, но существуют некоторые специфичные натройки CSS, о которых вы должны знать. В этой статье они все описываются.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td> + <p>Базовая компьютерная грамотность, основы HTML (изучите <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>), основы CSS (изучите <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a>), <a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">CSS основы по тексту и шрифтам.</a></p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Познакомиться с лучшими практиками и свойствами по стилизации списков.</td> + </tr> + </tbody> +</table> + +<h2 id="Пример_простого_списка">Пример простого списка</h2> + +<p>Для начала, давайте взглянем на пример простого списка. В данной статье мы рассмотрим ненумерованный, нумерованный и описательный списки — все они имеют аналогичные свойства стилизации, но некоторые имеют свои специальные свойства. Не стилизованный пример <a href="http://mdn.github.io/learning-area/css/styling-text/styling-lists/unstyled-list.html">доступен на Github</a> (проверьте также <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/styling-lists/unstyled-list.html">источник кода</a>.)</p> + +<p>HTML для нашего примера списка представлен ниже:</p> + +<pre class="brush: html"><h2>Shopping (unordered) list</h2> + +<p>Paragraph for reference, paragraph for reference, paragraph for reference, +paragraph for reference, paragraph for reference, paragraph for reference.</p> + +<ul> + <li>Hummus</li> + <li>Pita</li> + <li>Green salad</li> + <li>Halloumi</li> +</ul> + +<h2>Recipe (ordered) list</h2> + +<p>Paragraph for reference, paragraph for reference, paragraph for reference, +paragraph for reference, paragraph for reference, paragraph for reference.</p> + +<ol> + <li>Toast pita, leave to cool, then slice down the edge.</li> + <li>Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li> + <li>Wash and chop the salad.</li> + <li>Fill pita with salad, hummus, and fried halloumi.</li> +</ol> + +<h2>Ingredient description list</h2> + +<p>Paragraph for reference, paragraph for reference, paragraph for reference, +paragraph for reference, paragraph for reference, paragraph for reference.</p> + +<dl> + <dt>Hummus</dt> + <dd>A thick dip/sauce generally made from chick peas blended with tahini, lemon juice, salt, garlic, and other ingredients.</dd> + <dt>Pita</dt> + <dd>A soft, slightly leavened flatbread.</dd> + <dt>Halloumi</dt> + <dd>A semi-hard, unripened, brined cheese with a higher-than-usual melting point, usually made from goat/sheep milk.</dd> + <dt>Green salad</dt> + <dd>That green healthy stuff that many of us just use to garnish kebabs.</dd> +</dl></pre> + +<p>Если вы перейдете к живому примеру прямо сейчас и изучите элемент списка используя <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">инструменты разработчика браузера</a>, то вы заметите несколько стилей установленных по умолчанию:</p> + +<ul> + <li>Элементы {{htmlelement("ul")}} и {{htmlelement("ol")}} имеют верхний и нижний {{cssxref("margin")}} по <code>16px</code> (<code>1em</code>) и {{cssxref("padding-left")}} <code>40px</code> (<code>2.5em</code>.)</li> + <li>Объекты списка (элементы {{htmlelement("li")}}) не имеют заданных значений по умолчанию для интервалов.</li> + <li>Элемент {{htmlelement("dl")}} имеет верхний и нижний {{cssxref("margin")}} по <code>16px</code> (<code>1em</code>), но padding не задан.</li> + <li>Элементы {{htmlelement("dd")}} имеют {{cssxref("margin-left")}} <code>40px</code> (<code>2.5em</code>.)</li> + <li>Элементы {{htmlelement("p")}} которые мы включили для ссылок (сноски) имеют верхний и нижний {{cssxref("margin")}} по <code>16px</code> (<code>1em</code>), точно так же, как и различные типы списков.</li> +</ul> + +<h2 id="Управление_интервалами_списков">Управление интервалами списков</h2> + +<p>При оформлении списков, вам необходимо настроить их стили так, чтоб они сохраняли то же вертикальное расстояние, что и окружающие их элементы (такие как параграфы и изображения; иногда называемые вертикальным ритмом) и то же расстояние по горизонтали как и между собой (посмотреть <a href="http://mdn.github.io/learning-area/css/styling-text/styling-lists/">законченный стилизированный пример</a> на Github, а также <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/styling-lists/index.html">найти исходный код</a>.)</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">CSS, используемый для оформления текста и интервалов, выглядит следующим образом:</span></span></p> + +<pre class="brush: css">/* General styles */ + +html { + font-family: Helvetica, Arial, sans-serif; + font-size: 10px; +} + +h2 { + font-size: 2rem; +} + +ul,ol,dl,p { + font-size: 1.5rem; +} + +li, p { + line-height: 1.5; +} + +/* Description list styles */ + + +dd, dt { + line-height: 1.5; +} + +dt { + font-weight: bold; +} + +dd { + margin-bottom: 1.5rem; +}</pre> + +<ul> + <li>Первое правило устанавливает шрифт сайта и основной размер шрифта 10px. Они наследуются всеми на этой странице.</li> + <li>Правила 2 и 3 задают относительные размеры шрифтов заголовков, различных типов списков (их наследуют дочерние элементы списков) и параграфов. Это значит, что каждый параграф и список будут иметь одинаковый размер шрифта, а также верхний и нижний интервалы, помогая сохранить согласованность вертикального ритма.</li> + <li>Правило 4 задает одинаковую высоту {{cssxref("line-height")}} в параграфах и пунктах списка — так, что параграфы и каждый отдельный пункт списка будут иметь те же интервалы между строками. Это также поможет сохранить согласованность вертикального ритма.</li> + <li>Правила 5 и 6 применяются к списку описаний — мы задаем одинаковую высоту <code>line-height</code> между терминами и описаниями списке описаний как мы это делали с параграфами и пунктами списка. И снова, согласованность хорошая! <span class="tlid-translation translation" lang="ru"><span title="">Мы также делаем описание терминов жирным шрифтом, чтобы они визуально выделялись легче.</span></span> <span id="cke_bm_126E" style="display: none;"> </span></li> +</ul> + +<h2 id="Стили_специфичные_для_списков">Стили специфичные для списков</h2> + +<p>Теперь, рассмотрев общие методы интервалов для списков, давайте изучим некоторые специфичные спискам свойства. Существует три свойства, с которых вам надо начать знакомство, которые могут быть установлены для элементов {{htmlelement("ul")}} или {{htmlelement("ol")}}:</p> + +<ul> + <li>{{cssxref("list-style-type")}}: задает тип маркеров для использования в списке, например, квадратные или круглые маркеры для неупорядоченного списка, или цифры, буквы или римские цифры для упорядоченного списка.</li> + <li>{{cssxref("list-style-position")}}: управляет будет ли маркер появляется внутри пунктов списка или <span class="tlid-translation translation" lang="ru"><span title="">вне их перед началом каждого элемента.</span></span></li> + <li>{{cssxref("list-style-image")}}: позволяет вам использовать пользовательские изображения в качестве маркеров, а не просто квадрат или круг.</li> +</ul> + +<h3 id="Стили_маркеров">Стили маркеров</h3> + +<p>Как указано выше, свойство {{cssxref("list-style-type")}} позволяет вам устанавливать какой тип маркера использовать в качестве точек маркера. В нашем примере мы установили использование заглавных римских цифр в упорядоченном списке:</p> + +<pre class="brush: css">ol { + list-style-type: upper-roman; +}</pre> + +<p>Это дает нам следующий вид:</p> + +<p><img alt="an ordered list with the bullet points set to appear outside the list item text." src="https://mdn.mozillademos.org/files/12962/outer-bullets.png" style="border-style: solid; border-width: 1px; display: block; height: 119px; margin: 0px auto; width: 376px;"></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете найти гораздо больше опций, заглянув на справочную страницу {{cssxref ("list-style-type")}}.</span></span></p> + +<h3 id="Позиция_маркера">Позиция маркера</h3> + +<p>Свойство {{cssxref("list-style-position")}} устанавливает будет ли появляться маркер внутри пунктов списка или снаружи перед началом каждого пункта. Значение по умолчанию — <code>outside</code>, которое заставляет маркеры находится снаружи пунктов списка, как видно выше.</p> + +<p>Если вы установите значение на <code>inside</code>, то маркеры будут находиться внутри строк:</p> + +<pre class="brush: css">ol { + list-style-type: upper-roman; + list-style-position: inside; +}</pre> + +<p><img alt="an ordered list with the bullet points set to appear inside the list item text." src="https://mdn.mozillademos.org/files/12958/inner-bullets.png" style="border-style: solid; border-width: 1px; display: block; height: 123px; margin: 0px auto; width: 370px;"></p> + +<h3 id="Использование_пользовательского_изображения_как_маркер">Использование пользовательского изображения как маркер</h3> + +<p>Свойство {{cssxref("list-style-image")}} позволяет вам использовать пользовательское изображение в качестве вашего маркера. Синтаксис довольно прост:</p> + +<pre class="brush: css">ul { + list-style-image: url(star.svg); +}</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Однако это свойство немного ограничено с точки зрения управления позициями</span></span>, размерами (и т.д.) маркеров. <span class="tlid-translation translation" lang="ru"><span title="">Вам лучше использовать семейство свойств {{cssxref ("background")}}, о которых вы узнаете намного больше в модуле </span></span><a href="/en-US/docs/Learn/CSS/Styling_boxes">Styling boxes</a><span class="tlid-translation translation" lang="ru"><span title="">.</span> <span title="">А пока вот вам образец для дегустации!</span></span></p> + +<p>В нашем законченном примере мы оформили неупорядоченный список следующим образом (<span class="tlid-translation translation" lang="ru"><span title="">поверх того, что вы уже видели выше</span></span>):</p> + +<pre class="brush: css">ul { + padding-left: 2rem; + list-style-type: none; +} + +ul li { + padding-left: 2rem; + background-image: url(star.svg); + background-position: 0 0; + background-size: 1.6rem 1.6rem; + background-repeat: no-repeat; +}</pre> + +<p>Мы сделали следующее:</p> + +<ul> + <li>Установили {{cssxref("padding-left")}} элемента {{htmlelement("ul")}} с <code>40px</code> по умолчанию на <code>20px</code>, затем установили то же самое количество в пунктах списка. Это для того, чтобы все пункты списка продолжали выравниваться с порядком пунктов списка и описаний списка описаний, но пункты списка имеют некоторый padding для фоновых изображений чтобы сидеть внутри. Если бы мы не сделали этого, то фоновые изображения накладывались бы с текстом пунктов списка, что выглядело бы неряшливо.</li> + <li>Установили {{cssxref("list-style-type")}} на <code>none</code>, для того чтобы маркеры не появлялись по умолчанию. Мы собираемся использовать свойства {{cssxref("background")}} для управления маркерами.</li> + <li>Вставили маркер в каждый пункт неупорядоченного списка. <span class="tlid-translation translation" lang="ru"><span title="">Соответствующие свойства, следующие:</span></span> + <ul> + <li>{{cssxref("background-image")}}: <span class="tlid-translation translation" lang="ru"><span title="">Указывает путь к файлу изображения, который вы хотите использовать в качестве маркера.</span></span></li> + <li>{{cssxref("background-position")}}: Определяет где в фоне выбранного элемента появится изображение — в данном случае мы говорим <code>0 0</code>, что значит что маркер будет появляться в самом верху слева каждого пункта списка.</li> + <li>{{cssxref("background-size")}}: Задает размер фонового изображения. В идеале мы хотим, чтоб маркеры были того же размера что и пункты списка (или самую малость меньше или крупнее). Мы используем размер <code>1.6rem</code> (<code>16px</code>), <span class="tlid-translation translation" lang="ru"><span title="">что очень хорошо сочетается с отступом (padding) </span></span><code>20px</code><span class="tlid-translation translation" lang="ru"><span title="">, </span></span><span class="tlid-translation translation" lang="ru"><span title="">который мы позволили разместить внутри маркера </span></span>— <span class="tlid-translation translation" lang="ru"><span title="">16px плюс 4px интервала между маркером и текстом пункта списка работают хорошо.</span></span></li> + <li>{{cssxref("background-repeat")}}: По умолчанию, фоновые изображения повторяются пока не заполнят доступное фоновое пространство. Мы хотим всего лишь одну копию вставленного изображения в каждом случае, поэтому мы установили значение <code>no-repeat</code>.</li> + </ul> + </li> +</ul> + +<p>Это дает нам следующий результат:</p> + +<p><img alt="an unordered list with the bullet points set as little star images" src="https://mdn.mozillademos.org/files/16226/list_formatting.png" style="border-style: solid; border-width: 1px; display: block; height: 106px; margin: 0px auto; width: 124px;"></p> + +<h3 id="короткая_запись_list-style">короткая запись list-style</h3> + +<p>Эти три свойства упомянутые выше могут все быть заданы, используя лишь одну короткую запись свойства, {{cssxref("list-style")}}. Например, следующий CSS:</p> + +<pre class="brush: css">ul { + list-style-type: square; + list-style-image: url(example.png); + list-style-position: inside; +}</pre> + +<p>Может быть заменен этим:</p> + +<pre class="brush: css">ul { + list-style: square url(example.png) inside; +}</pre> + +<p>Значения могут быть перечислены в любом порядке, и вы можете использовать одно, два и все три (значения по умолчанию, использованные для свойств, которые не включены — <code>disc</code>, <code>none</code>, и <code>outside</code>). Если указаны и <code>type</code> и <code>image</code>, <span class="tlid-translation translation" lang="ru"><span title="">тип используется в качестве запасного варианта, если изображение по какой-либо причине не может быть загружено.</span></span></p> + +<h2 id="Контроль_счета_списка">Контроль счета списка</h2> + +<p>Иногда вам может понадобиться вести счет в упорядоченном списке по-другому — например начинать с цифры отличной от 1, или считать в обратном порядке, или вести счет с шагом больше 1. HTML и CSS имеют несколько инструментов которые помогут с этим.</p> + +<h3 id="start">start</h3> + +<p>Атрибут {{htmlattrxref("start","ol")}} позволит вам начать счет списка с цифры отличной от 1. Например:</p> + +<pre class="brush: html"><ol start="4"> + <li>Toast pita, leave to cool, then slice down the edge.</li> + <li>Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li> + <li>Wash and chop the salad.</li> + <li>Fill pita with salad, hummus, and fried halloumi.</li> +</ol></pre> + +<p>что даст вам такой результат:</p> + +<p>{{ EmbedLiveSample('start', '100%', 150) }}</p> + +<h3 id="reversed">reversed</h3> + +<p>Атрибут {{htmlattrxref("reversed","ol")}} начнет отсчет по убыванию вместо возрастания. Например:</p> + +<pre class="brush: html"><ol start="4" reversed> + <li>Toast pita, leave to cool, then slice down the edge.</li> + <li>Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li> + <li>Wash and chop the salad.</li> + <li>Fill pita with salad, hummus, and fried halloumi.</li> +</ol></pre> + +<p>что даст вам такой результат:</p> + +<p>{{ EmbedLiveSample('reversed', '100%', 150) }}</p> + +<div class="note"> +<p><strong>Обратите внимание</strong>: Если пунктов в списке в обратном списке больше, чем значение атрибута <code>start</code>, счет продолжится до нуля и далее отрицательные значения.</p> +</div> + +<h3 id="value">value</h3> + +<p>Атрибут {{htmlattrxref("value","ol")}} позволит вам установить специфичные цифровые значения к пунктам списка. Например:</p> + +<pre class="brush: html"><ol> + <li value="2">Toast pita, leave to cool, then slice down the edge.</li> + <li value="4">Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li> + <li value="6">Wash and chop the salad.</li> + <li value="8">Fill pita with salad, hummus, and fried halloumi.</li> +</ol></pre> + +<p>что даст вам такой результат:</p> + +<p>{{ EmbedLiveSample('value', '100%', 150) }}</p> + +<div class="note"> +<p><strong>Обратите внимание</strong>: Даже если вы используете нечисловой {{cssxref("list-style-type")}}, вам все равно надо использовать эквивалентное цифровое значение в атрибуте <code>value</code>.</p> +</div> + +<h2 id="Активное_изучение_Стилизация_вложенного_списка">Активное изучение: <span class="tlid-translation translation" lang="ru"><span title="">Стилизация вложенного списка</span></span></h2> + +<p>В этой сессии активного изучения, мы хотим, чтобы вы взяли все что вы выучили выше и попробовали стилизовать вложенный список. Мы предоставили вам HTML и хотим, чтобы вы:</p> + +<ol> + <li>Задали неупорядоченному списку квадратные маркеры.</li> + <li>Задали пунктам неупорядоченного и упорядоченного списка 1,5 межстрочный интервал их размера шрифта.</li> + <li>Задали упорядоченному списку маркеры в виде строчных букв.</li> + <li>Не стесняйтесь играться с примерами списков столько сколько вам нравится, экспериментируя с типами маркеров, интервалами или со всем что вы найдете.</li> +</ol> + +<p>Если вы допустите ошибку, вы всегда можете сделать сброс используя кнопку <em>Reset</em>. Если вы застрянете, нажмите кнопку <em>Show solution </em>чтобы посмотреть возможный ответ.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html"><div class="body-wrapper" style="font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;"> + <h2>HTML Input</h2> + <textarea id="code" class="html-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"><ul> + <li>First, light the candle.</li> + <li>Next, open the box.</li> + <li>Finally, place the three magic items in the box, in this exact order, to complete the spell: + <ol> + <li>The book of spells</li> + <li>The shiny rod</li> + <li>The goblin statue</li> + </ol> + </li> +</ul></textarea> + + <h2>CSS Input</h2> + <textarea id="code" class="css-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"></textarea> + + <h2>Output</h2> + <div class="output" style="width: 90%;height: 12em;padding: 10px;border: 1px solid #0095dd;overflow: auto;"></div> + <div class="controls"> + <input id="reset" type="button" value="Reset" style="margin: 10px 10px 0 0;"> + <input id="solution" type="button" value="Show solution" style="margin: 10px 0 0 10px;"> + </div> +</div> +</pre> + +<pre class="brush: js">var htmlInput = document.querySelector(".html-input"); +var cssInput = document.querySelector(".css-input"); +var reset = document.getElementById("reset"); +var htmlCode = htmlInput.value; +var cssCode = cssInput.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +var styleElem = document.createElement('style'); +var headElem = document.querySelector('head'); +headElem.appendChild(styleElem); + +function drawOutput() { + output.innerHTML = htmlInput.value; + styleElem.textContent = cssInput.value; +} + +reset.addEventListener("click", function() { + htmlInput.value = htmlCode; + cssInput.value = cssCode; + drawOutput(); +}); + +solution.addEventListener("click", function() { + htmlInput.value = htmlCode; + cssInput.value = 'ul {\n list-style-type: square;\n}\n\nul li, ol li {\n line-height: 1.5;\n}\n\nol {\n list-style-type: lower-alpha\n}'; + drawOutput(); +}); + +htmlInput.addEventListener("input", drawOutput); +cssInput.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 800) }}</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Счетчики CSS предоставляют расширенные инструменты для настройки счета и оформления списков, но они довольно сложные.</span></span> <span class="tlid-translation translation" lang="ru"><span title="">Мы рекомендуем изучить это, если вы захотите размяться. Смотрите</span></span>:</p> + +<ul> + <li>{{cssxref("@counter-style")}}</li> + <li>{{cssxref("counter-increment")}}</li> + <li>{{cssxref("counter-reset")}}</li> +</ul> + +<h2 id="Заключение">Заключение</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В плане стилизации списки сравнительно легко освоить, как только вы освоите несколько связанных базовых принципов и специфичные свойства. В следующей статье мы перейдем к методам стилизации ссылок.</span></span></p> + +<p>{{PreviousMenuNext("Learn/CSS/Styling_text/Fundamentals", "Learn/CSS/Styling_text/Styling_links", "Learn/CSS/Styling_text")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Основы стилизации текста и шрифта</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">Стилизация списков</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_links">Стилизация ссылок</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">Веб-шрифты</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Typesetting_a_homepage">Верстка домашней страницы общественной школы</a></li> +</ul> diff --git a/files/ru/learn/css/как/index.html b/files/ru/learn/css/как/index.html new file mode 100644 index 0000000000..105c7f0a97 --- /dev/null +++ b/files/ru/learn/css/как/index.html @@ -0,0 +1,86 @@ +--- +title: Использование CSS для решения общих проблем +slug: Learn/CSS/Как +translation_of: Learn/CSS/Howto +--- +<p class="summary">Следующие ссылки указывают на решения общих повседневных проблем, вам придется решать их с помощью CSS.</p> + +<h2 id="Примеры_и_использование">Примеры и использование</h2> + +<div class="column-container"> +<div class="column-half"> +<h3 id="Основы">Основы</h3> + +<ul> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/How_CSS_works#How_to_apply_your_CSS_to_your_HTML">Как применить CSS к HTML</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Syntax#White_space">Как использовать пробелы в CSS</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Syntax#Comments">Как писать комментарии в CSS</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Simple_selectors">Как выбрать элементы через имя элемента, класс или ID</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Attribute_selectors">Как выбрать элементы через имя атрибута и содержания</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Pseudo-classes">Как использовать псевдо-классы</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Pseudo-elements">Как использовать псевдо-элементы</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Multiple_selectors_on_one_rule">Как применить несколько селекторов к тому же правилу</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Colors">Как определить цвета в CSS</a></li> + <li> + <p><a href="/en-US/Learn/CSS/Introduction_to_CSS/Debugging_CSS#Inspecting_the_DOM_and_CSS">Как отлаживать CSS в браузере</a></p> + </li> +</ul> + +<h3 id="CSS_и_текст">CSS и текст</h3> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Как стилизовать текст</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">How to customize a list of elements</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Styling_links">Как стилизовать ссылки</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Fundamentals#Text_drop_shadows">How to add shadows to text</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Блоки_и_разметка">Блоки и разметка</h3> + +<ul> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Box_properties">How to size CSS boxes</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Overflow">How to control overflowing content</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Background_clip">How to control the part of a CSS box that the background is drawn under</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Types_of_CSS_boxes">How do I define inline, block, and inline-block?</a></li> + <li><a href="/en-US/docs/Learn/CSS/Howto/create_fancy_boxes">How to create fancy boxes</a> (also see the <a href="/en-US/docs/Learn/CSS/Styling_boxes">Styling boxes</a> module, generally).</li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Background_clip">How to use <code>background-clip</code> to control how much of the box your background image covers</a>.</li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Box_model_recap#Changing_the_box_model_completely">How to change the box model completely using <code>box-sizing</code></a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Backgrounds">How to control backgrounds</a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Borders">How to control borders</a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Styling_tables">How to style an HTML table</a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Advanced_box_effects#Box_shadows">How to add shadows to boxes</a></li> +</ul> +</div> +</div> + +<h2 id="Необычное_или_передовые_технологии"><span class="short_text" id="result_box" lang="ru"><span>Необычное</span> <span>или</span> <span>передовые технологии</span></span></h2> + +<p>Beyond the basics, CSS is allows very advanced design techniques. These articles help you tackle the hardest use cases you may face.</p> + +<h3 id="Общие">Общие</h3> + +<ul> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance#Specificity">How to calculate specificity of a CSS selector</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance#Controlling_inheritance">How to control inheritance in CSS</a></li> +</ul> + +<h3 id="Дополнительные_эффекты"><span class="short_text" id="result_box" lang="ru"><span>Дополнительные</span> <span>эффекты</span></span></h3> + +<ul> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Advanced_box_effects#Filters">How to use filters in CSS</a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Advanced_box_effects#Blend_modes">How to use blend modes in CSS</a></li> +</ul> + +<h3 id="Разметка">Разметка</h3> + +<ul> + <li><a href="/en-US/docs/Web/Guide/CSS/Flexible_boxes">Using CSS flexible boxes</a></li> + <li><a href="/en-US/docs/Web/Guide/CSS/Using_multi-column_layouts" title="/en-US/docs/Web/Guide/CSS/Using_multi-column_layouts">Using CSS multi-column layouts</a></li> + <li><a href="/en-US/docs/Web/Guide/CSS/Getting_started/Content">Using CSS generated content</a></li> +</ul> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<p><a href="/en-US/docs/Learn/CSS/Howto/CSS_FAQ">CSS FAQ</a> — A collection of smaller bits of information, covering a variety of topics from debugging to selector usage.</p> diff --git a/files/ru/learn/discover_browser_developer_tools/index.html b/files/ru/learn/discover_browser_developer_tools/index.html new file mode 100644 index 0000000000..8cd514efcd --- /dev/null +++ b/files/ru/learn/discover_browser_developer_tools/index.html @@ -0,0 +1,172 @@ +--- +title: Обзор инструментов разработки в браузерах +slug: Learn/Discover_browser_developer_tools +tags: + - Beginner + - Browser + - CSS + - CodingScripting + - Dev Tools + - HTML + - JavaScript + - Браузер + - Новичку + - Обучение +translation_of: Learn/Common_questions/What_are_browser_developer_tools +--- +<div>{{IncludeSubnav("/ru-RU/Learn")}}</div> + +<p>{{Previous("Learn/Getting_started_with_the_web")}}</p> + +<div class="summary"> +<p>Каждый современный интернет-браузер оснащён мощными инструментами для веб-разработчика. Эти инструменты позволяют делать различные вещи, от изучения загруженных в настоящий момент HTML, CSS и JavaScript до отображения в каких ресурсах нуждается страница и как долго она будет загружаться. Эта статья научит Вас использовать базовые функции инструментов разработчика в Вашем браузере.</p> +</div> + +<div class="note"> +<p><strong>Заметка</strong>: Прежде чем начать заниматься с примерами, откройте <a href="http://mdn.github.io/beginner-html-site-scripted/">пример сайта для начинающих</a>, с которым мы работали на <a href="/en-US/Learn/Getting_started_with_the_web">предыдущих занятиях</a>. Вам следует держать его открытым, чтобы выполнить описанные ниже действия.</p> +</div> + +<h2 id="Как_открыть_инструменты_веб-разработчика_в_Вашем_браузере">Как открыть инструменты веб-разработчика в Вашем браузере?</h2> + +<p>Панель разработчика находится в нижней части Вашего браузера :</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9561/Screenshot%20from%202014-11-25%2012:32:57.png" style="display: block; height: 625px; margin: 0px auto; width: 775px;"></p> + +<p>Как её отобразить? Есть три варианта:</p> + +<ul> + <li><em><strong>Клавиатура.</strong></em> <em>Ctrl + Shift + I</em>, кроме + + <ul> + <li><strong>Internet Explorer. </strong><em>(клавиша - F12) </em></li> + <li><strong>Mac OS X. </strong><em><span class="Unicode">(сочетание клавиш - ⌘ + ⌥ + I )</span></em></li> + </ul> + </li> + <li><span class="Unicode"><em><strong>Панель Меню. </strong></em></span> + <ul> + <li><strong>Firefox. </strong>Открыть меню <img alt="" src="https://mdn.mozillademos.org/files/9637/2014-01-10-13-08-08-f52b8c.png" style="height: 16px; width: 16px;"> <span class="Unicode"><em><span class="Unicode">➤ <img alt="" src="https://mdn.mozillademos.org/files/9639/Screenshot%20from%202014-11-26%2014:24:56.png" style="height: 40px; width: 45px;"></span></em><em><span class="Unicode">➤ Инструменты разработки, или</span></em><span class="Unicode"> </span><em>Инструменты ➤</em></span><em> Веб-разработка ➤ Инструменты разработки</em></li> + <li><strong>Chrome.</strong> <em><span class="Unicode">Дополнительные инструменты ➤</span> Инструменты разработчика</em></li> + <li><strong>Safari.</strong> <em>Разработка <span class="Unicode">➤</span> Показать Web Inspector .</em> Если Вы не видите меню "Разработка", зайдите в <em>Safari<span class="Unicode"> ➤</span> Настройки ➤ Дополнительно, </em> и проверьте стоит ли галочка <em>напротив "Показать меню разработки"</em>. </li> + <li><strong>Opera</strong>. <em><span class="Unicode">Меню </span></em> <em><span class="Unicode">➤</span> </em> <em><span class="Unicode">Разработка ➤</span> Инструменты разработчика. </em> Если Вы не видите меню "Разработка", включите его отображение, перейдя в Меню <em><span class="Unicode">➤</span> </em> Другие инструменты <em><span class="Unicode">➤</span> </em>Показать меню разработчика.</li> + </ul> + </li> + <li><strong><em>Контекстное меню.</em></strong> Нажмите правой кнопкой мыши на любом участке веб-страницы (Ctrl-клик для Mac), появится контекстное меню, в котором Вам нужно выбрать пункт <em>Исследовать Элемент</em>. (<em>дополнение: </em>этот способ отобразит Вам код того элемента, на котором вы щёлкнули правой кнопкой.)</li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9605/inspect-element-option.png" style="display: block; height: 264px; margin: 0px auto; width: 350px;"></p> + +<h2 id="Inspector_DOM_обозреватель_и_CSS_редактор">Inspector: DOM обозреватель и CSS редактор</h2> + +<p>По-умолчанию, в панели открывается вкладка<em> </em>Inspector, Вы можете увидеть это на скриншоте снизу. Этот инструмент позволяет Вам видеть, как HTML-код выглядит на странице в настоящем времени, также как CSS, который применён к каждому элементу на странице. Это также позволяет Вам в реальном времени редактировать как HTML, так и CSS. Внесённые изменения можно увидеть непосредственно в окне браузера.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9607/inspector.png" style="display: block; height: 727px; margin: 0px auto; width: 800px;"></p> + +<p>Если Вы н<em>е видите</em> Inspector,</p> + +<ul> + <li>Нажмите на вкладку <em>Inspector </em>.</li> + <li>В Internet Explorer, нажмите на <em>DOM Обозреватель, </em>или нажмите Ctrl + 1.</li> + <li>В Safari, элементы управления представлены не так чётко, но Вы должны увидеть HTML код, если Вы не выбрали что-то другое в окне разработки. Нажмите на кнопку <em>Стиль,</em> чтобы увидеть CSS.</li> +</ul> + +<h3 id="Обзор_DOM_inspector">Обзор DOM inspector</h3> + +<p>Для начала, попробуйте нажать правой кнопкой мыши (Ctrl+клик) по элементу HTML в DOM inspector и посмотрите на контекстное меню. Пункты меню могут различаться в разных браузерах, но важными из них являются одни и те же:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9609/dev-tool-context-menu.png" style="display: block; height: 236px; margin: 0px auto; width: 200px;"></p> + +<ul> + <li><strong>Удалить узел</strong> (иногда <em>Удалить элемент</em>). Удаляет текущий элемент.</li> + <li><strong>Править как HTML</strong> (иногда <em>Добавить атрибут</em>/<em>Править текст</em>). Позволяет редактировать HTML и видеть результат "вживую". Очень полезно для отладки и тестирования.</li> + <li><strong>:hover/:active/:focus</strong>. Заставляет элементы переключить своё состояние на то, к которому применён Ваш стиль.</li> + <li><strong>Копировать/Копировать как HTML</strong>. Копирует текущий выделенный HTML.</li> +</ul> + +<p>Попробуйте изменить что-нибудь через окно Inspector на Вашей странице прямо сейчас. Дважды кликните по элементу, или нажмите правой кнопкой мыши и выберите <em>Править как HTML </em>из контекстного меню. Вы можете сделать любые изменения, какие захотите, но Вы не сможете их сохранить.</p> + +<h3 id="Обзор_CSS_редактора">Обзор CSS редактора</h3> + +<p>По-умолчанию, CSS редактор отображает CSS свойства применённые к текущему выбранному элементу:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9631/css-viewer-2.png" style="border: 1px solid black; display: block; height: 218px; margin: 0px auto; width: 326px;"></p> + +<p>Эти функции особенно удобны:</p> + +<ul> + <li>Свойства, применённые к текущему элементу, отображаются в порядке убывания приоритета.</li> + <li>Можно убирать галочки напротив свойств для того чтобы видеть, что получится, если их удалить.</li> + <li>Нажмите на маленькую стрелочку рядом со свойством, чтобы увидеть все его эквиваленты.</li> + <li>Нажмите на имя свойства или его значение, чтобы открыть текстовое окошко, в котором Вы можете задать новые значения и увидеть, как изменится Ваш элемент с новыми значениями.</li> + <li>Рядом с каждым свойством указаны имя файла и номер строки. где располагается это свойство. Щелчок по этому пути перенесёт Вас в окно, где можно редактировать этот CSS и сохранить.</li> + <li>Вы можете также нажать на закрывающуюся фигурную скобку любого свойства, чтобы вывести текстовое поле на новую строку, где Вы сможете написать совершенно новую декларацию для Вашей страницы.</li> +</ul> + +<p>Вы должно быть уже заметили другие вкладки в CSS редакторе:</p> + +<ul> + <li><em>Вычислено</em>: Здесь указаны все вычисления свойств выделенного элемента (окончательные, нормализованные значения применённые браузером).</li> + <li><em>Блоковая модель</em>: Отображает блочную модель выделенного элемента, здесь Вы можете увидеть внешние и внутренние отступы, а также границы применённые к элементу, здесь также указан их размер.</li> + <li><em>Анимации</em>: В Firefox, на вкладке <em>Анимации</em> Вы можете увидеть анимации применённые к выделенному элементу.</li> +</ul> + +<h3 id="Узнать_больше">Узнать больше</h3> + +<p>Узнать больше об Inspector в различных браузерах:</p> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector">Firefox Page inspector</a></li> + <li><a href="http://msdn.microsoft.com/en-us/library/ie/dn255008%28v=vs.85%29.aspx">IE DOM Explorer</a></li> + <li><a href="https://developer.chrome.com/devtools/docs/dom-and-styles">Chrome DOM inspector</a> (Inspector в Opera схож с Inspector в Chrome)</li> + <li><a href="https://developer.apple.com/library/safari/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/ResourcesandtheDOM/ResourcesandtheDOM.html#//apple_ref/doc/uid/TP40007874-CH3-SW1">Safari DOM inspector and style explorer</a></li> +</ul> + +<h2 id="Консоль_JavaScript">Консоль JavaScript </h2> + +<p>Консоль JavaScript невероятно полезный инструмент для отладки JavaScript, если он не работает, как ожидалось. Она позволяет Вам загружать JavaScript вопреки порядку загрузки скрипта в браузере, и докладывает об ошибках как только браузер пытается выполнить Ваш код. Для доступа к консоли из любого браузера просто нажмите на кнопку Console. (В Internet Explorer, нажмите <em>Ctrl + 2</em>.) Откроется окно, как показано ниже:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9541/console.png" style="border: 1px solid black; display: block; height: 249px; margin: 0px auto; width: 821px;"></p> + +<p>Чтобы понять, что происходит, попробуйте ввести фрагменты кода в консоль один за другим (и затем нажмите Enter):</p> + +<ol> + <li> + <pre class="brush: js">alert('hello!');</pre> + </li> + <li> + <pre class="brush: js">document.querySelector('html').style.backgroundColor = 'purple';</pre> + </li> + <li> + <pre class="brush: js">var myImage = document.createElement('img'); +myImage.setAttribute('src','https://farm4.staticflickr.com/3455/3372925208_e1f2aae4e3_b.jpg'); +document.querySelector('h1').appendChild(myImage);</pre> + </li> +</ol> + +<p>Теперь попробуйте ввести следующую, неправильную версию кода и посмотрите, что из этого получится.</p> + +<ol> + <li> + <pre class="brush: js">alert('hello!);</pre> + </li> + <li> + <pre class="brush: js">document.cheeseSelector('html').style.backgroundColor = 'purple';</pre> + </li> + <li> + <pre class="brush: js">var myImage = document.createElement('img'); +myBanana.setAttribute('src','https://farm4.staticflickr.com/3455/3372925208_e1f2aae4e3_b.jpg'); +document.querySelector('h1').appendChild(myImage);</pre> + </li> +</ol> + +<p>Вы увидите некоторые ошибки, которые сообщит Вам браузер. Зачастую эти ошибки выглядят довольно загадочно, но они должны быть довольно простыми, чтобы можно было выяснить проблему!</p> + +<h3 id="Узнать_больше_2">Узнать больше</h3> + +<p>Узнать больше о JavaScript консоли в различных браузерах:</p> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Tools/Web_Console">Firefox Web Console</a></li> + <li><a href="http://msdn.microsoft.com/en-us/library/ie/dn255006%28v=vs.85%29.aspx">IE JavaScript console</a></li> + <li><a href="https://developer.chrome.com/devtools/docs/console">Chrome JavaScript Console</a> (Inpector в Opera схож с Inspector в Chrome)</li> + <li><a href="https://developer.apple.com/library/safari/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/Console/Console.html#//apple_ref/doc/uid/TP40007874-CH6-SW1">Safari Console</a></li> +</ul> diff --git a/files/ru/learn/getting_started_with_the_web/css_basics/index.html b/files/ru/learn/getting_started_with_the_web/css_basics/index.html new file mode 100644 index 0000000000..a091f49fc3 --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/css_basics/index.html @@ -0,0 +1,295 @@ +--- +title: Основы CSS +slug: Learn/Getting_started_with_the_web/CSS_basics +tags: + - Beginner + - CSS + - CodingScripting + - Learn + - Styling + - Web + - Веб + - Новичку + - Обучение +translation_of: Learn/Getting_started_with_the_web/CSS_basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p>CSS (Cascading Style Sheets) — это код, который вы используете для стилизации вашей веб-страницы. <em>Основы CSS</em> помогут вам понять, что вам нужно для начала работы. Мы ответим на такие вопросы как: Как сделать мой текст черным или красным? Как сделать так, чтобы контент появлялся в определенном месте на экране? Как украсить мою веб-страницу с помощью фоновых изображений и цветов?</p> +</div> + +<h2 id="Так_что_же_такое_CSS">Так что же такое CSS? </h2> + +<p>Как и HTML, CSS на самом деле не является языком программирования. Это не язык разметки - это <em>язык таблицы стилей. </em>Это означает, что он позволяет применять стили выборочно к элементам в документах HTML. Например, чтобы выбрать <strong>все</strong> элементы абзаца на HTML странице и изменить текст внутри них с черного на красный, вы должны написать этот CSS:</p> + +<pre class="notranslate"><code>p { + color: red; +}</code></pre> + +<p>Давайте попробуем: вставьте эти три строки CSS в новый файл в ваш текстовый редактор, а затем сохраните файл как <code>style.css</code> в вашей папке <code>styles</code>.</p> + +<p>Но нам все равно нужно применить CSS к нашему HTML документу. В противном случае, CSS стиль не повлияет на то, как ваш браузер отобразит HTML документ. (Если вы не следили за нашим проектом, то прочитайте раздел <a href="/ru/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a> и <a href="/ru/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a>, чтобы узнать, что вам нужно сделать в первую очередь.)</p> + +<ol> + <li>Откройте ваш файл <code>index.html</code> и вставьте следующую строку куда-нибудь в шапку, между <code><head></code> и <code></head></code> тегами: + + <pre class="brush: html notranslate"><link href="styles/style.css" rel="stylesheet" type="text/css"></pre> + </li> + <li>Сохраните <code>index.html</code> и загрузите его в вашем браузере. Вы должны увидеть что-то вроде этого:</li> +</ol> + +<p><img alt="A mozilla logo and some paragraphs. The paragraph text has been styled red by our css." src="https://mdn.mozillademos.org/files/9435/website-screenshot-styled.png" style="display: block; height: 832px; margin: 0px auto; width: 711px;">Если текст вашего абзаца теперь красный, примите наши поздравления! Вы написали свой первый успешный CSS!</p> + +<h3 id="Анатомия_набора_правил_CSS">Анатомия набора правил CSS</h3> + +<p>Давайте взглянем на вышеупомянутый CSS немного более подробно:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9461/css-declaration-small.png" style="display: block; height: 480px; margin: 0px auto; width: 850px;"></p> + +<p>Вся структура называется <strong>набором правил</strong> (но зачастую для краткости "правило"). Отметим также имена отдельных частей:</p> + +<dl> + <dt>Селектор (Selector)</dt> + <dd>Имя HTML элемента в начале набора правил. Он выбирает элемент(ы) для применения стиля (в данном случае, элементы <code>p</code> ). Для стилизации другого элемента, просто измените селектор.</dd> + <dt>Объявление (Declaration)</dt> + <dd>Единственное правило, например <code>color: red;</code> указывает, какие из <strong>свойств</strong> элемента вы хотите стилизовать.</dd> + <dt>Свойства (Properties)</dt> + <dd>Способы, которыми вы можете стилизовать определенный HTML элемент (в данном случае, <code>color</code> является свойством для элементов {{htmlelement("p")}}). В CSS вы выбираете, какие свойства вы хотите затронуть в вашем правиле.</dd> + <dt>Значение свойства (Property value)</dt> + <dd>Справа от свойства, после двоеточия, у нас есть <strong>значение свойства</strong>, которое выбирает одно из множества возможных признаков для данного свойства (существует множество значений <code>color</code>, помимо <code>red</code>).</dd> +</dl> + +<p>Обратите внимание на важные части синтаксиса:</p> + +<ul> + <li>Каждый набор правил (кроме селектора) должен быть обернут в фигурные скобки (<code>{}</code>).</li> + <li>В каждом объявлении необходимо использовать двоеточие (<code>:</code>), чтобы отделить свойство от его значений.</li> + <li>В каждом наборе правил вы должны использовать точку с запятой (<code>;</code>), чтобы отделить каждое объявление от следующего.</li> +</ul> + +<p>Таким образом, чтобы изменить несколько значений свойств сразу, вам просто нужно написать их, разделяя точкой с запятой, например так:</p> + +<pre class="brush: css notranslate">p { + color: red; + width: 500px; + border: 1px solid black; +}</pre> + +<h3 id="Выбор_нескольких_элементов">Выбор нескольких элементов</h3> + +<p>Вы также можете выбрать несколько элементов разного типа и применить единый набор правил для всех из них. Добавьте несколько селекторов, разделенных запятыми. Например:</p> + +<pre class="brush: css notranslate">p,li,h1 { + color: red; +}</pre> + +<h3 id="Разные_типы_селекторов">Разные типы селекторов</h3> + +<p>Существует множество различных типов селектора. Выше мы рассматривали только <strong>селектор элементов</strong>, который выбирает все элементы определенного типа в HTML документе. Но мы можем сделать выбор более конкретным. Вот некоторые из наиболее распространенных типов селекторов:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Имя селектора</th> + <th scope="col">Что выбирает</th> + <th scope="col">Пример</th> + </tr> + </thead> + <tbody> + <tr> + <td>Селектор элемента (иногда называемый селектором тега или типа)</td> + <td>Все HTML элемент(ы) указанного типа.</td> + <td><code>p</code><br> + Выбирает <code><p></code></td> + </tr> + <tr> + <td>ID селектор</td> + <td>Элемент на странице с указанным ID на данной HTML. Лучше всего использовать один элемент для каждого ID (и конечно один ID для каждого элемента), даже если вам разрешено использовать один и тот же ID для нескольких элементов.</td> + <td><code>#my-id</code><br> + Выбирает <code><p id="my-id"></code> или <code><a id="my-id"></code></td> + </tr> + <tr> + <td>Селектор класса</td> + <td>Элемент(ы) на странице с указанным классом (множество экземпляров класса может объявляться на странице).</td> + <td><code>.my-class</code><br> + Выбирает <code><p class="my-class"></code> и <code><a class="my-class"></code></td> + </tr> + <tr> + <td>Селектор атрибута</td> + <td>Элемент(ы) на странице с указанным атрибутом.</td> + <td><code>img[src]</code><br> + Выбирает <code><img src="myimage.png"></code> но не <code><img></code></td> + </tr> + <tr> + <td>Селектор псевдо-класса</td> + <td>Указанные элемент(ы), но только в случае определенного состояния, например, при наведении курсора.</td> + <td><code>a:hover</code><br> + Выбирает <code><a></code>, но только тогда, когда указатель мыши наведен на ссылку.</td> + </tr> + </tbody> +</table> + +<p>Существует еще много селекторов для изучения, и вы можете найти более подробный список в нашем <a href="/ru/docs/Web/Guide/CSS/Getting_started/Selectors">Руководстве селекторов</a>.</p> + +<h2 id="Шрифты_и_текст">Шрифты и текст</h2> + +<p>Теперь, когда мы изучили некоторые основы CSS, давайте добавим ещё несколько правил и информацию в наш файл <code>style.css</code>, чтобы наш пример хорошо выглядел. Прежде всего, давайте сделаем, чтобы наши шрифты и текст выглядели немного лучше.</p> + +<ol> + <li>Прежде всего, вернитесь и найдите <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">вывод из Google Fonts</a>, который вы уже где-то сохранили. Добавьте элемент {{htmlelement("link")}} где-нибудь внутри шапки вашего <code>index.html</code> (снова, в любом месте между тегами <code><head></code> и <code></head></code>). Это будет выглядеть примерно так: + + <pre class="brush: html notranslate"><link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'></pre> + Этот код связывает вашу страницу с таблицой стилями, которая загружает семейство шрифтов Open Sans вместе с вашей страницой и позволяет вам применять их к вашим HTML элементам используя свою собственную таблицу стилей.</li> + <li>Затем, удалите существующее правило в вашем <code>style.css</code> файле. Это был хороший тест, но красный текст, на самом деле, не очень хорошо выглядит.</li> + <li>Добавьте следующие строки в нужное место, заменив строку <code>placeholder</code> актуальной <code>font-family</code> строкой, которую вы получили из Google Fonts. (<code>font-family</code> просто означает, какой шрифт(ы) вы хотите использовать для вашего текста). Это правило устанавливает глобальный базовый шрифт и размер шрифта для всей страницы (поскольку <code><html></code> является родительским элементом для всей страницы, и все элементы внутри него наследуют такой же <code>font-size</code> и <code>font-family</code>): + <pre class="brush: css notranslate">html { + font-size: 10px; /* px значит 'пиксели': базовый шрифт будет 10 пикселей в высоту */ + font-family: placeholder: здесь должно быть имя шрифта из Google fonts +}</pre> + + <div class="note"> + <p><strong>Примечание</strong>: Все в CSS документе между <code>/*</code> и <code>*/ </code> является <strong>CSS комментарием</strong>, который браузер игнорирует при исполнении кода. Это место, где вы можете написать полезные заметки о том, что вы делаете.</p> + </div> + </li> + <li>Теперь мы установим размер шрифта для элементов, содержащих текст внутри HTML тела ({{htmlelement("h1")}}, {{htmlelement("li")}}, и {{htmlelement("p")}}). Мы также отцентрируем текст нашего заголовка и установим некоторую высоту строки и расстояние между буквами в теле документа, чтобы сделать его немного более удобным для чтения: + <pre class="brush: css notranslate">h1 { + font-size: 60px; + text-align: center; +} + +p, li { + font-size: 16px; + line-height: 2; + letter-spacing: 1px; +}</pre> + </li> +</ol> + +<p>Вы можете настроить значения <code>px</code> так, как вам нравится, чтобы ваш дизайн выглядел так, как вы хотите, но, в общем, ваш дизайн должен выглядеть вот так:</p> + +<p><img alt="a mozilla logo and some paragraphs. a sans-serif font has been set, the font sizes, line height and letter spacing are adjusted, and the main page heading has been centered" src="https://mdn.mozillademos.org/files/9447/website-screenshot-font-small.png" style="display: block; height: 1020px; margin: 0px auto; width: 921px;"></p> + +<h2 id="Блоки_блоки_и_ещё_раз_блоки">Блоки, блоки и ещё раз блоки</h2> + +<p>Одна вещь, которую вы заметите в написании CSS, заключается в том, что многое из этого касается блоков - настройка их размера, цвета, положения и т.д. Большинство HTML элементов на странице можно рассматривать как блоки, расположенные друг над другом.</p> + +<p><img alt="a big stack of boxes or crates sat on top of one another" src="https://mdn.mozillademos.org/files/9441/boxes.jpg" style="display: block; height: 463px; margin: 0px auto; width: 640px;"></p> + +<p>Не удивительно, макет CSS основан, главным образом, на <em>блочной модели (box model)</em>. Каждый из блоков, занимающий пространство на вашей странице имеет такие свойства, как:</p> + +<ul> + <li><code>padding</code>, пространство только вокруг контента (например, вокруг абзаца текста)</li> + <li><code>border</code>, сплошная линия, которая расположена рядом с padding</li> + <li><code>margin</code>, пространство вокруг внешней стороны элемента</li> +</ul> + +<p><img alt="three boxes sat inside one another. From outside to in they are labelled margin, border and padding" src="https://mdn.mozillademos.org/files/9443/box-model.png" style="display: block; height: 450px; margin: 0px auto; width: 574px;"></p> + +<p>В этом разделе мы также используем:</p> + +<ul> + <li><code>width</code> (ширину элемента)</li> + <li><code>background-color</code>, цвет позади контента и padding элементов</li> + <li><code>color</code>, цвет контента элемента (обычно текста)</li> + <li><code>text-shadow</code>: устанавливает тень на тексте внутри элемента</li> + <li><code>display</code>: устанавливает режим отображения элемента (пока что не волнуйтесь об этом)</li> +</ul> + +<p>Итак, давайте начнем и добавим больше CSS на нашей странице! Продолжайте добавлять эти новые правила, расположенные в нижней части страницы, и не бойтесь экспериментировать с изменением значений, чтобы увидеть, как это работает.</p> + +<h3 id="Изменение_цвета_страницы">Изменение цвета страницы</h3> + +<pre class="brush: css notranslate">html { + background-color: #00539F; +}</pre> + +<p>Это правило устанавливает цвет фона для всей страницы. Измените код цвета сверху, на цвет который <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">вы выбрали при планировании вашего сайта</a>.</p> + +<h3 id="Разбираемся_с_телом">Разбираемся с телом</h3> + +<pre class="brush: css notranslate">body { + width: 600px; + margin: 0 auto; + background-color: #FF9500; + padding: 0 20px 20px 20px; + border: 5px solid black; +}</pre> + +<p>Теперь для {{htmlelement("body")}} элемента. Здесь есть немало деклараций, так что давайте пройдем через них всех по одному:</p> + +<ul> + <li><code>width: 600px;</code> — заставляет тело быть всегда 600 пикселей в ширину.</li> + <li><code>margin: 0 auto;</code> — когда вы устанавливаете два значения для таких свойств как <code>margin</code> или <code>padding</code>, первое значение элемента влияет на верхнюю <strong>и</strong> нижнюю сторону (делает их <code>0</code> в данном случае), и второе значение на левую <strong>и</strong> правую сторону (здесь, <code>auto</code> является особым значением, которое делит доступное пространство по горизонтали поровну слева и справа). Вы также можете использовать один, три или четыре значения, как описано <a href="https://developer.mozilla.org/ru/docs/Web/CSS/margin#Values">здесь</a>.</li> + <li><code>background-color: #FF9500;</code> — как и прежде, устанавливает цвет фона элемента. Я использовал красновато-оранжевый для тела, в отличие от темно-синего цвета для {{htmlelement("html")}} элемента, но не стесняйтесь и эксперементируйте.</li> + <li><code>padding: 0 20px 20px 20px;</code> — у нас есть четыре значения, установленные для padding, чтобы сделать немного пространства вокруг нашего контента. В этот раз мы не устанавливаем padding на верхней части тела, но делаем 20 пикселей слева, снизу и справа. Значения устанавливаются сверху, справа, снизу, слева, в таком порядке.</li> + <li><code>border: 5px solid black;</code> — просто устанавливает сплошную черную рамку шириной 5 пикселей со всех сторон тела.</li> +</ul> + +<h3 id="Позиционирование_и_стилизация_нашего_заголовка_главной_страницы">Позиционирование и стилизация нашего заголовка главной страницы</h3> + +<pre class="brush: css notranslate">h1 { + margin: 0; + padding: 20px 0; + color: #00539F; + text-shadow: 3px 3px 1px black; +}</pre> + +<p>Вы, возможно, заметили, что есть ужасный разрыв в верхней части тела. Это происходит, потому что браузеры применяют некоторый <strong>стиль по умолчанию</strong> для элемента {{htmlelement("h1")}} (по сравнению с другими), даже если вы не применяли какой-либо CSS вообще! Это может звучать как плохая идея, но мы хотим, чтобы веб-страница без стилей имела базовую читаемость. Чтобы избавиться от разрыва, мы переопределили стиль по умолчанию, установив <code>margin: 0;</code>.</p> + +<p>Затем мы установили заголовку верхний и нижний padding на 20 пикселей, и сделали текст заголовка того же цвета, как и цвет фона html.</p> + +<p>Здесь, мы использовали одно довольно интересное свойство - это <code>text-shadow</code>, которое применяет тень к текстовому контенту элемента. Оно имеет следующие четыре значения:</p> + +<ul> + <li>Первое значение пикселей задает <strong>горизонтальное смещение</strong> тени от текста — как далеко она движется поперек: отрицательное значение должно двигать ее влево.</li> + <li>Второе значение пикселей задает <strong>вертикальное смещение</strong> тени от текста — как далеко она движется вниз, в этом примере: отрицательное значение должно переместить ее вверх.</li> + <li>Третье значение пикселей задает <strong>радиус размытия</strong> тени — большее значение будет означать более размытую тень.</li> + <li>Четвертое значение задает основной цвет тени.</li> +</ul> + +<p>И вновь попробуйте поэкспериментировать с различными значениями, чтобы посмотреть, что вы можете придумать.</p> + +<h3 id="Центрирование_изображения">Центрирование изображения</h3> + +<pre class="brush: css notranslate">img { + display: block; + margin: 0 auto; +}</pre> + +<p>В заключение, мы отцентрируем изображение, чтобы оно лучше выглядело. Мы можем использовать <code>margin: 0 auto</code> уловку снова, как мы это делали раньше для body, но мы также должны сделать кое-что еще. Элемент {{HTMLElement("body")}} является <strong>блочным</strong>, это значит, что он занимает место на странице и может иметь margin и другие значения отступов, применяемых к нему. Изображения, наоборот, являются <strong>строчными</strong> элементами, то есть они этого не могут. Таким образом, чтобы применить margin к изображению, мы должны дать изображению блочное поведение с помощью <code>display: block;</code>.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание: </strong>Приведенные выше инструкции предполагают, что вы используете изображение меньшей ширины, чем заданная для {{HTMLElement("body")}} (600 пикселей). Если ваше изображение больше, тогда оно выйдет за границы {{HTMLElement("body")}} и займет пространство страницы. Чтобы исправить это, вы можете 1) уменьши ширину изображения используя <a href="https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B2%D1%8B%D0%B9_%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%BE%D1%80">графический редактор</a>, или 2) изменить размер изображения используя CSS путем установки свойства {{cssxref("width")}} для <code><img></code> элемента меньшего значения (например <code>400 px;</code>).</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Не стоит беспокоиться, если вы еще не понимаете <code>display: block;</code> и различия между блочным/строчным. Вы поймете, когда будете изучать CSS более подробно. Вы можете узнать больше о различных доступных значениях display на нашей странице о свойстве <a href="/ru/docs/Web/CSS/display">display</a>.</p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>Если вы следовали всем инструкциям в этой статье, вы должны получить страницу, которая выглядит примерно так (вы также можете <a href="http://mdn.github.io/beginner-html-site-styled/">посмотреть нашу версию здесь</a>):</p> + +<p><img alt="a mozilla logo, centered, and a header and paragraphs. It now looks nicely styled, with a blue background for the whole page and orange background for the centered main content strip." src="https://mdn.mozillademos.org/files/9455/website-screenshot-final.png" style="display: block; height: 1084px; margin: 0px auto; width: 940px;"></p> + +<p>Если вы застряли, вы всегда можете сравнить свою работу с нашим <a href="https://github.com/mdn/beginner-html-site-styled/blob/gh-pages/styles/style.css">готовым примером кода на Github</a>.</p> + +<p>Здесь мы узнали только самую поверхность CSS. Чтобы узнать больше, перейдите на нашу <a href="https://developer.mozilla.org/ru/Learn/CSS">страницу изучения CSS</a>.</p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового программного обеспечения</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего веб-сайта</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Веб</a></li> +</ul> diff --git a/files/ru/learn/getting_started_with_the_web/dealing_with_files/index.html b/files/ru/learn/getting_started_with_the_web/dealing_with_files/index.html new file mode 100644 index 0000000000..ec66653d61 --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/dealing_with_files/index.html @@ -0,0 +1,126 @@ +--- +title: Работа с файлами +slug: Learn/Getting_started_with_the_web/Dealing_with_files +tags: + - Beginner + - CodingScripting + - Files + - Guide + - HTML + - theory + - website + - Новичку + - Руководство + - Файлы + - сайт +translation_of: Learn/Getting_started_with_the_web/Dealing_with_files +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p>Веб-сайт состоит из множества файлов: текстового контента, кода, стилей, медиа-контента, и так далее. Когда вы создаете веб-сайт, вы должны собрать эти файлы в рациональную структуру на вашем локальном компьютере, убедитесь, что они могут общаться друг с другом, и весь ваш контент выглядит правильно, прежде чем вы, в конечном итоге <a href="/ru/Learn/Getting_started_with_the_web/Publishing_your_website">загрузите их на сервер</a>. В статье <em>Работа с файлами</em> обсуждаются некоторые вопросы, о которых вам следует знать, чтобы вы могли рационально настроить файловую структуру для своего веб-сайта.</p> +</div> + +<h2 id="Где_ваш_веб-сайт_должен_располагаться_на_вашем_компьютере">Где ваш веб-сайт должен располагаться на вашем компьютере?</h2> + +<p>Когда вы работаете на веб-сайте локально на вашем компьютере, вы должны держать все связанные файлы в одной папке, которая отражает файловую структуру опубликованного веб-сайта на сервере. Эта папка может располагаться где угодно, но вы должны положить её туда, где вы сможете легко её найти, может быть, на ваш рабочий стол, в домашнюю папку или в корень вашего жесткого диска.</p> + +<ol> + <li>Выберите место для хранения проектов веб-сайта. Здесь, создайте новую папку с именем <code>web-projects</code> (или аналогичной). Это то место, где будут располагаться все ваши проекты сайтов.</li> + <li>Внутри этой первой папки, создайте другую папку для хранения вашего первого веб-сайта. Назовите ее <code>test-site</code> (или как-то более творчески).</li> +</ol> + +<h2 id="Небольшое_отступление_о_регистре_и_пробелах">Небольшое отступление о регистре и пробелах</h2> + +<p>Вы заметите, что в этой статье, мы просим вас называть папки и файлы полностью в нижнем регистре без пробелов. Это потому что:</p> + +<ol> + <li>Многие компьютеры, в частности веб-серверы, чувствительны к регистру. Так, например, если вы положили изображение на свой веб-сайт в <code>test-site/MyImage.jpg</code>, а затем в другом файле вы пытаетесь вызвать изображение как <code>test-site/myimage.jpg</code>, это может не сработать.</li> + <li>Браузеры, веб-серверы и языки программирования не обрабатывают пробелы последовательно. Например, если вы используете пробелы в имени файла, некоторые системы могут отнестись к имени файла как к двум именам файлов. Некоторые серверы заменяют пробелы в вашем имени файла на "%20" (символьный код для пробелов в URI), в результате чего все ваши ссылки будут сломаны. Лучше разделять слова дефисами, чем нижними подчеркиваниями: <code>my-file.html</code> лучше чем <code>my_file.html</code>.</li> +</ol> + +<p>Говоря простым языком, вы должны использовать дефис для имен файлов. Поисковая система Google рассматривает дефис как разделитель слов, но не относится к подчеркиванию таким образом. По этим причинам, лучше всего приобрести привычку писать названия ваших папок и файлов в нижнем регистре без пробелов, разделяя слова дефисами, по крайней мере, пока вы не поймете, что вы делаете. Так в будущем вы столкнетесь с меньшим количеством проблем.</p> + +<h2 id="Какую_структуру_должен_иметь_ваш_веб-сайт">Какую структуру должен иметь ваш веб-сайт?</h2> + +<p>Далее, давайте взглянем на то, какую структуру должен иметь наш тестовый сайт. Наиболее распространенные вещи, присутствующие в любом проекте сайта, которые мы создаем: индексный файл HTML и папки, содержащие изображения, файлы стилей и файлы скриптов. Давайте создадим их сейчас:</p> + +<ol> + <li><code><strong>index.html</strong></code>: Этот файл обычно содержит контент домашней страницы, то есть текст и изображения, которые люди видят, когда они впервые попадают на ваш сайт. Используя ваш текстовый редактор, создайте новый файл с именем <code>index.html</code> и сохраните его прямо внутри вашей папки <code>test-site</code>.</li> + <li><strong>Папка <code>images</code></strong>: Эта папка будет содержать все изображения, которые вы используете на вашем сайте. Создайте папку с именем <code>images</code> внутри вашей папки <code>test-site</code>.</li> + <li><strong>Папка <code>styles</code></strong>: Эта папка будет содержать CSS код, используемый для стилизации вашего контента (например, настройка текста и цвета фона). Создайте папку с именем <code>styles</code> внутри вашей папки <code>test-site</code>.</li> + <li><strong>Папка <code>scripts</code></strong>: Эта папка будет содержать весь JavaScript код, используемый для добавления интерактивных функций на вашем сайте (например, кнопки которые загружают данные при клике). Создайте папку с именем <code>scripts</code> внутри вашей папки <code>test-site</code>.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: На компьютерах под управлением Windows у вас могут возникнуть проблемы с отображением имен файлов, поскольку у Windows есть опция <strong>Скрывать расширения для известных типов файлов</strong>, включенная по умолчанию. Обычно вы можете отключить ее, перейдя в проводник, выбрать вариант <strong>Свойства папки...</strong> и снять флажок <strong>Скрывать расширения для зарегистрированных типов файлов</strong>, затем щёлкнуть <strong>OK</strong>. Для получения более точной информации, охватывающей вашу версию Windows, вы можете произвести поиск в Интернете.</p> +</div> + +<h2 id="Файловые_пути">Файловые пути</h2> + +<p>Для того, чтобы файлы общались друг с другом, вы должны указать файлам путь друг к другу - обычно один файл знает, где находится другой. Чтобы продемонстрировать это, мы вставим немного HTML в наш файл <code>index.html</code> и научим его отображать изображение, которое вы выбрали в статье <a href="/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">"Каким должен быть ваш веб-сайт?"</a></p> + +<ol> + <li>Скопируйте изображение, которое вы выбрали ранее, в папку <code>images</code>.</li> + <li>Откройте ваш файл <code>index.html</code> и вставьте следующий код в файл именно в таком виде. Не беспокойтесь о том, что все это значит - позже в этом руководстве мы рассмотрим сруктуры более подробно. + <pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Моя тестовая страница</title> + </head> + <body> + <img src="" alt="Моё тестовое изображение"> + </body> +</html> </pre> + </li> + <li>Строка <code><img src="" alt="Моё тестовое изображение"></code> - это HTML код, который вставляет изображение на страницу. Мы должны сказать HTML, где находится изображение. Изображение находится внутри папки <em>images</em>, которая находится в той же директории что и <code>index.html</code>. Чтобы спуститься вниз по нашей файловой структуре от <code>index.html</code> до нашего изображения, путь к файлу должен выглядеть так <code>images/your-image-filename</code>. Например наше изображение, названное <code>firefox-icon.png</code>, имеет такой путь к файлу: <code>images/firefox-icon.png</code>.</li> + <li>Вставьте путь к файлу в ваш HTML код между двойными кавычками <code>src=""</code>.</li> + <li>Сохраните ваш HTML файл, а затем загрузите его в вашем браузере (двойной щелчок по файлу). Вы должны увидеть вашу новую веб-страницу, отображающую ваше изображение!</li> +</ol> + +<p><img alt="A screenshot of our basic website showing just the firefox logo - a flaming fox wrapping the world" src="https://mdn.mozillademos.org/files/9229/website-screenshot.png" style="display: block; height: 542px; margin: 0px auto; width: 690px;"></p> + +<p>Некоторые общие правила о путях к файлам:</p> + +<ul> + <li>Для ссылки на целевой файл в той же директории, что и вызывающий HTML файл, просто используйте имя файла, например, <code>my-image.jpg</code>.</li> + <li>Для ссылки на файл в поддиректории, напишите имя директории в начале пути, плюс косую черту (forwardslash, слеш), например: <code>subdirectory/my-image.jpg</code>.</li> + <li>Для ссылки на целевой файл в директории <strong>выше</strong> вызывающего HTML файла, напишите две точки. Например, если <code>index.html</code> находится внутри подпапки <code>test-site</code>, а <code>my-image.png</code> - внутри <code>test-site</code>, вы можете обратиться к <code>my-image.png</code> из <code>index.html</code>, используя <code>../my-image.png</code>.</li> + <li>Вы можете комбинировать их так, как вам нравится, например <code>../subdirectory/another-subdirectory/my-image.png</code>.</li> +</ul> + +<p>На данный момент это все, что вам нужно знать</p> + +<div class="note"> +<p><strong>Примечание</strong>: Файловая система Windows стремится использовать обратный слеш (backslash), а не косую черту (forwardslash), например <code>C:\windows</code>. Это не имеет значения, даже если вы разрабатываете веб-сайт на Windows, вы все равно должны использовать обычные слеши в вашем коде.</p> +</div> + +<h2 id="Что_должно_быть_сделано">Что должно быть сделано?</h2> + +<p>К настоящему моменту структура вашей папки должна выглядеть примерно так:</p> + +<p><img alt="A file structure in mac os x finder, showing an images folder with an image in, empty scripts and styles folders, and an index.html file" src="https://mdn.mozillademos.org/files/9231/file-structure.png" style="display: block; height: 577px; margin: 0px auto; width: 929px;"></p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web")}}</p> + +<p> </p> + +<p> </p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового программного обеспечения</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего веб-сайта</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Веб</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/getting_started_with_the_web/how_the_web_works/index.html b/files/ru/learn/getting_started_with_the_web/how_the_web_works/index.html new file mode 100644 index 0000000000..27175cb898 --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/how_the_web_works/index.html @@ -0,0 +1,113 @@ +--- +title: Как работает Веб +slug: Learn/Getting_started_with_the_web/How_the_Web_works +tags: + - Beginner + - Client + - DNS + - HTTP + - IP + - Infrastructure + - Learn + - TCP + - Инфраструтура + - Клиент + - Новичку + - Обучение + - Сервер +translation_of: Learn/Getting_started_with_the_web/How_the_Web_works +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p><em>Как работает Веб</em> даст упрощенное представление о том, что происходит при просмотре веб-страницы в браузере на вашем компьютере или телефоне.</p> +</div> + +<p>Эта теория не так важна для написания веб-кода в краткосрочной перспективе, но в скором времени вы действительно начнете извлекать выгоду из понимания того, что происходит в фоновом режиме.</p> + +<h2 id="Клиенты_и_серверы">Клиенты и серверы</h2> + +<p>Компьютеры, подключенные к сети называются клиентами и серверами. Упрощенная схема того, как они взаимодействуют, может выглядеть следующим образом:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8973/Client-server.jpg" style="height: 123px; width: 336px;"></p> + +<ul> + <li>Клиенты являются обычными пользователями, подключенными к Интернету посредством устройств (например, компьютер подключен к Wi-Fi, или ваш телефон подключен к мобильной сети) и программного обеспечения, доступного на этих устройствах (как правило, браузер, например, Firefox или Chrome).</li> + <li>Серверы - это компьютеры, которые хранят веб-страницы, сайты или приложения. Когда клиентское устройство пытается получить доступ к веб-странице, копия страницы загружается с сервера на клиентский компьютер для отображения в браузере пользователя.</li> +</ul> + +<h2 id="Остальные_части_панели_инструментов">Остальные части панели инструментов</h2> + +<p>Клиент и сервер, о которых мы рассказали выше, не раскрывают всю суть. Есть много других компонентов, и мы опишем их ниже.</p> + +<p>А сейчас давайте представим, что Веб - это дорога. Одна сторона дороги является клиентом, который представляет собой ваш дом. Другая сторона дороги является сервером, который представляет собой магазин. Вы хотите что-то купить в нём.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9749/road.jpg" style="display: block; height: 427px; margin: 0px auto; width: 640px;"></p> + +<p>Помимо клиента и сервера, мы также должны уделить внимание:</p> + +<ul> + <li><strong>Ваше Интернет-подключение</strong>: Позволяет отправлять и принимать данные по сети. Оно подобно улице между домом и магазином.</li> + <li><strong>TCP/IP</strong>: Протокол Управления Передачей и Интернет Протокол являются коммуникационными протоколами, которые определяют, каким образом данные должны передаваться по сети. Они как транспортные средства, которые позволяют сделать заказ, пойти в магазин и купить ваши товары. В нашем примере, это как автомобиль или велосипед (или собственные ноги).</li> + <li><strong>DNS</strong>: Система Доменных Имён напоминает записную книжку для веб-сайтов. Когда вы вводите веб-адрес в своем браузере, браузер обращается к DNS, чтобы найти реальный адрес веб-сайта, прежде чем он сможет его получить. Браузеру необходимо выяснить, на каком сервере живет сайт, поэтому он может отправлять HTTP-сообщения в нужное место (см. Ниже). Это похоже на поиск адреса магазина, чтобы вы могли попасть в него.</li> + <li><strong>HTTP</strong>: Протокол Передачи Гипертекста - это {{Glossary("Protocol", "протокол")}}, который определяет язык для клиентов и серверов, чтобы общаться друг с другом. Он, как язык, который вы используете, чтобы заказать ваш товар.</li> + <li><strong>Файлы компонентов</strong>: сайт состоит из нескольких различных файлов, которые подобны различным отделам с товарами в магазине. Эти файлы бывают двух основных типов: + <ul> + <li><strong>Файлы кода</strong>: сайты построены преимущественно на HTML, CSS и JavaScript, хотя вы познакомитесь с другими технологиями чуть позже.</li> + <li><strong>Материалы</strong>: это собирательное название для всех других вещей, составляющих сайт, такие как изображения, музыка, видео, документы Word и PDF.</li> + </ul> + </li> +</ul> + +<h2 id="Что_же_на_самом_деле_происходит">Что же на самом деле происходит?</h2> + +<p>Когда вы вводите веб-адрес в свой браузер (для нашей аналогии - посещаете магазин):</p> + +<ol> + <li>Браузер обращается к DNS серверу и находит реальный адрес сервера, на котором "живет" сайт (Вы находите адрес магазина).</li> + <li>Браузер посылает HTTP запрос к серверу, запрашивая его отправить копию сайта для клиента (Вы идёте в магазин и заказываете товар). Это сообщение и все остальные данные, передаваемые между клиентом и сервером, передаются по интернет-соединению с использованием протокола TCP/IP.</li> + <li>Если сервер одобряет запрос клиента, сервер отправляет клиенту статус "200 ОК", который означает: "Конечно, вы можете посмотреть на этот сайт! Вот он", а затем начинает отправку файлов сайта в браузер в виде небольших порций, называемых пакетными данными (магазин выдает вам ваш товар или вам привозят его домой).</li> + <li>Браузер собирает маленькие куски в полноценный сайт и показывает его вам (товар прибывает к вашей двери — новые вещи, потрясающе!).</li> +</ol> + +<h2 id="DNS">DNS</h2> + +<p>Реальные веб-адреса - неудобные, незапоминающиеся строки, которые Вы вводите в адресную строку, чтобы найти ваши любимые веб-сайты. Эти строки состоят из чисел, например: <code>63.245.215.20</code>.</p> + +<p>Такой набор чисел называется {{Glossary("IP Address", "IP-адресом")}} и представляет собой уникальное местоположение в Интернете. Впрочем, его не очень легко запомнить, правда? Вот почему изобрели DNS. Это специальные сервера, которые связывают веб-адрес, который вы вводите в браузере (например, "mozilla.org"), с реальным IP-адресом сайта.</p> + +<p>Сайты можно найти непосредственно через их IP-адреса. Вы можете найти IP-адрес веб-сайта, введя его домен в инструмент, как <a href="https://ipinfo.info/html/ip_checker.php">IP Checker</a>.</p> + +<h2 id="Пакеты">Пакеты</h2> + +<p>Ранее мы использовали термин "пакеты", чтобы описать формат, в котором данные передаются от сервера к клиенту. Что мы имеем в виду? В основном, когда данные передаются через Интернет, они отправляются в виде тысячи мелких кусочков, так что множество разных пользователей могут скачивать один и тот же сайт одовременно. Если бы сайты отправлялись одним большим куском, тогда бы только один пользователь мог скачать его за один раз, и это, очевидно, сделало бы пользование интернетом не эффективным и не очень радостным.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="/ru/Learn/How_the_Internet_works">Как работает Интернет</a></li> + <li><a href="https://dev.opera.com/articles/http-basic-introduction/">HTTP — Протокол уровня приложений</a></li> + <li><a href="https://dev.opera.com/articles/http-lets-get-it-on/">HTTP: Давайте изучим его!</a></li> + <li><a href="https://dev.opera.com/articles/http-response-codes/">HTTP: Коды ответов</a></li> +</ul> + +<h2 id="Благодарность">Благодарность</h2> + +<p>Фото улицы: <a href="https://www.flickr.com/photos/kdigga/9110990882/in/photolist-cXrKFs-c1j6hQ-mKrPUT-oRTUK4-7jSQQq-eT7daG-cZEZrh-5xT9L6-bUnkip-9jAbvr-5hVkHn-pMfobT-dm8JuZ-gjwYYM-pREaSM-822JRW-5hhMf9-9RVQNn-bnDMSZ-pL2z3y-k7FRM4-pzd8Y7-822upY-8bFN4Y-kedD87-pzaATg-nrF8ft-5anP2x-mpVky9-ceKc9W-dG75mD-pY62sp-gZmXVZ-7vVJL9-h7r9AQ-gagPYh-jvo5aM-J32rC-ibP2zY-a4JBcH-ndxM5Y-iFHsde-dtJ15p-8nYRgp-93uCB1-o6N5Bh-nBPUny-dNJ66P-9XWmVP-efXhxJ">Street composing</a>, <a href="https://www.flickr.com/photos/kdigga/">Kevin D</a>.</p> + +<p>{{PreviousMenu("Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового программного обеспечения</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего веб-сайта</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Веб</a></li> +</ul> diff --git a/files/ru/learn/getting_started_with_the_web/html_basics/index.html b/files/ru/learn/getting_started_with_the_web/html_basics/index.html new file mode 100644 index 0000000000..ecfa21217d --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/html_basics/index.html @@ -0,0 +1,229 @@ +--- +title: Основы HTML +slug: Learn/Getting_started_with_the_web/HTML_basics +tags: + - HTML + - Web + - Новичку + - Обучение +translation_of: Learn/Getting_started_with_the_web/HTML_basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p>HTML (Hypertext Markup Language) - это код, который используется для структурирования и отображения веб-страницы и её контента. Например, контент может быть структурирован внутри множества параграфов, маркированных списков или с использованием изображений и таблиц данных. Как видно из названия, эта статья даст вам базовое понимание HTML и его функций.</p> +</div> + +<h2 id="Что_такое_HTML_на_самом_деле">Что такое HTML на самом деле?</h2> + +<p>HTML не является языком программирования; это <em>язык разметки</em>, и используется, чтобы сообщать вашему браузеру, как отображать веб-страницы, которые вы посещаете. Он может быть сложным или простым, в зависимости от того, как хочет веб-дизайнер. HTML состоит из ряда <strong>{{Glossary("element", "элементов")}}</strong>, которые вы используете, чтобы вкладывать или оборачивать различные части контента, чтобы заставить контент отображаться или действовать определенным образом. Ограждающие {{Glossary("tag", "теги")}} могут сделать слово или изображение ссылкой на что-то еще, могут сделать слова курсивом, сделать шрифт больше или меньше и так далее. Например, возьмем следующую строку контента:</p> + +<pre class="notranslate">Моя кошка очень раздражена</pre> + +<p>Если бы мы хотели, чтобы строка стояла сама по себе, мы могли бы указать, что это абзац, заключая его в теги абзаца:</p> + +<pre class="brush: html notranslate"><p>Моя кошка очень раздражена</p></pre> + +<h3 id="Анатомия_HTML_элемента">Анатомия HTML элемента</h3> + +<p>Давайте рассмотрим элемент абзаца более подробно.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9347/grumpy-cat-small.png" style="display: block; height: 255px; margin: 0px auto; width: 821px;"></p> + +<p>Главными частями нашего элемента являются:</p> + +<ol> + <li><strong>Открывающий тег (Opening tag)</strong>: Состоит из имени элемента (в данном случае, "p"), заключенного в открывающие и закрывающие <strong>угловые скобки</strong>. Открывающий тег указывает, где элемент начинается или начинает действовать, в данном случае — где начинается абзац.</li> + <li><strong>Закрывающий тег (Closing tag):</strong> Это то же самое, что и открывающий тег, за исключением того, что он включает в себя косую черту перед именем элемента. Закрывающий элемент указывает, где элемент заканчивается, в данном случае — где заканчивается абзац. Отсутствие закрывающего тега является одной из наиболее распространенных ошибок начинающих и может приводить к странным результатам.</li> + <li><strong>Контент (Content)</strong>: Это контент элемента, который в данном случае является просто текстом.</li> + <li><strong>Элемент(Element)</strong>: Открывающий тег, закрывающий тег и контент вместе составляют элемент.</li> +</ol> + +<p>Элементы также могут иметь атрибуты, которые выглядят так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9345/grumpy-cat-attribute-small.png" style="display: block; height: 156px; margin: 0px auto; width: 1287px;"></p> + +<p>Атрибуты содержат дополнительную информацию об элементе, которую вы не хотите показывать в фактическом контенте. В данном случае, <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">class</span></font> это <em>имя</em> <em>атрибута,</em> а <code>editor-note</code> это <em>значение атрибута</em>. Класс позволяет дать элементу идентификационное имя, которое может позже использоваться, чтобы обращаться к элементу с информацией о стиле и прочих вещах.</p> + +<p>Атрибут всегда должен иметь:</p> + +<ol> + <li>Пробел между ним и именем элемента (или предыдущим атрибутом, если элемент уже имеет один или несколько атрибутов).</li> + <li>Имя атрибута, за которым следует знак равенства.</li> + <li>Значение атрибута, заключенное с двух сторон в кавычки.</li> +</ol> + +<h3 id="Вложенные_элементы">Вложенные элементы</h3> + +<p>Вы также можете располагать элементы внутри других элементов — это называется <strong>вложением</strong>. Если мы хотим заявить, что наша кошка <strong>очень</strong> раздражена, мы можем заключить слово "очень" в элемент {{htmlelement("strong")}} , который указывает, что слово должно быть сильно акцентированно:</p> + +<pre class="brush: html notranslate"><p>Моя кошка <strong>очень</strong> раздражена.</p></pre> + +<p>Вы, однако, должны убедиться, что ваши элементы правильно вложены: в примере выше мы открыли первым элемент {{htmlelement("p")}}, затем элемент {{htmlelement("strong")}}, потом мы должны закрыть сначала элемент {{htmlelement("strong")}}, затем {{htmlelement("p")}}. Приведенное ниже неверно:</p> + +<pre class="example-bad brush: html notranslate"><p>Моя кошка <strong>очень раздражена.</p></strong></pre> + +<p>Элементы должны открываться и закрываться правильно, поэтому они явно располагаются внутри или снаружи друг друга. Если они перекрываются, как в примере выше, ваш веб-браузер будет пытаться сделать наилучшее предположение на основе того, что вы пытались сказать, что может привести к неожиданным результатам. Так что не стоит этого делать!</p> + +<h3 id="Пустые_элементы">Пустые элементы</h3> + +<p>Некоторые элементы не имеют контента, и называются <strong>пустыми элементами</strong>. Возьмем элемент {{htmlelement("img")}}, который уже имеется в нашем HTML:</p> + +<pre class="brush: html notranslate"><img src="images/firefox-icon.png" alt="Моё тестовое изображение"></pre> + +<p>Он содержит два атрибута, но не имеет закрывающего тега <code></img></code>, и никакого внутреннего контента. Это потому, что элемент изображения не оборачивает контент для влияния на него. Его целью является вставка изображения в HTML страницу в нужном месте.</p> + +<h3 id="Анатомия_HTML_документа">Анатомия HTML документа</h3> + +<p>Мы завершили изучение основ отдельных HTML элементов, но они не очень полезны сами по себе. Теперь мы посмотрим, как отдельные элементы объединяются в целую HTML страницу. Давайте вернемся к коду, который мы записывали в наш <code>index.html</code> (с которым мы впервые встретились в статье <a href="/ru/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a>):</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Моя тестовая страница</title> + </head> + <body> + <img src="images/firefox-icon.png" alt="Моё тестовое изображение"> + </body> +</html></pre> + +<p>Здесь мы имеем:</p> + +<ul> + <li><code><!DOCTYPE html></code> — доктайп. В прошлом, когда HTML был молод (около 1991/1992), доктайпы должны были выступать в качестве ссылки на набор правил, которым HTML страница должна была следовать, чтобы считаться хорошим HTML, что могло означать автоматическую проверку ошибок и другие полезные вещи. Однако в наши дни, никто не заботится об этом, и они на самом деле просто исторический артефакт, который должен быть включен для того, что бы все работало правильно. На данный момент это все, что вам нужно знать.</li> + <li><code><html></html></code> — элемент {{htmlelement("html")}}. Этот элемент оборачивает весь контент на всей странице, и иногда известен как корневой элемент.</li> + <li><code><head></head></code> — элемент {{htmlelement("head")}}. Этот элемент выступает в качестве контейнера для всего, что вы пожелаете включить на HTML страницу, но<em> не являющегося </em>контентом, который вы показываете пользователям вашей страницы. К ним относятся такие вещи, как ключевые слова и описание страницы, которые будут появляться в результатах поиска, CSS стили нашего контента, кодировка и многое другое.</li> + <li><code><body></body></code> — элемент {{htmlelement("body")}}. В нем содержится <em>весь</em> контент, который вы хотите показывать пользователям, когда они посещают вашу страницу, будь то текст, изображения, видео, игры, проигрываемые аудиодорожки или что-то еще.</li> + <li><code><meta charset="utf-8"></code> — этот элемент устанавливает UTF-8 кодировку вашего документа, которая включает в себя большинство символов из всех известных человечеству языков. По сути, теперь документ может обрабатывать любой текстовый контент, который вы в него вложите. Нет причин не устанавливать её, так как это может помочь избежать некоторых проблем в дальнейшем.</li> + <li><code><title></title></code> — элемент {{htmlelement("title")}}. Этот элемент устанавливает заголовок для вашей страницы, который является названием, появляющимся на вкладке браузера загружаемой страницы, и используется для описания страницы, когда вы добавляете ее в закладки/избранное.</li> +</ul> + +<h2 id="Изображения">Изображения</h2> + +<p>Давайте снова обратим наше внимание на элемент {{htmlelement("img", "изображения")}}:</p> + +<pre class="brush: html notranslate"><img src="images/firefox-icon.png" alt="Mоё тестовое изображение"></pre> + +<p>Как было сказано раньше, код встраивает изображение на нашу страницу в нужном месте. Это делается с помощью атрибута <code>src</code> (source, источник), который содержит путь к нашему файлу изображения.</p> + +<p>Мы также включили атрибут <code>alt</code> (alternative, альтернатива). В этом атрибуте, вы указываете поясняющий текст для пользователей, которые не могут увидеть изображение, возможно, по следующим причинам:</p> + +<ol> + <li>У них присутствуют нарушения зрения. Пользователи со значительным нарушением зрения часто используют инструменты, называемые Screen Readers (экранные дикторы), которые читают для них альтернативный текст.</li> + <li>Что-то пошло не так, в результате чего изображение не отобразилось. Например, попробуйте намеренно изменить путь в вашем атрибуте <code>src</code>, сделав его неверным. Если вы сохраните и перезагрузите страницу, то вы должны увидеть что-то подобное вместо изображения:</li> +</ol> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9349/alt-text-example.png" style="display: block; height: 36px; margin: 0px auto; width: 108px;"></p> + +<p>Альтернативный текст - это "пояснительный текст". Он должен предоставить читателю достаточно информации, чтобы иметь представление о том, что передает изображение. В этом примере наш текст "My test image" ("Моё тестовое изображение") не годится. Намного лучшей альтернативой для нашего логотипа Firefox будет "The Firefox logo: a flaming fox surrounding the Earth" ("Логотип Firefox: огненный Лис вокруг Земли").</p> + +<p>Сейчас попробуйте придумать более подходящий альтернативный текст для вашего изображения.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Узнайте больше о <a href="/ru/docs/Web/Accessibility">специальных возможностях</a>.</p> +</div> + +<h2 id="Разметка_текста">Разметка текста</h2> + +<p>В этом разделе рассмотрим некоторые из основных HTML элементов, которые вы будете использовать для разметки текста.</p> + +<h3 id="Заголовки">Заголовки</h3> + +<p>Элементы заголовка позволяют вам указывать определенные части вашего контента в качестве заголовков или подзаголовков. Точно так же, как книга имеет название, названия глав и подзаголовков, HTML документ может содержать то же самое. HTML включает шесть уровней заголовков {{htmlelement("h1")}}–{{htmlelement("h6")}}, хотя обычно вы будете использовать не более 3-4 :</p> + +<pre class="brush: html notranslate"><h1>Мой главный заголовок</h1> +<h2>Мой заголовок верхнего уровня</h2> +<h3>Мой подзаголовок</h3> +<h4>Мой под-подзаголовок</h4></pre> + +<p>Теперь попробуйте добавить подходящее название для вашей HTML страницы, чуть выше элемента {{htmlelement("img")}}.</p> + +<h3 id="Абзацы">Абзацы</h3> + +<p>Как было сказано раньше, элемент {{htmlelement("p")}} предназначен для абзацев текста; вы будете использовать их регулярно при разметке текстового контента:</p> + +<pre class="brush: html notranslate"><p>Это одиночный абзац</p></pre> + +<p>Добавьте свой образец текста (вы создавали его в статье <a href="/ru/Learn/Getting_started_with_the_web/What_should_your_web_site_be_like"><em>Каким должен быть ваш веб-сайт?</em></a>) в один или несколько абзацев, расположенных прямо под элементом {{htmlelement("img")}}.</p> + +<h3 id="Списки">Списки</h3> + +<p>Большая часть веб-контента является списками и HTML имеет специальные элементы для них. Разметка списка всегда состоит по меньшей мере из двух элементов. Наиболее распространенными типами списков являются нумерованные и ненумерованные списки:</p> + +<ol> + <li><strong>Ненумерованные списки</strong> - это списки, где порядок пунктов не имеет значения, как в списке покупок. Они оборачиваются в элемент {{htmlelement("ul")}}.</li> + <li><strong>Нумерованные списки -</strong> это списки, где порядок пунктов имеет значение, как в рецепте. Они оборачиваются в элемент {{htmlelement("ol")}}.</li> +</ol> + +<p>Каждый пункт внутри списков располагается внутри элемента {{htmlelement("li")}} (list item, элемент списка).</p> + +<p>Например, если мы хотим включить часть следующего фрагмента абзаца в список:</p> + +<pre class="brush: html notranslate"><p>Mozilla, мы являемся мировым сообществом технологов, мыслителей и строителей, работающих вместе ... </p></pre> + +<p>Мы могли бы изменить разметку на эту:</p> + +<pre class="brush: html notranslate"><p>Mozilla, мы являемся мировым сообществом</p> + +<ul> + <li>технологов</li> + <li>мыслителей</li> + <li>строителей</li> +</ul> + +<p>работающих вместе ... </p></pre> + +<p>Попробуйте добавить упорядоченный или неупорядоченный список на свою страницу.</p> + +<h2 id="Ссылки">Ссылки</h2> + +<p>Ссылки очень важны — это то, что делает Интернет Интернетом. Чтобы добавить ссылку, нам нужно использовать простой элемент — {{htmlelement("a")}} — <em>a</em> это сокращение от "anchor" ("якорь"). Чтобы текст в вашем абзаце стал ссылкой, выполните следующие действия:</p> + +<ol> + <li>Выберите некоторый текст. Мы выбрали текст "Манифест Mozilla".</li> + <li>Оберните текст в элемент {{htmlelement("a")}}, например так: + <pre class="brush: html notranslate"><a>Манифест Mozilla</a></pre> + </li> + <li>Задайте элементу {{htmlelement("a")}} атрибут<strong> </strong><font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">href</span></font>, например так: + <pre class="brush: html notranslate"><a href="">Манифест Mozilla</a></pre> + </li> + <li>Заполните значение этого атрибута веб-адресом, на который вы хотите указать ссылку: + <pre class="brush: html notranslate"><a href="https://www.mozilla.org/ru/about/manifesto/details/">Манифест Mozilla</a></pre> + </li> +</ol> + +<p>Вы можете получить неожиданные результаты, если в самом начале веб-адреса вы опустите <code>https://</code> или <code>http://</code> часть, называемую <em>протоколом</em>. После создания ссылки, кликните по ней, чтобы убедиться, что она направляет вас туда, куда вы хотели.</p> + +<div class="note"> +<p><code>href</code> сначала может выглядеть довольно непонятым выбором для имени атрибута. Если у вас возникли проблемы с тем, чтобы запомнить его, можете запомнить, что атрибут href образуется как <em><strong>h</strong>ypertext <strong>ref</strong>erence </em>("гипертекстовая ссылка").</p> +</div> + +<p>Теперь добавьте ссылку на вашу страницу, если вы еще не сделали этого.</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Если вы следовали всем инструкциям в этой статье, то вы должны увидеть в конечном итоге страницу, аналогичную рисунку ниже (вы также можете <a href="http://mdn.github.io/beginner-html-site/">посмотреть ее здесь</a>):<br> + <br> + <img alt="A web page screenshot showing a firefox logo, a heading saying mozilla is cool, and two paragraphs of filler text" src="https://mdn.mozillademos.org/files/9351/finished-test-page-small.png" style="display: block; height: 838px; margin: 0px auto; width: 716px;"></p> + +<p>Если вы застряли, вы всегда можете сравнить свою работу с нашим <a href="https://github.com/mdn/beginner-html-site/blob/gh-pages/index.html">готовым примером кода</a> на GitHub.</p> + +<p>Здесь вы узнали только самую поверхность HTML. Чтобы узнать больше, перейдите на страницу <a href="/ru/Learn/HTML">Обучение HTML: руководства и уроки</a>.</p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового программного обеспечения</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего веб-сайта</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Веб</a></li> +</ul> diff --git a/files/ru/learn/getting_started_with_the_web/index.html b/files/ru/learn/getting_started_with_the_web/index.html new file mode 100644 index 0000000000..8500828b35 --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/index.html @@ -0,0 +1,69 @@ +--- +title: Начало работы с Вебом +slug: Learn/Getting_started_with_the_web +tags: + - Beginner + - CSS + - Design + - Guide + - HTML + - Index + - TopicStub + - publishing + - theory + - Новичку + - Обучающая зона + - Обучение + - Руководство +translation_of: Learn/Getting_started_with_the_web +--- +<div>{{LearnSidebar}}</div> + +<div class="summary"> +<p><em>Начало работы с Вебом</em> - это серия коротких уроков, которые познакомят вас с практическими аспектами веб-разработки. Вы настроите инструменты, необходимые для создания простой веб-страницы и публикации своего собственного кода.</p> +</div> + +<h2 id="История_вашего_первого_веб-сайта">История вашего первого веб-сайта</h2> + +<p>Необходимо много работать, чтобы создать профессиональный веб-сайт, так что, если вы новичок в веб-разработке, мы рекомендуем начать с малого. Вы не будете создавать еще один Facebook прямо сейчас, но создать свой простой веб-сайт не так уж и сложно, так что мы начнем с этого.</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Прорабатывая статьи</span></span>, перечисленные ниже по порядку, вы пройдете путь от нуля до создания своей первой веб-страницы. Ну что, давайте начнем!</p> + +<h3 id="Установка_базового_программного_обеспечения"><a href="/ru/docs/Learn/Getting_started_with_the_web/Установка_базового_программного_обеспечения">Установка базового программного обеспечения</a></h3> + +<p>Когда речь заходит об инструментаx для создания веб-сайта, тут есть из чего выбрать. Если вы только начинаете, вас может смутить количество текстовых редакторов, фреймворков и инструментов тестирования. В главе <a href="/ru/docs/Learn/Getting_started_with_the_web/Установка_базового_программного_обеспечения">Установка базового программного обеспечения</a> мы покажем вам шаг за шагом, как установить только то программное обеспечение, которое вам понадобится для веб-разработки на начальном этапе.</p> + +<h3 id="Каким_должен_быть_ваш_веб-сайт"><a href="/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a></h3> + +<p>Перед тем, как вы начнете писать код для вашего веб-сайта, нужно составить план. Какую информацию вы демонстрируете? Какие шрифты и цвета вы используете? <a href="/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a> Мы опишем простой метод, которому вы сможете следовать, чтобы спланировать содержание и дизайн вашего сайта.</p> + +<h3 id="Работа_с_файлами"><a href="/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a></h3> + +<p>Веб-сайт состоит из множества файлов: текстового содержания, кода, таблиц стилей, медиа-контента, и так далее. Когда вы создаете веб-сайт, вам нужно собрать эти файлы в разумную структуру и убедиться, что они могут взаимодействовать друг с другом. <a href="/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a> объясняет, как создать разумную файловую структуру для вашего веб-сайта и про какие проблемы вы должны знать.</p> + +<h3 id="Основы_HTML"><a href="/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a></h3> + +<p>Язык гипертекстовой разметки (Hypertext Markup Language, HTML) - это код, который вы используете для структурирования веб-содержимого и придания ему смысла и цели. Например, является ли мое содержимое набором абзацев, либо списком маркированных пунктов? Нужно ли вставить изображения на мою страницу? Есть ли у меня таблица данных? Не перегружая вас, статья <a href="/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a> предоставляет достаточно информации для вашего знакомства с HTML.</p> + +<h3 id="Основы_CSS"><a href="/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a></h3> + +<p>Каскадные таблицы стилей (Cascading Stylesheets, CSS) - это код, который вы используете для стилизации своего веб-сайта. Например, хотите ли вы, чтобы текст был черным или красным? Где должно быть нарисовано содержимое на экране? Какие фоновые изображения и цвета должны быть использованы, чтобы украсить ваш веб-сайт? <a href="/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a> проведет вас через то, что вам нужно знать, чтобы начать.</p> + +<h3 id="Основы_JavaScript"><a href="/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a></h3> + +<p>JavaScript - это язык программирования, который вы используете для добавления интерактивных функций для вашего веб-сайта, например, игр, событий, которые происходят при нажатии кнопок или ввода данных в формы, динамических эффектов стилизации, анимации и многого другого. <a href="/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a> дает вам представление о том, что можно сделать с помощью этого захватывающего языка, и как начать.</p> + +<h3 id="Публикация_вашего_веб-сайта"><a href="/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего веб-сайта</a></h3> + +<p>После того как вы закончили писать код и организовали файлы, которые составляют ваш веб-сайт, нужно разместить все это в Интернете так, чтобы люди могли его найти. <a href="/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего сайта</a> описывает, как отобразить ваш простой пример кода в Интернете с минимальными усилиями.</p> + +<h3 id="Как_работает_Интернет"><a href="/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Интернет</a></h3> + +<p>Когда вы заходите на свой любимый веб-сайт, в фоновом режиме происходит много сложных вещей, о которых вы можете не знать. Статья <a href="/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Интернет</a> описывает, что происходит, когда вы просматриваете веб-страницы на своем компьютере.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://www.youtube.com/playlist?list=PLo3w8EB99pqLEopnunz-dOOBJ8t-Wgt2g">Web Demystified</a>(web обзор): большая серия видеороликов, объясняющая основы web, нацеленных на начинающих веб-разработчиков. Создано <a href="https://twitter.com/JeremiePat">Жереми Патонье</a>.</li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/The_web_and_web_standards">The web and web standards</a> (веб и веб стандарты): В этой статье приведена полезная информация о Вебе — как он появился, что такое технологии веб-стандартов, как они работают вместе, почему "веб-разработчик" - это отличная карьера, <span class="tlid-translation translation" lang="ru"><span title="">и какие виды наилучшей практики вы узнаете в ходе курса.</span></span></li> +</ul> diff --git a/files/ru/learn/getting_started_with_the_web/javascript_basics/index.html b/files/ru/learn/getting_started_with_the_web/javascript_basics/index.html new file mode 100644 index 0000000000..5cdf99a8da --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/javascript_basics/index.html @@ -0,0 +1,413 @@ +--- +title: Основы JavaScript +slug: Learn/Getting_started_with_the_web/JavaScript_basics +tags: + - Beginner + - CodingScripting + - JavaScript + - Learn + - Новичку + - Обучение +translation_of: Learn/Getting_started_with_the_web/JavaScript_basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p>JavaScript – это язык программирования, который добавляет интерактивность на ваш веб-сайт (например: игры, отклик при нажатии кнопок или при вводе данных в формы, динамические стили, анимация). Эта статья поможет вам начать работать с этим захватывающим языком и даст вам представление о том, на что он способен.</p> +</div> + +<h2 id="Что_такое_JavaScript_на_самом_деле">Что такое JavaScript на самом деле?</h2> + +<p>{{Glossary("JavaScript")}} ("JS" для краткости) — это полноценный {{Glossary("Dynamic programming language", "динамический язык программирования")}}, который применяется к {{Glossary("HTML")}} документу, и может обеспечить динамическую интерактивность на веб-сайтах. Его разработал Brendan Eich, сооснователь проекта Mozilla, Mozilla Foundation и Mozilla Corporation.</p> + +<p>JavaScript невероятно универсален и дружелюбен к новичкам. Обладая большим опытом, вы сможете создавать игры, анимированную 2D и 3D графику, полномасштабные приложения с базами данных и многое другое!</p> + +<p>JavaScript сам по себе довольно компактный, но очень гибкий. Разработчиками написано большое количество инструментов поверх основного языка JavaScript, которые разблокируют огромное количество дополнительных функций с очень небольшим усилием. К ним относятся:</p> + +<ul> + <li>Программные интерфейсы приложения ({{Glossary("API","API")}}), встроенные в браузеры, обеспечивающие различные функциональные возможности, такие как динамическое создание HTML и установку CSS стилей, захват и манипуляция видеопотоком, работа с веб-камерой пользователя или генерация 3D графики и аудио сэмплов.</li> + <li>Сторонние API позволяют разработчикам внедрять функциональность в свои сайты от других разработчиков, таких как Twitter или Facebook.</li> + <li>Также вы можете применить к вашему HTML сторонние фреймворки и библиотеки, что позволит вам ускорить создание сайтов и приложений.</li> +</ul> + +<p>Поскольку эта статья должна быть только лёгким введением в JavaScript, мы не собираемся путать вас на этом этапе, подробно рассказывая о том, какая разница между основным языком JavaScript и различными инструментами, перечисленными выше. Вы можете подробно изучить все это позже, в нашей <a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript">учебной области JavaScript </a> и в остальной части MDN. </p> + +<p>Ниже мы познакомим вас с некоторыми аспектами основного языка, и вы также будете играть с несколькими функциями API браузера. Веселитесь!</p> + +<h2 id="Пример_hello_world">Пример "hello world"</h2> + +<p>Предыдущий раздел звучит очень многообещающе, и это на самом деле так — JavaScript является одной из самых перспективных веб-технологий, и когда вы освоитесь и начнёте использовать его, ваши веб-сайты перейдут в новое измерение мощи и креативности.</p> + +<p>Тем не менее, с JavaScript немного более сложно освоиться, чем с HTML и CSS. Вам придется начать с малого, продолжая изучение небольшими шагами. Для начала мы покажем вам, как добавить некоторые основы JavaScript на вашу страницу, чтобы создать "hello world!" пример (<a href="https://ru.wikipedia.org/wiki/Hello,_world!">стандарт в начальных примерах программирования</a>).</p> + +<div class="warning"> +<p><strong>Важно</strong>: Если вы не следили за остальным нашим курсом, <a href="https://github.com/mdn/beginner-html-site-styled/archive/gh-pages.zip">скачайте этот пример кода</a> и используйте его в качестве стартовой точки.</p> +</div> + +<ol> + <li>Для начала перейдите на ваш тестовый сайт и создайте папку с именем 'scripts' (без кавычек). Затем, в новой папке скриптов, которую вы только что создали, создайте новый файл с именем <code>main.js</code>. Сохраните его в вашей папке <code>scripts</code>.</li> + <li>Далее перейдите в ваш <code>index.html</code> файл и введите следующий элемент на новой строке прямо перед закрывающим тегом <code></body></code>: + <pre class="brush: html notranslate"><script src="scripts/main.js"></script></pre> + </li> + <li> В основном этот код выполняет ту же работу, что и элемент {{htmlelement("link")}} для CSS — добавляет JavaScript на страницу, позволяя ему взаимодействовать с HTML (и CSS, и чем-нибудь ещё на странице).</li> + <li>Теперь добавьте следующий код в файл <code>main.js</code>: + <pre class="brush: js notranslate">var myHeading = document.querySelector('h1'); +myHeading.textContent = 'Hello world!';</pre> + </li> + <li>Теперь убедитесь, что HTML и JavaScript файлы сохранены, и загрузите <code>index.html</code> в браузере. Вы должны увидеть что-то вроде этого: <img alt="" src="https://mdn.mozillademos.org/files/9543/hello-world.png" style="display: block; height: 236px; margin: 0px auto; width: 806px;"></li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Причиной, по которой мы поставили элемент {{htmlelement("script")}} в нижней части HTML файла, является то, что HTML-элементы загружаются браузером в том порядке, в котором они расположены в файле. Поэтому, если JavaScript загружается первым и ему нужно взаимодействовать с HTML ниже его, он не сможет работать, так как JavaScript будет загружен раньше, чем HTML, с которым нужно работать. Поэтому, располагать JavaScript в нижней части HTML страницы считается лучшей стратегией.</p> +</div> + +<h3 id="Что_произошло">Что произошло?</h3> + +<p>Итак, ваш заголовок текста был изменен на "Hello world!" с помощью JavaScript. Мы сделали это с помощью вызова функции {{domxref("Document.querySelector", "querySelector()")}}, захватив ссылку на наш заголовок и сохранив её в переменной, названной <code>myHeading</code>. Это очень похоже на то, что мы делали в CSS с помощью селекторов. Если вы хотите что-то сделать с элементом, то для начала вам нужно его выбрать.</p> + +<p>После этого, вы устанавливаете значение переменной <code>myHeading</code> в {{domxref("Node.textContent", "textContent")}} свойство (которое представляет собой контент заголовка) "Hello world!".</p> + +<h2 id="Ускоренный_курс_по_основам_языка">Ускоренный курс по основам языка</h2> + +<p>Давайте познакомимся с некоторыми основными возможностями языка JavaScript, чтобы дать вам больше понимания, как это всё работает. Более того, эти возможности являются общими для всех языков программирования. Если вы сможете понять эти основы, вы будете в состоянии начать программировать, как ни в чём не бывало!</p> + +<div class="warning"> +<p><strong>Важно</strong>: В этой статье попробуйте вводить примеры строк кода в вашей JavaScript консоли, чтобы увидеть, что происходит. Для более подробной информации о JavaScript консоли смотрите статью <a href="/ru/Learn/Discover_browser_developer_tools">Откройте для себя браузерные инструменты разработчика</a>.</p> +</div> + +<h3 id="Переменные">Переменные</h3> + +<p>{{Glossary("Variable", "Переменные")}} — это контейнеры, внутри которых вы можете хранить значения. Вы начинаете с того, что объявляете переменную с помощью ключевого слова <code><a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/var">var</a></code> <span class="tlid-translation translation" lang="ru"><span title="">(не рекомендуется, продолжайте читать, чтобы получить объяснения)</span></span> или <code><a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let">let</a></code>, за которым следует любое имя, которым вы захотите её назвать:</p> + +<pre class="brush: js notranslate">let myVariable;</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Точка с запятой в конце строки указывает, где заканчивается оператор; это абсолютно необходимо, когда вам нужно разделить оператора на одной строке. Однако некоторые люди считают, что хорошая практика - указывать их в конце каждого оператора. Существуют и другие правила, когда вы должны и не должны их использовать - смотрите более подробно в статье <a href="http://news.codecademy.com/your-guide-to-semicolons-in-javascript/">ваше руководство по точкам с запятой в JavaScript</a>.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете назвать переменную практически как угодно, но есть некоторые ограничения для её имени (смотрите<a href="http://www.codelifter.com/main/tips/tip_020.shtml"> в правилах именования переменных</a>.) Если вы не уверены, вы можете <a href="https://mothereff.in/js-variables">проверить имя вашей переменной</a>, чтобы увидеть корректно ли оно.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: JavaScript чувствителен к регистру — <code>myVariable</code> отличается от переменной <code>myvariable</code>. Если у вас возникают проблемы в вашем коде, проверьте регистр!</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Примечание: </strong>Для получения более подробной информации о разнице между var и let, смотрите: <a href="https://wiki.developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let">Разница между var и let</a>.</p> +</div> + +<p>После объявления переменной вы можете присвоить ей значение:</p> + +<pre class="brush: js notranslate">myVariable = 'Bob';</pre> + +<p>Вы можете сделать обе эти операции на одной и той же строке, если вы захотите:</p> + +<pre class="brush: js notranslate">var myVariable = 'Bob';</pre> + +<p>Вы можете получить значение, просто вызвав переменную по имени:</p> + +<pre class="brush: js notranslate">myVariable;</pre> + +<p>После установки значения переменной вы можете изменить его позже:</p> + +<pre class="notranslate">var myVariable = 'Bob'; +myVariable = 'Steve';</pre> + +<p>Обратите внимание, что переменные имеют разные <a href="/ru/docs/Web/JavaScript/Data_structures">типы данных</a>:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="row">Переменная</th> + <th scope="col">Пояснение</th> + <th scope="col">Пример</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">{{Glossary("String")}}</th> + <td>Последовательность текста, называемая строкой. Чтобы указать, что это значение является строкой, вы должны заключить его в кавычки.</td> + <td><code>var myVariable = 'Bob';</code></td> + </tr> + <tr> + <th scope="row">{{Glossary("Number")}}</th> + <td>Числа. Числа не имеют кавычек вокруг них.</td> + <td><code>var myVariable = 10;</code></td> + </tr> + <tr> + <th scope="row">{{Glossary("Boolean")}}</th> + <td>Значение True(Правда)/False(Ложь). Слова <code>true</code> и <code>false</code> специальные ключевые слова в JS, и не нуждаются в кавычках.</td> + <td><code>var myVariable = true;</code></td> + </tr> + <tr> + <th scope="row">{{Glossary("Array")}}</th> + <td>Массив, который позволяет хранить несколько значений в одной ссылке.</td> + <td><code>var myVariable = [1,'Bob','Steve',10];</code><br> + Обратиться к каждому элементу массива можно так:<br> + <code>myVariable[0]</code>, <code>myVariable[1]</code>, и т.д.</td> + </tr> + <tr> + <th scope="row">{{Glossary("Object")}}</th> + <td>В принципе, что угодно. Все в JavaScript является объектом, и может храниться в переменной. Имейте это в виду, пока вы учитесь.</td> + <td><code>var myVariable = document.querySelector('h1');</code><br> + Все это из вышеприведённых примеров.</td> + </tr> + </tbody> +</table> + +<p>Так для чего нам нужны переменные? Что ж, переменные должны были сделать что-нибудь интересное в программировании. Если значения не могли бы изменяться, то вы не могли бы ничего сделать динамическим, например, персонализировать приветственное сообщение или сменить изображение, отображаемое в галерее изображений.</p> + +<h3 id="Комментарии">Комментарии</h3> + +<p>Комментарии - это, по сути, короткие фрагменты текста, которые могут быть добавлены в код, и которые игнорируются браузером. Вы можете поместить комментарии в JavaScript код, так же как вы делали это в CSS:</p> + +<pre class="brush: js notranslate">/* +Всё, что находится тут - комментарий. +*/</pre> + +<p>Если ваш комментарий не содержит переноса строк, то зачастую легче поставить две косые черты, как тут:</p> + +<pre class="brush: js notranslate" style="font-size: 14px;">// Это комментарий +</pre> + +<h3 id="Операторы">Операторы</h3> + +<p>{{Glossary("operator")}} — это математический символ, который производит результат, основанный на двух значениях (или переменных). В приведенной ниже таблице вы можете увидеть некоторые из наиболее простых операторов, наряду с некоторыми примерами, которые опробуете в JavaScript консоли.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="row">Оператор</th> + <th scope="col">Пояснение</th> + <th scope="col">Символ(ы)</th> + <th scope="col">Пример</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">Сложение (Конкатенация)</th> + <td>Используется для сложения двух чисел или склеивания двух строк вместе.</td> + <td><code>+</code></td> + <td><code>6 + 9;<br> + "Hello " + "world!";</code></td> + </tr> + <tr> + <th scope="row">Вычитание, Умножение, Деление</th> + <td>Они делают то, чего вы от них ожидаете в математике.</td> + <td><code>-</code>, <code>*</code>, <code>/</code></td> + <td><code>9 - 3;<br> + 8 * 2; // умножение в JS это звездочка<br> + 9 / 3;</code></td> + </tr> + <tr> + <th scope="row">Присваивание</th> + <td>Вы уже это видели: он присваивает значение переменной.</td> + <td><code>=</code></td> + <td><code>var myVariable = 'Bob';</code></td> + </tr> + <tr> + <th scope="row">Равенство (Тождество)</th> + <td>Делает проверку, если увидит, что два значения равны друг другу, то возвращает результат <code>true</code>/<code>false</code> (Boolean).</td> + <td><code>===</code></td> + <td><code>var myVariable = 3;<br> + myVariable === 4;</code></td> + </tr> + <tr> + <th scope="row">Отрицание (Неравенство)</th> + <td>Возвращает логически противоположное значение, которое ему предшествует; превращает <code>true</code> в <code>false</code>, и т.д. Когда используется вместе с оператором равенства, оператор отрицания проверяет, являются ли два значения <em>не</em> равными.</td> + <td><code>!</code>, <code>!==</code></td> + <td> + <p>Основное выражение <code>true</code>, но сравнение возвращает <code>false</code>, потому что мы отрицаем его:</p> + + <p><code>var myVariable = 3;<br> + !(myVariable === 3);</code></p> + + <p>Здесь мы проверяем "<code>myVariable</code> НЕ равно 3". Это возвращает <code>false</code>, потому что <code>myVariable</code> равно 3.</p> + + <p><code><code>var myVariable = 3;</code><br> + myVariable !== 3;</code></p> + </td> + </tr> + </tbody> +</table> + +<p>Существует намного больше операторов для изучения, но этих пока хватит. Смотрите их полный список в разделе <a href="/ru/docs/Web/JavaScript/Reference/Operators">выражения и операторы</a>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Смешивание типов данных может привести к некоторым неожиданным результатам при выполнении вычислений, поэтому будьте осторожны, правильно ссылайтесь на ваши переменные, чтобы получать ожидаемые результаты. Например, введите <code>"35" + "25"</code> в вашу консоль. Почему вы не получили результат, который вы ожидали? Потому, что кавычки превратили числа в строки, так что у вас в итоге получилась конкатенация строк, а не сложение чисел. Если вы введёте, <code>35 + 25</code>, то получите правильный результат.</p> +</div> + +<h3 id="Условия">Условия</h3> + +<p>Условия — это кодовые структуры, которые позволяют вам проверять, истинно или ложно выражение, а затем выполнить другой код в зависимости от результата. Самая распространенная форма условия называется, <code>if ... else</code>. Например:</p> + +<pre class="brush: js notranslate">var iceCream = 'chocolate'; +if (iceCream === 'chocolate') { + alert('Yay, I love chocolate ice cream!'); +} else { + alert('Awwww, but chocolate is my favorite...'); +}</pre> + +<p>Выражение внутри <code>if ( ... )</code> — это проверка, которая использует тождественный оператор (как описано выше), чтобы сравнить переменную <code>iceCream</code> со строкой <code>chocolate</code> и увидеть равны ли они. Если это сравнение возвращает <code>true</code>, выполнится первый блок кода. Если нет, этот код пропустится и выполнится второй блок кода, после инструкции <code>else</code>.</p> + +<h3 id="Функции">Функции</h3> + +<p>{{Glossary("Function", "Функции")}} - способ упаковки функциональности, которую вы хотите использовать повторно. Всякий раз, когда вам нужна определенная процедура, вы можете просто вызвать функцию по её имени, а не переписывать весь код каждый раз. Вы уже видели некоторые функции, описанные выше, например:</p> + +<ol> + <li> + <pre class="brush: js notranslate">var myVariable = document.querySelector('h1');</pre> + </li> + <li> + <pre class="brush: js notranslate">alert('hello!');</pre> + </li> +</ol> + +<p>Эти функции, <code>document.querySelector</code> и <code>alert</code>, встроены в браузер для того, чтобы вы использовали их всякий раз, когда вам это необходимо.</p> + +<p>Если вы видите что-то, что выглядит как имя переменной, но имеет после него скобки — <code>()</code>, скорее всего, это функция. Функции часто принимают {{Glossary("Argument", "аргументы")}} — биты данных, которые им необходимы для выполнения своей работы. Они находятся в скобках, и разделяются запятыми, если присутствует более одного аргумента.</p> + +<p>Например, функция <code>alert()</code> вызывает всплывающий блок, появляющийся в окне браузера, но мы должны дать ему строку в качестве аргумента, чтобы сказать функции, что писать во всплывающем блоке.</p> + +<p>Хорошая новость заключается в том, что вы можете определить свои собственные функции — в следующем примере мы напишем простую функцию, которая принимает два числа в качестве аргументов и умножает их:</p> + +<pre class="brush: js notranslate">function multiply(num1,num2) { + var result = num1 * num2; + return result; +}</pre> + +<p>Попробуйте запустить вышеупомянутую функцию в консоли, затем попробуйте изменить аргументы, например:</p> + +<pre class="brush: js notranslate">multiply(4,7); +multiply(20,20); +multiply(0.5,3);</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Инструкция <a href="/ru/docs/Web/JavaScript/Reference/Statements/return"><code>return</code></a> сообщает браузеру, что нужно вернуть переменную <code>result</code> из функции, которую можно будет использовать. Это необходимо потому, что переменные, определенные внутри функций, доступны только внутри этих функций. Это называется {{Glossary("Scope", "областью видимости")}} переменной. (Читайте <a href="/ru/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Variable_scope">больше об области видимости переменных</a>.)</p> +</div> + +<h3 id="События">События</h3> + +<p>Для создания действительной интерактивности на веб-сайте вам необходимы события. События — это структура, которая слушает то, что происходит в браузере, а затем позволяет вам запускать код в ответ на это. Наиболее очевидным является <a href="/ru/docs/Web/Events/click">событие клика</a>, которое вызывается браузером, когда мы щёлкаем по чему-то мышью. Для демонстрации этого события введите следующую команду в вашу консоль, а затем щёлкните по текущей веб-странице:</p> + +<pre class="brush: js notranslate">document.querySelector('html').onclick = function() { + alert('Ouch! Stop poking me!'); +}</pre> + +<p>Существуют множество способов прикрепить событие к элементу. Здесь мы выбираем {{htmlelement("html")}} элемент и устанавливаем ему обработчик свойства <code><a href="/ru/docs/Web/API/GlobalEventHandlers.onclick">onclick</a></code> анонимной функцией (т.е. безымянной) которая содержит код, который мы хотим запустить для события клика.</p> + +<p>Обратите внимание, что</p> + +<pre class="brush: js notranslate">document.querySelector('html').onclick = function() {};</pre> + +<p>эквивалентно</p> + +<pre class="brush: js notranslate">var myHTML = document.querySelector('html'); +myHTML.onclick = function() {};</pre> + +<p>Просто так короче.</p> + +<h2 id="Прокачаем_пример_нашего_веб-сайта">Прокачаем пример нашего веб-сайта</h2> + +<p>Теперь, когда мы прошли некоторые основы JavaScript, давайте добавим несколько крутых несложных функций в пример нашего сайта, чтобы дать вам некоторое представление о принципах работы.</p> + +<h3 id="Добавление_смены_изображения">Добавление смены изображения</h3> + +<p>В этом разделе мы добавим ещё одно изображение на наш сайт и добавим некоторый простой JavaScript для переключения между двумя изображениями, когда по ним щелкнули.</p> + +<ol> + <li>В первую очередь найдите другое изображение, которые вы хотели бы показать на вашем сайте. Убедитесь что оно такого же размера, как ваше первое изображение или максимально близкое к нему.</li> + <li>Сохраните изображение в вашу папку <code>images</code>.</li> + <li>Переименуйте это изображение в 'firefox2.png' (без кавычек).</li> + <li>Перейдите в ваш файл <code>main.js</code> и введите следующий JavaScript. (Если ваш "hello world" JavaScript по-прежнему существует, удалите его.) + <pre class="brush: js notranslate">var myImage = document.querySelector('img'); + +myImage.onclick = function() { + var mySrc = myImage.getAttribute('src'); + if(mySrc === 'images/firefox-icon.png') { + myImage.setAttribute ('src','images/firefox2.png'); + } else { + myImage.setAttribute ('src','images/firefox-icon.png'); + } +}</pre> + </li> + <li>Сохраните все файлы и загрузите <code>index.html</code> в браузере. Теперь, когда вы щёлкните по изображению, оно должно измениться на другое!</li> +</ol> + +<p>Итак, мы сохраняем ссылку на наш элемент {{htmlelement("img")}} в переменной <code>myImage</code>. Далее, мы создаём этой переменной обработчик события <code>onclick</code> с анонимной функцией. Теперь, каждый раз, когда на этот элемент изображения щёлкнут:</p> + +<ol> + <li>Мы получаем значение из атрибута <code>src</code> изображения.</li> + <li>Мы используем условие для проверки значения <code>src,</code> равен ли путь к исходному изображению: + <ol> + <li>Если это так, мы меняем значение <code>src</code> на путь ко 2-му изображению, заставляя другое изображение загружаться внутри элемента {{htmlelement("image")}}.</li> + <li>Если это не так (значит, оно должно было уже измениться), мы меняем значение <code>src</code>, возвращаясь к первоначальному пути изображения, каким он был изначально.</li> + </ol> + </li> +</ol> + +<h3 id="Добавление_персонального_приветственного_сообщения">Добавление персонального приветственного сообщения</h3> + +<p>Далее мы добавим немного другого кода, чтобы изменить заголовок страницы на персонализированное приветственное сообщение, когда пользователь впервые зайдет на сайт. Это приветственное сообщение будет сохраняться, когда пользователь покинет сайт, а позже вернется - мы сохраним его с помощью <a href="https://developer.mozilla.org/ru/docs/Web/API/Web_Storage_API">Web Storage API</a>. Мы также включим возможность изменить пользователя и, следовательно, приветственное сообщение, в любое время, когда это будет необходимо.</p> + +<ol> + <li>В <code>index.html</code>, добавьте следующую строку перед элементом {{htmlelement("script")}}: + + <pre class="brush: html notranslate"><button>Change user</button></pre> + </li> + <li>В <code>main.js</code>, добавьте следующий код в конец файла, точно так, как написано - он захватит ссылки на новую кнопку и заголовок, и сохранит их в переменные: + <pre class="brush: js notranslate">var myButton = document.querySelector('button'); +var myHeading = document.querySelector('h1');</pre> + </li> + <li>Теперь добавьте следующую функцию для установки персонализированного приветствия - она ничего не будет делать, но мы будем использовать её позже: + <pre class="brush: js notranslate">function setUserName() { + var myName = prompt('Please enter your name.'); + localStorage.setItem('name', myName); + myHeading.<span class="pl-smi">textContent</span> = 'Mozilla is cool, ' + myName; +}</pre> + Эта функция содержит функцию <a href="/ru/docs/Web/API/Window.prompt"><code>prompt()</code></a>, которая вызывает диалоговое окно, немного похожее на <code>alert()</code> кроме того, что <code>prompt()</code> просит пользователя ввести некоторые данные, и сохраняет эти данные в переменной, после того как пользователь нажимает <strong>OK</strong>. В данном случае, мы просим пользователя ввести его имя. Далее, мы вызываем API под названием <code>localStorage</code>, который позволяет нам хранить данные в браузере и извлекать их позднее. Мы используем функцию <code>setItem()</code> из localStorage для создания и хранения данных в свойстве под названием <code>'name'</code>, и устанавливаем это значение в переменную <code>myName</code>, которая содержит имя введенное пользователем. В конце мы устанавливаем <code>textContent</code> заголовку в виде строки и имени пользователя.</li> + <li>Затем добавьте блок <code>if ... else</code> - мы могли бы назвать это кодом инициализации, поскольку он структурирует приложение при его первой загрузке: + <pre class="brush: js notranslate">if(!localStorage.getItem('name')) { + setUserName(); +} else { + var storedName = localStorage.getItem('name'); + myHeading.<span class="pl-smi">textContent</span> = 'Mozilla is cool, ' + storedName; +}</pre> + Этот блок сначала использует оператор отрицания (логическое НЕ, представленное в виде !) чтобы проверить, существуют ли данные в пункте <code>name</code>. Если нет, то функция <code>setUserName()</code> запускается для их создания. Если данные существуют (то есть, пользователь установил его во время предыдущего посещения), мы извлекаем сохраненное имя, с помощью <code>getItem()</code> и устанавливаем <code>textContent</code> заголовку в виде строки плюс имя пользователя, так же, как мы делали внутри <code>setUserName()</code>.</li> + <li>Наконец, установите обработчик события <code>onclick</code> на кнопку. При нажатии кнопки запускается функция <code>setUserName()</code>. Это позволяет пользователю установить новое имя, всякий раз, когда он захочет, нажатием кнопки: + <pre class="brush: js notranslate">myButton.onclick = function() { + setUserName(); +} +</pre> + </li> +</ol> + +<p>Теперь, когда вы впервые заходите на сайт, он попросит вас указать имя пользователя, а затем предоставит вам персональное сообщение. Вы можете изменить имя в любое время, нажав на кнопку. В качестве дополнительного бонуса, поскольку имя хранится внутри localStorage, оно сохраняется после закрытия сайта, сохраняя при этом персонализированное сообщение при следующем открытии сайта!</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Если вы следовали всем инструкциям в этой статье, в конечном итоге вы должны получить страницу, которая выглядит примерно так (вы также можете <a href="https://mdn.github.io/beginner-html-site-scripted/">посмотреть нашу версию здесь</a>):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9539/website-screen-scripted.png" style="display: block; height: 995px; margin: 0px auto; width: 800px;"></p> + +<p>Если вы застряли, вы всегда можете сравнить свою работу с нашим <a href="https://github.com/mdn/beginner-html-site-scripted/blob/gh-pages/scripts/main.js">готовым примером кода на Github</a>.</p> + +<p>Здесь мы узнали только самую поверхность JavaScript. Если вам понравился этот язык и вы хотите изучить его поглубже, перейдите к нашему разделу <a href="/ru/docs/Learn/JavaScript">изучение JavaScript</a>.</p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового программного обеспечения</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего веб-сайта</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Веб</a></li> +</ul> diff --git a/files/ru/learn/getting_started_with_the_web/publishing_your_website/index.html b/files/ru/learn/getting_started_with_the_web/publishing_your_website/index.html new file mode 100644 index 0000000000..3e70566e96 --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/publishing_your_website/index.html @@ -0,0 +1,183 @@ +--- +title: Публикация вашего веб-сайта +slug: Learn/Getting_started_with_the_web/Publishing_your_website +tags: + - FTP + - GitHub + - Google App Engine + - Веб + - Веб сервер + - Изучение + - Начинающий + - Публикация + - Хостинг +translation_of: Learn/Getting_started_with_the_web/Publishing_your_website +--- +<p>{{LearnSidebar}}{{PreviousMenuNext("Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web/How_the_Web_works", "Learn/Getting_started_with_the_web")}}</p> + +<div class="summary"> +<p>После того, как вы закончите писать код и организовывать файлы, которые составляют ваш веб-сайт, вам нужно расположить все это в Интернете, чтобы люди могли найти ваш сайт. В этой статье описывается, как разместить простой пример вашего кода с минимальными усилиями.</p> +</div> + +<h2 id="Какие_существуют_варианты">Какие существуют варианты?</h2> + +<p>Публикация веб-сайта это не простая тема, главным образом, потому что существует много различных способов сделать это. В этой статье мы не стремимся документировать все возможные методы. Скорее, мы обсудим плюсы и минусы трех обширных стратегий с точки зрения новичка, а затем вы пройдете через один метод, который будет работать в настоящее время.</p> + +<h3 id="Получение_хостинга_и_доменного_имени">Получение хостинга и доменного имени</h3> + +<p>Чтобы иметь больший контроль над контентом и внешним видом веб-сайта, большинство людей предпочитают покупать веб-хостинг и доменное имя:</p> + +<ul> + <li>Хостинг — арендованное файловое пространство на <a href="/en-US/Learn/What_is_a_web_server">веб-сервере</a> хостинговой компании. Вы размещаете ваши файлы веб-сайта в этом пространстве, и веб-сервер выдает контент для веб-пользователей, которые запрашивают его.</li> + <li><a href="/en-US/Learn/Understanding_domain_names">Доменное имя</a> — уникальный адрес по которому люди могут найти ваш веб-сайт, например <code>http://www.mozilla.org</code> или <code>http://www.bbc.co.uk</code>. Вы можете арендовать доменное имя на столько лет, сколько захотите (минимум на 1 год) у <strong>регистратора доменов</strong>.</li> +</ul> + +<p>Множество профессиональных веб-сайтов располагается в Интернете именно таким образом.</p> + +<p>Кроме того, вам потребуется {{Glossary("FTP", "File Transfer Protocol (FTP)")}}-клиент (более подробно см. <a href="/en-US/Learn/How_much_does_it_cost#Software">Сколько это стоит: программное обеспечение</a>), чтобы передать файлы веб-сайта на сервер. Существует множество FTP-клиентов, но, как правило, вам нужно войти на веб-сервер, используя данные, предоставленные вашей хостинговой компанией (например: имя пользователя (логин), пароль, имя хоста). Затем FTP-клиент отобразит файлы на вашем компьютере в одной половине окна и файлы на хостинговом сервере в другой половине, так вы сможете перетаскивая копировать файлы с вашего компьютера на сервер и обратно.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9469/ftp.jpg" style="display: block; height: 487px; margin: 0px auto; width: 800px;"></p> + +<h4 id="Советы_по_поиску_хостингов_и_доменов">Советы по поиску хостингов и доменов</h4> + +<ul> + <li>Здесь мы не продвигаем какие-то конкретные хостинговые компании. Чтобы найти хостинг и регистратора доменных имен, просто поищите "веб-хостинг" и "доменные имена". Во всех таких сервисах есть функция, позволяющая вам проверить, доступно ли имя домена, или кто-то другой уже зарегестрировал его. </li> + <li>Ваш домашний или рабочий {{Glossary("ISP", "Интернет-провайдер")}} может предоставлять хостинговые услуги для небольших веб-сайтов. Набор возможностей в таком случае может быть ограничен, но, тем не менее, он может отлично подойти для ваших первых экспериментов - свяжитесь с ними и узнайте! </li> + <li>Также есть несколько бесплатных сервисов, таких как <a href="https://neocities.org/">Neocities</a>, <a href="https://www.blogger.com">Blogspot</a>, и <a href="https://wordpress.com/">Wordpress</a>. Опять же, вы получаете то, за что платите, но они идеально подходят для ваших первоначальных экспериментов. Бесплатные сервисы по большей части не требуют FTP-клиентов - вы можете перетаскивать ваши файлы напрямую в веб-интерфейсе.</li> + <li>Иногда компании предлагают одновременно и хостинг и домен.</li> +</ul> + +<h3 id="Использование_онлайн_инструментов_таких_как_GitHub_или_Google_App_Engine">Использование онлайн инструментов, таких как GitHub или Google App Engine</h3> + +<p>Некоторые сервисы позволяют вам опубликовать сайт:</p> + +<ul> + <li><a href="https://github.com/">GitHub</a> - это "социальная сеть программистов". С помощью нее можно загружать репозитории с вашими разработками для хранения в <a href="http://git-scm.com/">Git</a> - <strong>систему контроля версий. </strong>По-умолчанию все разработки хранятся с открытым исходным кодом, а это значит, что ваш код будет доступен любому - участники могут по нему учиться либо же предлагать свои улучшения. Вы также можете объединяться с другими кодерами! Это очень большое и полезное сообщество, в чьи ряды лучше вступить, и Git/GitHub это очень популярная <a href="http://git-scm.com/book/en/v2/Getting-Started-About-Version-Control">система контроля версий</a> — большинство компаний сейчас использует ее для работы. GitHub имеет очень полезную функцию <a href="https://pages.github.com/">GitHub pages</a>, с помощью которой вы сможете опубликовать ваш код (ваш сайт) в интернете.</li> + <li><a href="https://cloud.google.com/appengine/" title="App Engine - Build Scalable Web & Mobile Backends in Any Language | Google Cloud Platform">Google App Engine</a> - это мощная платформа, которая позволяет создавать и запускать приложения в инфраструктуре Google — нужно ли вам создать многоуровневое веб-приложение с нуля или разместить статический веб-сайт. Смотрите <a href="https://developer.mozilla.org/ru/docs/Learn/Common_questions/How_do_you_host_your_website_on_Google_App_Engine">как разместить ваш веб-сайт на Google App Engine</a> чтобы узнать больше информации.</li> +</ul> + +<p>В отличие от других хостингов, эти услуги обычно бесплатны, но взамен вы получите ограниченный набор инструментов.</p> + +<h3 id="Использование_облачных_IDE_таких_как_CodePen">Использование облачных IDE, таких как CodePen</h3> + +<p>Существует ряд веб-приложений, эмулирующих среду веб-разработки, позволяющих вводить HTML, CSS и JavaScript, а затем отображать результат этого кода в виде сайта - и все это на одной вкладке браузера. Вообще говоря, эти инструменты достаточно просты, отлично подходят для обучения, хороши для того, чтобы делиться кодом (например, если вы хотите поделиться техникой с коллегой или обратиться за помощью в отладке к коллегам из другого офиса) и бесплатны (основные функции). Они размещают вашу отрендереную страницу на уникальном веб-адресе. Однако, основные функции довольно ограничены, и приложения обычно не предоставляют хостинговое пространство для таких файлов, как изображения и т.д.</p> + +<p>Попробуйте один из этих и посмотрите, какой из них вам больше нравится:</p> + +<ul> + <li><a href="https://jsfiddle.net/">JSFiddle</a></li> + <li><a href="https://thimble.mozilla.org">Thimble</a></li> + <li><a href="http://jsbin.com/">JSBin</a></li> + <li><a href="https://codepen.io/">CodePen</a></li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9471/jsbin-screen.png" style="display: block; height: 849px; margin: 0px auto; width: 1392px;"></p> + +<h2 id="Публикация_с_помощью_GitHub">Публикация с помощью GitHub</h2> + +<p>А теперь, давайте рассмотрим, как опубликовать свой сайт на страницах GitHub. Мы не хотим сказать, что этот метод является единственным и наиболее верным, но это бесплатно, достаточно просто, а также затрагивает определённые навыки, которые точно будут полезны для вашего дальнейшего обучения.</p> + +<h3 id="Основная_настройка">Основная настройка</h3> + +<ol> + <li>Прежде всего, <a href="http://git-scm.com/downloads">установите Git</a> на ваш компьютер. Это основная версия системы управления версий, поддерживающая GitHub.</li> + <li>Далее, <a href="https://github.com/join">создайте аккаунт в GitHub</a>. Это просто и легко.</li> + <li>После того как вы зарегистрировались, войдите в github.com используя ваш логин и пароль.</li> + <li>Далее, вам нужно создать новый репозиторий для ваших файлов. Нажмитре Плюс (+) в правом верхнем углу главной страницы GitHub, затем выберите <em>New repository</em>.</li> +</ol> + +<p>На этой странице, в поле <em>Repository name</em>, введите <em>username</em>.github.io, где <em>username</em> это ваше имя пользователя. Так, например, наш друг <em>valerii15298</em> введёт <em>valerii15298.github.io</em>.</p> + +<p><img alt="" src="https://i.imgur.com/hdCboGw.png" style="display: block; height: 849px; margin: 0px auto; width: 1392px;"></p> + +<p>Нажмите <em>Create repository</em> и вы окажетесь на следующей странице:</p> + +<p><img alt="" src="https://i.imgur.com/ZWE2DMv.png" style="display: block; height: 849px; margin: 0px auto; width: 1392px;"></p> + +<h3 id="Загрузка_ваших_файлов_на_GitHub">Загрузка ваших файлов на GitHub</h3> + +<p>Здесь у нас будет использоваться командная строка чтобы отправить наш репозиторий на GitHub. Командная строка - это окно где вы вводите команды для быстрого выполнения таких вещей, как создание файла или запуск программы, без использования пользовательского интерфейса. Командная строка выглядит примерно так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9483/command-line.png" style="display: block; height: 478px; margin: 0px auto; width: 697px;"></p> + +<div class="note"> +<p><strong>Заметка</strong>: Вы также можете использовать графический пользовательский интерфейс <a href="http://git-scm.com/downloads/guis">Git</a> для этих же целей, если вам не удобно работать с командной строкой.</p> +</div> + +<p><span id="command-line">У всех операционных систем есть командная строка:</span></p> + +<ul> + <li><strong>Windows</strong>: <strong>Командная строка. </strong>Чтобы открыть её нажмите клавишу Windows, затем введите <em>Командная строка </em>в поле поиска, и выберите её в появившемся списке. Заметьте, что Windows имеет свои собственные соглашения команд, отличные от Linux и OS X, поэтому приведенные ниже команды могут отличаться на вашем компьютере.</li> + <li><strong>OS X</strong>: <strong>Terminal</strong> можно найти в <em>Приложения > Утилиты</em>.</li> + <li><strong>Linux</strong>: Обычно вы можете вытащить терминал с помощью Ctrl + Alt + T. Если это не сработает, найдите <strong>Терминал</strong> в панели приложений или меню.</li> +</ul> + +<p>Сначала это может показаться немного страшным, но не волнуйтесь - вы скоро освоите основы. Вы говорите компьютеру сделать что-то в терминале, введя команду и нажав Enter.</p> + +<ol> + <li>Укажите в командной строке каталог <code>test-site</code> (или другое название каталога, содержащего ваш сайт). Для этого используйте команду <code>cd</code> (т.е. «change directory»). Вот то, что вы наберете, если разместили свой веб-сайт в каталоге под названием <code>test-site</code> на рабочем столе: + + <pre class="brush: bash notranslate">cd Desktop/test-site</pre> + </li> + <li>Когда командная строка указывает внутрь вашего каталога веб-сайта, введите следующую команду, которая сообщает инструменту <code>git</code>, чтобы он превратил каталог в репозиторий git: + <pre class="brush: bash notranslate">git init</pre> + </li> + <li>Далее вернемся к сайту GitHub. На текущей странице вас интересует раздел "…or push an existing repository from the command line". Вы должны увидеть две строки кода в этом разделе. Скопируйте всю первую строку, вставьте ее в командную строку и нажмите Enter. Команда должна выглядеть примерно так: + <pre class="brush: bash notranslate">git remote add origin https://github.com/bobsmith/bobsmith.github.io.git</pre> + </li> + <li>Далее введите следующие две команды, нажимая Enter после каждой. Это подготовит код к загрузке на GitHub, и укажет Git управлять этими файлами. + <pre class="brush: bash notranslate">git add --all +git commit -m 'adding my files to my repository'</pre> + </li> + <li>Наконец, загрузите код на GitHub - вернитесь на веб-страницу GitHub, на которой вы находились, и введите в терминал команду: + <pre class="brush: bash notranslate">git push -u origin master</pre> + </li> + <li>Теперь, когда вы перейдете по веб-адресу, созданному в GitHub, в новом окне браузера (<em>username.github.io</em>), вы увидите ваш сайт онлайн! Разошлите ссылку вашим друзьям, пусть оценят ваше мастерство.</li> +</ol> + +<div class="note"> +<p><strong>Заметка</strong>: Если вы застряли, <a href="https://pages.github.com/">GitHub Pages homepage</a> будет очень полезна для вас.</p> +</div> + +<h3 id="Дальнейшее_изучение_GitHub">Дальнейшее изучение GitHub</h3> + +<p>Если вы хотите сделать больше изменений на своем тестовом сайте и загрузить их в GitHub, вам просто нужно внести изменения в свои файлы, как и раньше. Затем вам нужно ввести следующие команды (нажав Enter после каждого), чтобы вставить эти изменения в GitHub:</p> + +<pre class="notranslate">git add --all +git commit -m 'another commit' +git push</pre> + +<p>Вы можете заменить <em>another commit</em> более подходящим сообщением, описывающим какие изменения вы только что сделали. </p> + +<p>Мы едва затронули Git. Чтобы узнать больше, начните с <a href="https://help.github.com/index.html">GitHub Help site</a>.</p> + +<h2 id="Заключение">Заключение</h2> + +<p>К этому моменту, у вас должен быть собственный пример веб-сайта, доступный по уникальному веб-адресу. Отлично!</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9485/hosted-final-site.png" style="display: block; height: 1049px; margin: 0px auto; width: 878px;"></p> + +<h3 id="Дальнейшее_чтение">Дальнейшее чтение</h3> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/%D0%A7%D1%82%D0%BE_%D1%82%D0%B0%D0%BA%D0%BE%D0%B5_%D0%B2%D0%B5%D0%B1_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80">Что такое веб-сервер?</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/Understanding_domain_names">Что такое доменные имена?</a></li> + <li><a href="/en-US/Learn/How_much_does_it_cost">Сколько стоит сделать что-то в Интернете?</a></li> + <li><a href="https://www.codecademy.com/learn/deploy-a-website">Развертывание сайта</a>: хороший курс от Codecademy, который забегает немного вперёд и показывает некоторые дополнительные техники.</li> + <li><a href="http://alignedleft.com/resources/cheap-web-hosting">Cheap or Free Static Website Hosting</a>, статья написанная Скоттом Мюрреем содержит некоторые полезные идеи о доступных сервисах.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web/How_the_Web_works", "Learn/Getting_started_with_the_web")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового программного обеспечения</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего веб-сайта</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Веб</a></li> +</ul> diff --git a/files/ru/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html b/files/ru/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html new file mode 100644 index 0000000000..c6ef10460d --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html @@ -0,0 +1,123 @@ +--- +title: Каким должен быть ваш веб-сайт? +slug: Learn/Getting_started_with_the_web/What_will_your_website_look_like +tags: + - Assets + - Beginner + - Composing + - Content + - Design + - Fonts + - Learn + - Plan + - Дизайн + - Контент + - Новичку + - Шрифты +translation_of: Learn/Getting_started_with_the_web/What_will_your_website_look_like +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Installing_basic_software", "Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p><em>Каким должен быть ваш веб-сайт?</em> обсудите план и дизайн веб-сайта, <em>прежде</em> чем приступить к написанию кода, в том числе "Какую информацию будет содержать мой веб-сайт?" "Какие шрифты и цвета я хочу использовать?" "Что будет делать мой сайт?"</p> +</div> + +<h2 id="Перво-наперво_планирование">Перво-наперво: планирование</h2> + +<p>Перед тем как делать что-то, вам нужны идеи. Что ваш веб-сайт должен фактически делать? По существу, ваш веб-сайт может делать все, что угодно, но для вашей первой попытки, вы должны придерживаться простых вещей. Мы начнем с создания простой веб-страницы, содержащую заголовок, изображение и несколько абзацев.</p> + +<p>Для начала, вам будет нужно ответить на следующие вопросы:</p> + +<ol> + <li><strong>О чем ваш веб-сайт?</strong> Вам нравятся собаки, Нью-Йорк или Pacman?</li> + <li><strong>Какую информацию вы предоставляете о предмете?</strong> Напишите заголовок и несколько абзацев, и подумайте над изображениями, которые вы хотите показать на своей странице.</li> + <li><strong>Как будет выглядеть ваш веб-сайт</strong>, в простых терминах высокого уровня. Какой цвет фона? Какой вид шрифта будет уместен: деловой, мультяшный, жирный и кричащий или тонкий?</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Комплексные проекты нуждаются в детализированных руководствах, которые включают все детали цветов, шрифтов, расстояния между элементами на странице, соответствующий стиль письма и так далее. Их иногда называют руководствами по проектированию или бренд-бук, вы можете увидеть пример в <a href="https://www.mozilla.org/en-US/styleguide/products/firefox-os/">Руководство Firefox OS</a>.</p> +</div> + +<h2 id="Сделайте_набросок_вашего_дизайна">Сделайте набросок вашего дизайна</h2> + +<p>Теперь возьмите ручку и бумагу и сделайте примерный набросок того, как вы хотите, чтобы выглядел ваш сайт. Для вашей первой веб-страницы должен получиться небольшой набросок, и вы должны взять это в привычку. Это действительно помогает, и вам не нужно быть Ван Гогом!</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9239/website-drawing-scan.png" style="display: block; height: 460px; margin: 0px auto; width: 640px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Даже в реальных, сложных веб-сайтах, команда разработчиков обычно начинает с наброска на бумаге и потом строит цифровые макеты используя графические редакторы или веб-технологии.</p> + +<p>Веб-команда часто включает в себя пару графических дизайнеров и дизайнера с опытом взаимодействия (user-experience (UX) designer). Графические дизайнеры, очевидно, работают вместе над визуализацией веб-сайта. UX дизайнеры играют более абстрактную роль, обращаясь к тому как пользователи будут пользоваться и взаимодействовать с веб-сайтом.</p> +</div> + +<h2 id="Выберите_свои_активы">Выберите свои активы</h2> + +<p>На данном этапе хорошо бы начать собирать контент, который в конечном итоге появится на вашей веб-странице.</p> + +<h3 id="Текст">Текст</h3> + +<p>У вас должен быть текст, разбитый на заголовки и параграфы. Придерживайтесь этого правила.</p> + +<h3 id="Цветовая_схема">Цветовая схема</h3> + +<p>Чтобы выбрать цвет, перейдите в <a href="/ru/docs/Web/CSS/CSS_Colors/Color_picker_tool">инструмент выбора цвета</a> и выберите цвет, который вам нравится. Когда вы щёлкните по цвету, вы увидите странный код из шести цифр, например, <code>#660066</code>. Это называется <em>шестнадцатеричный код (hex(adecimal) code)</em> и он представляет ваш цвет. Скопируйте это код куда-нибудь прямо сейчас.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8975/Screenshot%20from%202014-11-03%2017:40:49.png" style="height: 262px; width: 448px;"></p> + +<h3 id="Изображения">Изображения</h3> + +<p>Чтобы выбрать изображение, перейдите в <a href="https://www.google.com/imghp?gws_rd=ssl">Google Картинки</a> и найдите что-нибудь подходящее.</p> + +<ol> + <li>Когда вы найдете изображение, которое хотели, щёлкните по нему.</li> + <li>Нажмите кнопку <em>В полном размере (View image)</em>.</li> + <li>На следующей странице, правым щелчком мыши на изображении (Ctrl + клик на Mac), выберите Сохранить изображение как... (<em>Save Image As...)</em>, и выберите место для сохранения вашего изображения. В качестве альтернативы, скопируйте адрес изображения из адресной строки браузера для последующего использования.</li> +</ol> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8985/Screenshot%20from%202014-11-04%2015:09:21.png" style="height: 293px; width: 420px;"></p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8989/Screenshot%20from%202014-11-04%2015:20:48.png" style="height: 292px; width: 340px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Большинство изображений в Интернете, использованных в Google Картинках имеют авторские права. Для снижения вероятности нарушения авторских прав, используйте фильтр лицензии Google. Для этого: 1) кликните на <strong>Инструменты поиска (Search tools)</strong>, затем на 2) <strong>Права на использование (Usage rights)</strong>:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8981/Screenshot%20from%202014-11-04%2014:27:45.png" style="height: 195px; width: 587px;"></p> +</div> + +<h3 id="Шрифт">Шрифт</h3> + +<p>Чтобы выбрать шрифт:</p> + +<ol> + <li>Перейдите на <a href="http://www.google.com/fonts">Google Fonts</a> и прокрутите список вниз, пока не найдете шрифт, который вам понравится. Вы также можете использовать элементы управления справа для дальнейшей фильтрации результатов.</li> + <li>Щёлкните по кнопке "плюс" рядом со шрифтом, который вы хотите выбрать.</li> + <li>Щёлкните по кнопке "* Family Selected" на панели в нижней части страницы. ("*" зависит от того, сколько шрифтов вы выбрали)</li> + <li>В всплывающем окне вы можете увидеть и скопировать строки кода, которые предоставляет Google, чтобы сохранить их позже в вашем текстовом редакторе.</li> +</ol> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13871/font1.png"></p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13873/font2.png"></p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Installing_basic_software", "Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web")}}</p> + +<p> </p> + +<p> </p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового программного обеспечения</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего веб-сайта</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Веб</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/getting_started_with_the_web/веб_и_веб_стандарты/index.html b/files/ru/learn/getting_started_with_the_web/веб_и_веб_стандарты/index.html new file mode 100644 index 0000000000..08fad617b5 --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/веб_и_веб_стандарты/index.html @@ -0,0 +1,167 @@ +--- +title: Всемирная сеть (веб) и веб-стандарты +slug: Learn/Getting_started_with_the_web/Веб_и_веб_стандарты +tags: + - Веб-стандарты + - Изучение +translation_of: Learn/Getting_started_with_the_web/The_web_and_web_standards +--- +<p dir="ltr">{{learnsidebar}}</p> + +<p dir="ltr">Статья содержит общую информацию о всемирной сети (the Web) — откуда она взялась, что такое веб-стандарты, как они связанны, почему "веб разработчик" отличный карьерный выбор и чему полезному можно научиться изучая этот курс.</p> + +<h2 dir="ltr" id="Краткая_история_сети_веб">Краткая история сети веб</h2> + +<p dir="ltr">Мы постарались максимально кратко изложить здесь информацию. Если вы более детально заинтересованы в истории веб сети, то попробуйте поискать это в интернете.</p> + +<p dir="ltr">В конце 1960-х военные США разработали коммуникационную сеть <a href="/en-US/docs/Glossary/Arpanet">ARPANET</a>. Вполне можно её рассматривать в качестве прародителя современной сети, так как она работала с помощью <a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BC%D0%BC%D1%83%D1%82%D0%B0%D1%86%D0%B8%D1%8F_%D0%BF%D0%B0%D0%BA%D0%B5%D1%82%D0%BE%D0%B2">коммутации пакетов</a>, и для неё впервые была внедрена сетевая модель <a href="https://ru.wikipedia.org/wiki/TCP/IP">TCP/IP</a>. Эти две технологии послужили основой, на которой затем был построен интернет.</p> + +<p dir="ltr">В 1980 году Тим Бернерс-Ли (aka TimBL) написал программу под названием ENQUIRE, которая позволяла устанавливать связь между двумя узлами. Ничего не напоминает?</p> + +<p dir="ltr">В 1989 году TimBL выступил в организации <a href="https://ru.wikipedia.org/wiki/%D0%A6%D0%95%D0%A0%D0%9D">ЦЕРН</a> с идеями о методах структурирования, обработке и обмена информацией (<a href="https://www.w3.org/History/1989/proposal.html">Information Management: A Proposal</a>), предложив при этом концепцию "<a href="https://ru.wikipedia.org/wiki/%D0%93%D0%B8%D0%BF%D0%B5%D1%80%D1%82%D0%B5%D0%BA%D1%81%D1%82">гипертекста</a>". Идеи Тима были одобрены и он начал воплощать в реальность свой проект. Современная сеть построена на основании его работ. </p> + +<p dir="ltr">К концу 1990-го года Тим Бернерс разработал все необходимые для запуска сети средства — <a href="/en-US/docs/Web/HTTP">HTTP</a>, <a href="/en-US/docs/Web/HTML">HTML</a>, первый в мире веб браузер (<a href="https://en.wikipedia.org/wiki/WorldWideWeb">WorldWideWeb</a>), сервер HTTP и несколько веб страниц для наглядности.</p> + +<p dir="ltr">В течение нескольких последующих лет веб сеть расширялась, выпускались новые браузеры, были установлены тысячи серверов и созданны миллионы веб страниц. Как и обещали, достаточно краткая история.</p> + +<p dir="ltr">Стоит отметить, что в 1994 году TimBL основал консорциум Всемирной паутины (<a href="https://www.w3.org/">World Wide Web Consortium (W3C)</a>) - организацию, связывающую множество компаний для сплочения усилий в области разработки веб технологий. После этого появились технологии, например, такие как <a href="/en-US/docs/Web/CSS">CSS</a> и <a href="/en-US/docs/Web/JavaScript">JavaScript</a>, которые преобразовали веб сеть в тот вид, в котором мы наблюдаем её сейчас.</p> + +<h2 dir="ltr" id="Веб-стандарты">Веб-стандарты</h2> + +<p dir="ltr"><strong>Веб-стандарты</strong> - это технологии, используемые для создания веб страниц. Стандарты существуют в виде технической документации (спецификаций), которая точно описывает как та, или иная технология должна работать. Документация никак не поможет изучить то, как пользоваться описываемыми в ней технологиями (вот почему существет сайт MDN Web Docs). Она используются разработчиками ПО для внендрения технологий (например, в веб браузеры).</p> + +<p dir="ltr">В качестве примера приведем стандарт <a href="https://html.spec.whatwg.org/multipage/">HTML Living Standard</a>. Он описывает как HTML (все элементы HTML, связанные с ними API и остальные близкие технологии) должны быть реализованы.</p> + +<p dir="ltr">Веб-стандарты создаются организациями стандартов — институтами, которые приглашают группы людей из различных компаний для согласования того, как технологии должны применяться наиболее эффективным образом в рассматриваемых случаях. Самая известная организация веб-стандартов - W3C. Существуют и другие: <a href="https://whatwg.org/">WHATWG</a> (ответственны за модернизацию языка html), <a href="https://www.ecma-international.org/">ECMA</a> (выпускают стандарты языка ECMAScript, на котором построен JavaScript), <a href="https://www.khronos.org/">Khronos</a> (создают технологии для 3D графики, например WebGL).</p> + +<h3 dir="ltr" id="Open_standards">"Open" standards</h3> + +<p dir="ltr">One of the key aspects of web standards, which TimBL and the W3C agreed on from the start, is that the web (and web technologies) should be free to both contribute and use, and not encumbered by patents/licensing. Therefore anyone can write the code to build a website for free, and anyone can contribute to the standards creation process, where the specs are written.</p> + +<p dir="ltr">Because web technologies are created openly, in collaboration between many different companies, it means that no one company gets to control them, which is a really good thing. You wouldn't want a single company suddenly deciding to put the entire web behind a paywall, or releasing a new version of HTML that everyone has to buy to continue making web sites, or worse still, just deciding they aren't interested any more and just turning it off.</p> + +<p dir="ltr">This allows the web to remain a freely-available public resource.</p> + +<h3 dir="ltr" id="Не_разорви_сеть">Не разорви сеть</h3> + +<p dir="ltr">Популярная в области веб-стандартов фраза гласит: "не разорви сеть". Это означает, что каждая новая веб-технология должна быть совместима со всеми предыдущими технологиями (поэтому старые сайты до сих пор работают), и со всеми последующими (разрабатываемые в последствии технологии, в свою очередь, должны быть совместимы с имеющимися). В процессе изучения представленного здесь материала вы начнете понимать каким образом это реализуется.</p> + +<h2 id="Being_a_web_developer_is_good">Being a web developer is good</h2> + +<p>The web industry is a very attractive market to enter if you are looking for a job. Recent published figures say that there are currently around 19 million web developers in the world, and that figure is set more than double in the next decade. And at the same time, there is a skill shortage in the industry — so what better time to learn web development?</p> + +<p>It isn't all fun and games however — building web sites is a more complicated proposition than it used to be, and you'll have to put some time in to studying all the different technologies you need to use, all the techniques and best practices you need to know, and all the typical patterns you'll be called upon to implement. It'll take you a few months to really start to get into it, and then you'll need to keep learning so that your knowledge stays up-to-date with all the new tools and features that appear on the web platform, and keep practicing and refining your craft.</p> + +<p><em>The only constant is change.</em></p> + +<p>Does this sound hard? Don't worry — we aim to give you everything you need to know to get started, and things will get easier. Once you embrace the constant change and uncertainty of the web, you'll start to enjoy yourself. As a part of the web community, you'll have an entire web of contacts and useful material to help you, and you'll start to enjoy the creative possibilities it brings.</p> + +<p>You're a digital creative now. Enjoy the experience, and the potential for earning a living.</p> + +<h2 id="Overview_of_modern_web_technologies">Overview of modern web technologies</h2> + +<p>There are a number of technologies to learn if you want to be a front-end web developer. In this section we will describe them briefly. For a more detailed explanation of how some of them work together, read our article <a href="/en-US/docs/Learn/Getting_started_with_the_web/How_the_Web_works">How the web works</a>.</p> + +<h3 id="Browsers">Browsers</h3> + +<p>You are probably reading these words inside a web browser in this very moment (unless you've printed it out, or are using assistive technology, such as a screenreader to read it out to you). Web browsers are the software programs people use to consume the web, and include <a href="https://www.mozilla.org/en-US/firefox/">Firefox</a>, <a href="https://www.google.com/chrome/">Chrome</a>, <a href="https://www.opera.com/">Opera</a>, <a href="https://www.apple.com/safari/">Safari</a>, and <a href="https://www.microsoft.com/en-us/windows/microsoft-edge">Edge</a>.</p> + +<h3 id="HTTP">HTTP</h3> + +<p>Hypertext Transfer Protocol, or <a href="/en-US/docs/Web/HTTP/Basics_of_HTTP">HTTP</a>, is a messaging protocol that allows web browsers to communicate with web servers (where web sites are stored). A typical conversation goes something like</p> + +<pre class="notranslate">"Hello web server. Can you give me the files I need to render bbc.co.uk"? + +"Sure thing web browser — here you go" + +[Downloads files and renders web page]</pre> + +<p>The actual syntax for HTTP messages (called requests and responses) is not that human-readable, but this gives you the basic idea.</p> + +<h3 id="HTML_CSS_and_JavaScript">HTML, CSS, and JavaScript</h3> + +<p><a href="/en-US/docs/Web/HTML">HTML</a>, <a href="/en-US/docs/Web/CSS">CSS</a>, and <a href="/en-US/docs/Web/JavaScript">JavaScript</a> are the main three technologies you'll use to build a website:</p> + +<ul> + <li> + <p>Hypertext markup language, or <strong>HTML</strong>, is a markup language consisting of different elements you can wrap (mark up) content in to give it meaning (semantics) and structure. Simple HTML looks like this:</p> + + <pre class="brush: html notranslate"><h1>This is a top-level heading</h1> + +<p>This is a paragraph of text.</p> + +<img src="cat.jpg" alt="A picture of my cat"></pre> + + <p>If we adopted a house-building analogy, HTML would be like the foundations and walls of the house, which give it structure and hold it together.</p> + </li> + <li> + <p>Cascading Style Sheets (<strong>CSS</strong>) is a rule-based language used to apply styles to your HTML, for example setting text and background colors, adding borders, animating things, or laying out a page in a certain way. As a simple example, the following code would turn our HTML paragraph red:</p> + + <pre class="brush: css notranslate">p { + color: red; +}</pre> + + <p>In the house analogy, CSS is like the paint, wallpaper, carpets and paintings you'd use to make the house look nice.</p> + </li> + <li> + <p><strong>JavaScript</strong> is the programming language we use to add interactivity to web sites, from dynamic style switching, to fetching updates from the server, right through to complex 3D graphics. The following simple JavaScript will store a reference to our paragraph in memory and change the text inside it:</p> + + <pre class="brush: js notranslate">let pElem = document.querySelector('p'); +pElem.textContent = 'We changed the text!';</pre> + + <p>In the house analogy, JavaScript is like the cooker, TV, Microwave, or hairdryer — the things that give your house useful functionality</p> + </li> +</ul> + +<h3 id="Tooling">Tooling</h3> + +<p>Once you've learned the "raw" technologies that can be used to build web pages (such as HTML, CSS, and JavaScript), you'll soon start to come across various tools that can be used to make your work easier or more efficient. Examples include:</p> + +<ul> + <li>The <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools</a> inside modern browsers that can be used to debug your code.</li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing">Testing tools</a> that can be used to run tests to show whether your code is behaving as you intended it to.</li> + <li>Libraries and frameworks built on top of JavaScript that allow you to build certain types of web site much more quickly and effectively.</li> + <li>So-called "Linters", which take a set of rules, look at your code, and highlight places where you haven't followed the rules properly.</li> + <li>Minifiers, which remove all the whitespace from your code files to make it so that they are smaller and therefore download from the server more quickly.</li> +</ul> + +<h3 id="Server-side_languages_and_frameworks">Server-side languages and frameworks</h3> + +<p>HTML, CSS, and JavaScript are front-end (or client-side) languages, which means they are run by the browser to produce a website front-end that your users can use.</p> + +<p>There are another class of languages called back-end (or server-side) languages, meaning that they are run on the server before the result is then sent to the browser to be displayed. A typical use for a server-side language is to get some data out of a database and generate some HTML to contain the data, before then sending the HTML over to the browser to display it to the user.</p> + +<p>Example server-side languages include ASP.NET, Python, PHP, and NodeJS.</p> + +<h2 id="Web_best_practices">Web best practices</h2> + +<p>We have briefly talked about the technologies that you'll use to build websites. Now let's discuss the best practices you should employ to make sure you are using those technologies in the best way that you can.</p> + +<p>When doing web development, the main cause of uncertainty comes from the fact that you don't know what combination of technology each user will use to view your web site:</p> + +<ul> + <li>User 1 might be looking at it on an iPhone, with a small, narrow screen.</li> + <li>User 2 might be looking at it on a Windows laptop with a widescreen monitor attached to it.</li> + <li>User 3 might be blind, and using a screenreader to read the web page out to them.</li> + <li>User 4 might be using a really old desktop machine that can't run modern browsers.</li> +</ul> + +<p>Because you don't know exactly what your users will use, you need to design defensively — make your web site as flexible as possible, so that all of the above users can make use of it, even if they might not all get the same experience. In short, we are trying to make the web work for all, as much as possible.</p> + +<p>You'll come across the below concepts at some point in your studies.</p> + +<ul> + <li><strong>Cross-browser compatibility</strong> is the practice of trying to make sure your webpage works across as many devices as possible. This includes using technologies that all the browsers support, delivering better experiences to browsers that can handle them (progressive enhancement), and/or writing code so that it falls back to a simpler but still usable experience in older browsers (graceful degradation). It also involves a lot of testing to see if anything fails in certain browsers, and then more work to fix those failures.</li> + <li><strong>Responsive web design</strong> is the practice of making your functionality and layouts flexible so they can automatically adapt to different browsers. An obvious example is a website that is laid out one way in a widescreen browser on the desktop, but displays as a more compact, single-column layout on mobile phone browsers. Try adjusting the width of your browser window now, and see what happens.</li> + <li><strong>Performance</strong> means getting web sites to load as quickly as possible, but also making them intuitive and easy to use so that users don't get frustrated and go somewhere else.</li> + <li><strong>Accessibility</strong> means making your websites usable by as many different kinds of people as possible (related concepts are diversity and inclusion, and inclusive design). This includes people with visual impairments, hearing impairments, cognitive disabilities, or physical disabilities. It also goes beyond people with disabilities — how about young or old people, people from different cultures, people using mobile devices, or people with unreliable or slow network connections?</li> + <li><strong>Internationalization</strong> means making websites usable by people from different cultures, who speak different languages to your own. There are technical considerations here (such as altering your layout so that it still works OK for right-to-left, or even vertical languages), and human ones (such as using simple, non-slang language so that people who have your language as their second or third language are more likely to understand your text).</li> + <li><strong>Privacy & Security</strong>. These two concepts are related but different. Privacy refers to allowing people to go about their business privately and not spying on them or collecting more of their data than you absolutely need to. Security refers to constructing your website in a secure way so that malicious users cannot steal information contained on it from you or your users.</li> +</ul> + +<h2 dir="ltr" id="See_also">See also</h2> + +<ul dir="ltr"> + <li><a href="https://en.wikipedia.org/wiki/History_of_the_World_Wide_Web">History of the World Wide Web</a></li> + <li><a href="/en-US/docs/Learn/Common_questions/How_does_the_Internet_work">How does the internet work?</a></li> +</ul> diff --git a/files/ru/learn/getting_started_with_the_web/установка_базового_программного_обеспечения/index.html b/files/ru/learn/getting_started_with_the_web/установка_базового_программного_обеспечения/index.html new file mode 100644 index 0000000000..40b4254712 --- /dev/null +++ b/files/ru/learn/getting_started_with_the_web/установка_базового_программного_обеспечения/index.html @@ -0,0 +1,78 @@ +--- +title: Установка базового программного обеспечения +slug: Learn/Getting_started_with_the_web/Установка_базового_программного_обеспечения +tags: + - WebMechanics + - Браузер + - Интрументы + - Начинающий + - Новичку + - Обучение + - Текстовый редактор + - Установка +translation_of: Learn/Getting_started_with_the_web/Installing_basic_software +--- +<div> +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web")}}</div> +</div> + +<div class="summary"> +<p>В <em>Установке базового программного обеспечения</em>, мы покажем вам, какие инструменты вам необходимы для простой веб-разработки, и как правильно установить их.</p> +</div> + +<h2 id="Какие_инструменты_используют_профессионалы">Какие инструменты используют профессионалы?</h2> + +<ul> + <li><strong>Компьютер</strong>. Может быть, это звучит очевидно для некоторых людей, но некоторые из вас читают эту статью с телефона или библиотечного компьютера. Для серьезной веб-разработки, лучше приобрести настольный компьютер (Windows, Mac или Linux).</li> + <li><strong>Текстовый редактор</strong>, чтобы писать код. Это может быть текстовый редактор (например, <a href="https://code.visualstudio.com/">Visual Studio Code</a>, <a href="https://notepad-plus-plus.org/">Notepad++</a>, <a href="https://www.sublimetext.com/">Sublime Text</a>, <a href="https://atom.io/">Atom</a>, <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>, или <a href="https://www.vim.org/">VIM</a>) или гибридный редактор (например, <a href="https://www.adobe.com/products/dreamweaver.html">Dreamweaver </a>or <a href="https://www.jetbrains.com/webstorm/">WebStorm</a>). Офисные редакторы не подходят для этого, посколько они зависят от скрытых элементов, которые мешают движкам рендеринга, <span class="tlid-translation translation" lang="ru"><span title="">используемым веб-браузерами</span></span>.</li> + <li><strong>Веб-браузеры</strong>, для тестирования кода. В настоящее время наиболее часто используемые браузеры это <a href="https://www.mozilla.org/ru/firefox/new/">Firefox</a>, <a href="https://www.google.com/chrome/browser/">Chrome</a>, <a href="http://www.opera.com/">Opera</a>, <a href="https://www.apple.com/safari/">Safari</a>, и <a href="http://windows.microsoft.com/ru/internet-explorer/download-ie">Internet Explorer</a>. Вы также должны тестировать ваш сайт на то, как он работает на мобильных устройствах и на любых старых браузерах, которые ваша целевая аудитория может все ещё широко использовать (например, IE 6-8). <a href="https://lynx.browser.org/">Lynx</a>, текстовый веб-браузер для терминала, отлично подходит для того, чтобы увидеть, как ваш сайт воспринимается слабовидящими пользователями.</li> + <li><strong>Графический редактор</strong>, такие как <a href="http://www.gimp.org/">The Gimp</a>, <a href="http://www.getpaint.net/">Paint.NET</a>, или <a href="http://www.adobe.com/uk/products/photoshop.html">Photoshop</a>, чтобы создавать изображения для ваших веб-страниц.</li> + <li><strong>Система контроля версий</strong>, чтобы управлять файлами на сервере, для совместной работы над проектом с командой, обмениваться кодом и избегать редакторских конфликтов. Сейчас <a href="http://git-scm.com/">Git</a> является наиболее популярным инструментом контроля версий, и репозиторий кода <a href="https://github.com/">Github</a>, основанный на Git, также является очень популярным.</li> + <li><strong>FTP программа</strong>, чтобы загружать веб-страницы на сервер для публичного просмотра. Существует обилие таких программ, доступных в том числе <a href="https://cyberduck.io/">Cyberduck</a>, <a href="http://fetchsoftworks.com/">Fetch</a>, и <a href="https://filezilla-project.org/">FileZilla</a>.</li> + <li><strong>Система автоматизации</strong>, такая как <a href="http://gruntjs.com/">Grunt</a> или <a href="http://gulpjs.com/">Gulp</a>, для автоматического выполнения повторяющихся задач, например, минимизации кода и запуска тестов.</li> + <li>Шаблоны, библиотеки, фреймворки и т. д., чтобы ускорить написание общей функциональности.</li> + <li>А также некоторые другие инструменты!</li> +</ul> + +<h2 id="Какие_инструменты_на_самом_деле_нужны_мне_прямо_сейчас">Какие инструменты на самом деле нужны мне прямо сейчас?</h2> + +<p>Этот список выглядит страшновато, но, к счастью, вы можете начать веб-разработку, не зная ничего о большинстве из того, что в нем написано. В этой статье мы установим базовый минимум - текстовый редактор и некоторые современные веб-браузеры.</p> + +<h3 id="Установка_текстового_редактора">Установка текстового редактора</h3> + +<p>У вас, наверное, уже есть базовый текстовый редактор на вашем компьютере. По умолчанию Windows включает <a href="https://ru.wikipedia.org/wiki/%D0%91%D0%BB%D0%BE%D0%BA%D0%BD%D0%BE%D1%82_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0%29">Блокнот</a> и Mac OS X поставляется с <a href="https://ru.wikipedia.org/wiki/TextEdit">TextEdit</a>. Linux дистрибутивы варьируются; Ubuntu поставляется с <a href="https://ru.wikipedia.org/wiki/Gedit">gedit</a> по умолчанию.</p> + +<p>Для веб-разработки вам, вероятно, понадобится больше, чем могут предложить Notepad или TextEdit. Мы рекомендуем начать с <a href="https://www.sublimetext.com/"> </a><a href="https://code.visualstudio.com/">Visual Studio Code</a>, <span class="tlid-translation translation" lang="ru"><span title="">который является бесплатным редактором, который предлагает </span></span><span class="tlid-translation translation" lang="ru"><span title="">предварительный просмотр и подсказки во время написания кода.</span></span></p> + +<h3 id="Установка_современных_веб-браузеров">Установка современных веб-браузеров</h3> + +<p>На данный момент, мы установим только пару настольных веб-браузеров, чтобы проверять наш код. Выберите вашу операционную систему ниже и нажмите на соответствующие ссылки для загрузки установочных программ ваших любимых браузеров:</p> + +<ul> + <li>Linux: <a href="https://www.mozilla.org/ru/firefox/new/">Firefox</a>, <a href="https://www.google.com/chrome/browser/">Chrome</a>, <a href="http://www.opera.com/">Opera</a>, <a href="https://brave.com">Brave</a>.</li> + <li>Windows: <a href="https://www.mozilla.org/ru/firefox/new/">Firefox</a>, <a href="https://www.google.com/chrome/browser/">Chrome</a>, <a href="http://www.opera.com/">Opera</a>, <a href="http://windows.microsoft.com/ru/internet-explorer/download-ie">Internet Explorer</a>, <a href="https://brave.com">Brave</a> (Если у вас есть Windows 8 или выше, вы можете установить IE 10 или более позднюю версию; иначе, вам следует установить альтернативный браузер)</li> + <li>Mac: <a href="https://www.mozilla.org/ru/firefox/new/">Firefox</a>, <a href="https://www.google.com/chrome/browser/">Chrome</a>, <a href="http://www.opera.com/">Opera</a>, <a href="https://www.apple.com/safari/">Safari</a>, <a href="https://brave.com">Brave</a> (Safari постовляется с iOS и OS X по умолчанию)</li> +</ul> + +<p>Прежде, чем идти дальше, вам следует установить, по крайней мере, два из этих браузеров, чтобы использовать их для тестирования.</p> + +<h3 id="Установка_локального_веб-сервера">Установка локального веб-сервера</h3> + +<p>Некоторые примеры для успешной работы необходимо будет запустить на веб-сервере. Вы можете узнать, как это сделать в статье <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">How do you set up a local testing server?</a></p> + +<p>{{NextMenu("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового программного обеспечения</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">Каким должен быть ваш веб-сайт?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">Основы HTML</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/CSS_basics">Основы CSS</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">Основы JavaScript</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Публикация вашего веб-сайта</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Веб</a></li> +</ul> diff --git a/files/ru/learn/how_the_internet_works/index.html b/files/ru/learn/how_the_internet_works/index.html new file mode 100644 index 0000000000..19230a4042 --- /dev/null +++ b/files/ru/learn/how_the_internet_works/index.html @@ -0,0 +1,102 @@ +--- +title: Как работает Интернет +slug: Learn/How_the_Internet_works +tags: + - Начинающий + - Руководство + - Учебник + - туториал +translation_of: Learn/Common_questions/How_does_the_Internet_work +--- +<div>{{LearnSidebar}}</div> + +<div class="summary"> +<p>Эта статья о том, что такое Интернет, и как он работает.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Отсутствуют, но мы будем признательны, если вы сначала прочтете <a href="/en-US/docs/Learn/Thinking_before_coding">Материал о там как начать разрабатывать свой сайт</a></td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Вы изучите основы технической инфраструктуры Веба и поймете разницу между Вебом и интернетом. </p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Резюме">Резюме</h2> + +<p><strong>Интернет</strong> является основой сети (the Web), технической инфраструктурой, благодаря которой и существует Всемирная Паутина. По своей сути, интернет - очень большая сеть компьютеров, которые могут взаимодействовать друг с другом.</p> + +<p><a href="https://www.wikiwand.com/ru/%D0%98%D0%BD%D1%82%D0%B5%D1%80%D0%BD%D0%B5%D1%82#/.D0.98.D1.81.D1.82.D0.BE.D1.80.D0.B8.D1.8F" rel="external">История интернета не до конца ясна</a>. Проект по созданию интернета был начат в 60-х годах как исследовательский проект при поддержке министерства обороны США, но уже в 80-е годы вырос в сеть, которую поддерживали и развивали множество университетов и частных компаний. Технологии, лежащие в основе интернета, также продолжали развиваться со временем, но основной принцип работы не сильно изменился: Интернет - это способ подключить компьютеры в единую сеть и убедиться, что даже при серьезных сбоях, они все равно найдут способ связаться друг с другом.</p> + +<h2 id="Активное_изучение">Активное изучение</h2> + +<ul> + <li><a href="https://www.youtube.com/watch?v=7_LPdttKXPc">Как работает интернет за 5 минут</a>: 5-минутный видеоролик поможет вам понять базовые принципы работы интернета (автор Aaron Titus).</li> +</ul> + +<h2 id="Погружаемся_глубже">Погружаемся глубже</h2> + +<h3 id="Простая_сеть">Простая сеть</h3> + +<p>Когда нужно связать между собой два компьютера, вы должны связать их в сеть либо проводным (обычно с помощью <a href="https://ru.wikipedia.org/wiki/Коммутационный_шнур">Ethernet кабеля</a>), либо беспроводным способом (например, с помощью <a href="http://ru.wikipedia.org/wiki/WiFi" rel="external">WiFi</a> или <a href="http://ru.wikipedia.org/wiki/Bluetooth" rel="external">Bluetooth</a>). Современные компьютеры поддерживают любой из этих способов связи.</p> + +<div class="note"> +<p><strong>Примечание:</strong> До конца этой статьи мы будем говорить только о физическом (проводном) способе подключения, но беспроводные сети работают аналогичным образом.</p> +</div> + +<p><img alt="Two computers linked together" src="https://mdn.mozillademos.org/files/8441/internet-schema-1.png" style="height: 152px; width: 600px;"></p> + +<p>Таким способом Вы можете подключить более двух компьютеров, но с каждым новым это становится все сложнее. Если хочется подключить, скажем, 10 компьютеров, вам понадобится 45 кабелей и 9 сетевых плат в каждом компьютере!</p> + +<p><img alt="Ten computers all together" src="https://mdn.mozillademos.org/files/8443/internet-schema-2.png" style="height: 576px; width: 600px;"></p> + +<p>Чтобы решить эту проблему, каждый компьютер в сети подключается к специальному маленькому компьютеру. Этот компьютер называют <em>маршрутизатором</em>. Маршрутизатор исполняет только одну роль: как сигнальщик на железной дороге он следит за тем, чтобы пакет, отправленный одним компьютером — источником — достиг пункта назначения. Чтобы отправить сообщение компьютеру B, компьютер A сначала должен отправить его маршрутизатору, который перенаправит его компьютеру B и проконтролирует, чтобы данные не попали компьютеру C.</p> + +<p>С добавлением маршрутизатора наша сеть здорово упрощается: чтобы соединить 10 компьютеров нам требуется только 10 кабелей (каждый кабель соединяет маршрутизатор с одним из компьютеров).</p> + +<p><img alt="Ten computers with a router" src="https://mdn.mozillademos.org/files/8445/internet-schema-3.png" style="height: 576px; width: 600px;"></p> + +<h3 id="Сеть_сетей">Сеть сетей</h3> + +<p>Пока все нормально. Но что нам делать, если нужно объединить в сеть сотни, тысячи или миллиарды компьютеров? Конечно, один маршрутизатор не справится с этой задачей, но если вы внимательно читали, то помните, что маршрутизатор — это обычный компьютер, и ничто не мешает нам соединить друг с другом 2 маршрутизатора. Давайте сделаем это.</p> + +<p><img alt="Two routers linked together" src="https://mdn.mozillademos.org/files/8447/internet-schema-4.png"></p> + +<p>Подключая компьютеры к маршрутизатору, а затем — маршрутизатор к другому маршрутизатору, мы можем увеличивать нашу сеть до сколь угодно больших размеров.</p> + +<p><img alt="Routers linked to routers" src="https://mdn.mozillademos.org/files/8449/internet-schema-5.png" style="height: 563px; width: 600px;"></p> + +<p>Такая сеть уже очень похожа на то, что мы называем интернетом, но мы что-то упустили. Наша сеть построена для решения только наших задач. Но кроме нее есть и другие сети: наши друзья, соседи — кто угодно может создать свою сеть. Как же нам их объединить? Мы не можем протянуть кабели между нашим домом и всеми остальными сетями в мире. Чтобы решить эту проблему, мы можем воспользоваться уже существующими кабельными сетями. Ведь у нас дома уже есть кабели, например, электрические или телефонные. Телефонный провод уже соединяет ваш дом со всем остальным миром, так что он идеально подходит для решения нашей задачи. Чтобы подключить нашу сеть к глобальной сети с помощью телефонного провода, нам понадобится специальное оборудование, которое называется <em>модем</em>. Модем перекодирует информацию, поступающую из нашей сети в формат, который можно передавать через телефонную сеть, и наоборот, декодируют информацию из телефонной сети в формат, который распознают наши компьютеры.</p> + +<p><img alt="A router linked to a modem" src="https://mdn.mozillademos.org/files/8451/internet-schema-6.png" style="height: 340px; width: 600px;"></p> + +<p>Итак, мы подключились к телефонной сети. Следующий шаг — передать сообщение из нашей сети в сеть, с которой мы хотим связаться. Чтобы сделать это, мы должны подключить нашу сеть к провайдеру услуг интернета (Internet Service Provider (ISP)). Провайдер — компания, которая обслуживает специальные маршрутизаторы, которые не только подключены друг к другу (объединяют в единую сеть всех клиентов провайдера), но также связаны с маршрутизаторами других провайдеров. Таким образом, наше сообщение, пройдя транзитом через сеть нескольких провайдеров, достигнет сеть назначения. Интернет — это сеть сетей, которая объединяет в себе всю вышеперечисленную инфраструктуру.</p> + +<p><img alt="Full Internet stack" src="https://mdn.mozillademos.org/files/8453/internet-schema-7.png" style="height: 1293px; width: 340px;"></p> + +<h3 id="Поиск_компьютера">Поиск компьютера</h3> + +<p>Чтобы послать сообщение какому-то компьютеру, необходимо как-то обратиться к нему, выделить среди других. Поэтому каждый компьютер, подключенный к сети, имеет свой уникальный адрес для связи: этот адрес называют IP-адресом (IP — сокращение для <em>Internet Protocol</em>, протокол интернета). В зависимости от версии протокола IP этот адрес может записываться по-разному. Самая широко используемая версия интернет-протокола — версия 4. Адреса IPv4 обычно записываются в виде четырёх чисел, разделенных точками, например: 192.168.2.10.</p> + +<p>Такие адреса отлично подходят для компьютеров, но людям очень сложно их запоминать. Чтобы упростить себе жизнь, мы можем присвоить каждому IP-адресу псевдоним с понятным для человека именем. Такой псевдоним называют доменным именем. Например, google.com — доменное имя, которое является псевдонимом IP-адреса 173.194.121.32. Использование доменного имени — самый простой способ обратиться к компьютеру в интернете.</p> + +<p><img alt="Show how a domain name can alias an IP address" src="https://mdn.mozillademos.org/files/8405/dns-ip.png" style="height: 160px; width: 330px;"></p> + +<h3 id="Интернет_и_веб">Интернет и веб</h3> + +<p>Как вы уже заметили, когда мы просматриваем Веб с помощью браузера, обычно мы используем доменное имя, чтобы обратиться к веб-сайту. Означает ли это, что Интернет и Веб — это одно и то же? Ответ не так прост. Мы уже знаем, что Интернет — это техническая основа, которая позволяет миллиардам компьютеров связываться друг с другом. Среди этих компьютеров есть небольшая группа (называемая веб-серверами), которые могут отправлять сообщения, распознаваемые браузерами. <em>Интернет</em> — это инфраструктура, а <em>Веб</em> — это сервис, построенный на основе этой инфраструктуры. Стоит отметить, что кроме Веба есть и другие сервисы, построенные на базе Интернета. Например, электронная почта или {{Glossary("IRC")}}.</p> + +<h2 id="Что_дальше">Что дальше</h2> + +<ul> + <li><a href="/ru/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает Веб</a></li> + <li><a href="/ru/docs/Learn/Pages_sites_servers_and_search_engines">Понимание разницы между веб-страницей, веб-сайтом, веб-сервером и поисковиком</a></li> + <li><a href="/ru/docs/Learn/Understanding_domain_names">Что такое доменные имена</a></li> +</ul> diff --git a/files/ru/learn/html/forms/how_to_build_custom_form_widgets/index.html b/files/ru/learn/html/forms/how_to_build_custom_form_widgets/index.html new file mode 100644 index 0000000000..8a4ca2d6b8 --- /dev/null +++ b/files/ru/learn/html/forms/how_to_build_custom_form_widgets/index.html @@ -0,0 +1,792 @@ +--- +title: Как создавать пользовательские виджеты форм +slug: Learn/HTML/Forms/How_to_build_custom_form_widgets +tags: + - HTML + - Web + - Пример + - Продвинутый + - Руководство + - Формы +translation_of: Learn/Forms/How_to_build_custom_form_controls +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/Form_validation", "Learn/HTML/Forms/Sending_forms_through_JavaScript", "Learn/HTML/Forms")}}</div> + +<p class="summary">Существует много случаев, когда возможностей <a href="/ru/docs/Learn/HTML/Forms/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5_%D0%B2%D0%B8%D0%B4%D0%B6%D0%B5%D1%82%D1%8B_%D1%84%D0%BE%D1%80%D0%BC">стандартных виджетов HTML форм</a> недостаточно. Если вы хотите <a href="/en-US/docs/Advanced_styling_for_HTML_forms">придать лучший вид</a> каким-либо виджетам как, например, {{HTMLElement("select")}}, или вы хотите создать особое поведение виджета, то у вас нет другого выбора, кроме как создать собственные виджеты.</p> + +<p>В этой статье мы рассмотрим как создать такой виджет. Для этого мы возьмем пример: переделка элемента {{HTMLElement("select")}} .</p> + +<div class="note"> +<p><strong>Замечание:</strong> Мы сфокусируемся на создании виджетов, а не на том чтобы сделать код универсальным и многоразовым; поэтому будут использоваться некоторый нетривиальный JavaScript код и манипуляции DOM в неизвестном контексте, что выходит за рамки этой статьи.</p> +</div> + +<h2 id="Дизайн_структура_и_семантика">Дизайн, структура и семантика</h2> + +<p>В начале создания пользовательского виджета необходимо обрисовать что именно вы хотите. Это сэкономит драгоценное время. Особенно важно четко определить все состояния вашего виджета. Чтобы это сделать, лучше начать с существущего виджета, состояния и реакции которго хорошо известны, так что вы сможете просто подражать им насколько это возможно.</p> + +<p>В нашем примере мы будем переделывать элемент {{HTMLElement("select")}}. Вот такой результат мы хотим достичь:</p> + +<p><img alt="The three states of a select box" src="/files/4481/custom-select.png" style="height: 135px; width: 366px;"></p> + +<p>Этот скриншот показывает три основных состояния нашего виджета: нормальное состояние (слева); активное состояние (посередине) и развернутое состояние (справа).</p> + +<p>С точки зрения реакций нужно чтобы наш виджет взаимодействовал как с мышью, так и с клавиатурой, так же как и стандартный виджет. Давайте сначала определим, как виджет приходит в каждое состояние:</p> + +<dl> + <dt>Виджет в нормальном состоянии когда:</dt> + <dd> + <ul> + <li>страница загружается</li> + <li>виджет был активным и пользователь кликает где-то вне виджета</li> + <li>виджет был активным и пользователь перемещает фокус на другой виджет при помощи клавиатуры</li> + </ul> + + <div class="note"> + <p><strong>Замечание:</strong> Перемещение фокуса по странице обычно осуществялется клавишей "tab", но не везде. Например в Safari циклический переход между ссылками на странице осуществляется по усмолчанию <a href="http://www.456bereastreet.com/archive/200906/enabling_keyboard_navigation_in_mac_os_x_web_browsers/">комбинацией Option+Tab</a>.</p> + </div> + </dd> + <dt>Виджет в активном состоянии когда:</dt> + <dd> + <ul> + <li>пользователь кликает на него</li> + <li>пользователь нажимает клавишу Tab, и он получает фокус</li> + <li>виджет был в развернутом состоянии и позователь кликает на виджет.</li> + </ul> + </dd> + <dt>Виджет в развернутом состоянии:</dt> + <dd> + <ul> + <li>виджет в любом другом состоянии и пользователь кликает на него</li> + </ul> + </dd> +</dl> + +<p>Теперь, когда мы знаем, как изменяются состояния, важно определить, как изменить значение виджета:</p> + +<dl> + <dt>Значение изменяется когда:</dt> + <dd> + <ul> + <li>пользователь кликает на один-из-вариантов когда виджет в развернутом состоянии</li> + <li>пользователь нажимает клавиши стрелка вверх или вниз когда виджет в активном состоянии</li> + </ul> + </dd> +</dl> + +<p>Наконец, давайте определим, как будут вести себя варианты виджета:</p> + +<ul> + <li>когда виджет развернут, выбранный вариант подсвечен</li> + <li>когда курсор мыши находится над вариантом, он подсвечен и ранее подсвеченный вариант возвращается в его обычное состояние</li> +</ul> + +<p>Для нашего примера остановимся на этом; но, если вы внимательный читатель, вы заметите, что некоторые реакции отсутствуют. Например, как вы думаете, что произойдет если пользователь нажмет клавишу "tab" когда виджет в развернутом состоянии? Ответом будет... ничего. OK, правильная реакция кажется очевидной, но поскольку она не определена в наших спецификациях, то очень легко пропустить реализацию этой реакции. Это особенно верно для командной работы, когда те, кто опеределяет какими должны быть реакции виджета сами не реализуют их.</p> + +<p>Другой забавный пример: что произойдет, если пользователь нажмет клавишу вверх или вниз когда виджет находитися в развернутом состоянии? Это немного сложнее. Если вы предположите, что активное и развернутое состояние полностью различны, то ответом снова будет "ничего не произойдет" , потому что мы не определили никаких взаимодействий с клавиатурой в открытом состоянии. С другой стороны, если вы предположите, что активное и развернутое состояние немного похожи, значение может изменится, но выбранный вариант точно не будет соответственно подсвечен, опять же потому, что мы не определили никаких действий с клавиатуры над вариантами когда виджет находится в развернутом состоянии (мы определили только то, что произойдет, когда виджет развернется, но ничего более).</p> + +<p>В нашем примере пропущенные спецификации очевидны, так что мы с ними справимся, но это может стать реальной проблемой для новых экзотических виджетов, когда никто не имеет ни малейшего представления о том как они должны реагировать. Всегда лучше потратить время на этом этапе дизайна, потому что если вы плохо определите, или забудете определить реакцию виджета, то будет очень сложно изменять ее, когда пользователи уже привыкнут. Если у вас есть сомнения - спросите мнения у окружающих, и, если позволяет бюджет, не стесняйтесь <a href="https://ru.wikipedia.org/wiki/%D0%AE%D0%B7%D0%B0%D0%B1%D0%B8%D0%BB%D0%B8%D1%82%D0%B8-%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5">выполнять пользовательские тесты</a>. Этот процесс называется UX Design (<a href="https://ru.wikipedia.org/wiki/%D0%94%D0%B8%D0%B7%D0%B0%D0%B9%D0%BD_%D0%B2%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D1%8F_%D1%81_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D0%B5%D0%BC">Дизайн взаимодействия с пользователем</a>). Если вы хотите узнать больше об этой теме, вам следует посетить следующие полезные ресурсы:</p> + +<ul> + <li><a href="http://www.uxmatters.com/" rel="external" title="http://www.uxmatters.com/">UXMatters.com</a></li> + <li><a href="http://uxdesign.com/" rel="external" title="http://uxdesign.com/">UXDesign.com</a></li> + <li><a href="http://uxdesign.smashingmagazine.com/" rel="external" title="http://uxdesign.smashingmagazine.com/">The UX Design section of SmashingMagazine</a></li> +</ul> + +<div class="note"> +<p><strong>Замечание: </strong>Также, в большинстве систем, есть способ развернуть элемент {{HTMLElement("select")}} чтобы посмотреть все доступные варианты (это то-же что кликнуть мышью элемент {{HTMLElement("select")}} ). Это возможно комбинацией Alt+Стрелка вниз для Windows и не реализовано в нашем примере —но это будет просто сделать, так как механизм уже реализован дл события <code>click</code>.</p> +</div> + +<h3 id="Определение_структуры_и_семантики_HTML">Определение структуры и семантики HTML</h3> + +<p>Теперь, когда основной функционал виджета определен, пора начать создание виджета. Первым делом определим его HTML структуру и придадим основную семантику. Вот все что нам нужно чтобы переделать элемент {{HTMLElement("select")}}:</p> + +<pre class="brush: html"><!-- Это основной контейнер для нашего виджета. + Аттрибут tabindex позволяет пользователю переместить фокус на виджет. + Позже мы увидим, что лучше его установить через JavaScript. --> +<div class="select" tabindex="0"> + + <!-- Этот контейнер послужит для отображения текущего значения виджета --> + <span class="value">Cherry</span> + + <!-- Этот контейнер содержит все варинты. доступные для нашего виджета. + Так как это список, то есть смысл использовать элемент ul. --> + <ul class="optList"> + <!-- Каждый вариант содержит то значение, которое будет отображено, позже мы увидим + как получить то значение, которое будет отппралено вместе с данными формы --> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> + +</div></pre> + +<p>Обратите внимание на использование имен классов: они описывают каждый соответствующий элемет независимо от фактически используемых базовых элементов HTML. Важно быть уверенными что нам не придется жестко привязывать наши CSS и JavaScript к HTML структуре,тогда мы сможем позже вносить изменения не нарушая код виджета. Например, если вы захотите создать эквивалент элемента {{HTMLElement("optgroup")}}.</p> + +<h3 id="Создание_внешнего_вида_с_помощью_CSS">Создание внешнего вида с помощью CSS</h3> + +<p>Теперь у нас есть структура и мы можем заняться дизайном нашего виджета. Весь смысл создания нашего собственного виджета в том, чтобы мы могли придать ему такой внешний вид, как мы захотим. Поэтому мы разделим нашу работу с CSS на две части: в первой части будут правила CSS абсолютно необходимые чтобы реакции нашего виджета были как у элемента {{HTMLElement("select")}} , а вторая чать будет состоять из красивеньких рюшечек, чтобы виджет выглядел так, как нам нравится.</p> + +<h4 id="Обязательные_стили">Обязательные стили</h4> + +<p>Обязательные стили - это те, которые необходимы для обработки трех состояний нашего виджета..</p> + +<pre class="brush: css">.select { + /* Это создаст контекст позиционирования для списка вариантов */ + position: relative; + + /* Это сделает наш виджет частью текстового потока и одновременно сделает его + изменяемого размера */ + display : inline-block; +}</pre> + +<p>Еще нам нужен дополнительный класс <code>active,</code> чтобы определить, как будет выглядеть наш виджет в активном состоянии. Так как наш виджет может находится в фокусе, то мы укажем этот стиль еще и для псевдокласса {{cssxref(":focus")}} чтобы быть уверенными, что виджет будет вести себя одинаково.</p> + +<pre class="brush: css">.select .active, +.select:focus { + outline: none; + + /* Это свойство - box-shadow - необязательно, однако нам важно видеть активное состояние + т.к. мы используем его по умолчанию. Можете спокойно его переопределить. */ + box-shadow: 0 0 3px 1px #227755; +}</pre> + +<p>Теперь давайте стилизуем список опций:</p> + +<pre class="brush: css">/* Селектор .select здесь применен для удобства (<a href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D1%81%D0%B0%D1%85%D0%B0%D1%80">синтаксический сахар</a>), чтобы быть уверенными, + что определяемые классы находятся в нашем виджете. */ +.select .optList { +/* Это позволит нам быть уверенными, что список вариантов будет показан ниже значения + и вне HTML потока */ + position : absolute; + top : 100%; + left : 0; +}</pre> + +<p>Еще нам нужен дополнительный класс, для обращения к списку вариантов, когда он скрыт. Это необходимо чтобы справиться с различиями активного и развернутого состояния, т.к. они не совсем совпадают.</p> + +<pre class="brush: css">.select .optList.hidden { + /* Это самый простой из доступных способов путь скрыть список, + а о доступности мы еще поговрим в конце */ + max-height: 0; + visibility: hidden; +}</pre> + +<h4 id="Украшательства">Украшательства</h4> + +<p>Теперь, когда основная функциональность на месте, можем начинать развлекаться. То, что мы сделаем дальше, является всего лишь примером того, что возможно, и будет соответствовать скриншоту в начале этой статьи. Но вы можете свободно эксперементировать и посмотреть на что вы способны.</p> + +<pre class="brush: css">.select { + /* Все размеры будут выражены в em по соображениям удобства + (чтобы быть уверенными, что виджет будет изменять размер если пользователь будет + использовать увеличение в текстовом режиме браузера). Вычисления сделаны из расчета что + 1em == 16px что является умолчанием для большинства браузеров. + Если вы затрудняетесь с преобразованием px в em, попробуйте http://riddle.pl/emcalc/ */ + font-size : 0.625em; /* это (10px) новый размер шрифта для нашего контекста для значения + em в исходном контексте */ + font-family : Verdana, Arial, sans-serif; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + /* Нам нужно добавить дополнительное пространство для стрелки вниз */ + padding : .1em 2.5em .2em .5em; /* 1px 25px 2px 5px */ + width : 10em; /* 100px */ + + border : .2em solid #000; /* 2px */ + border-radius : .4em; /* 4px */ + box-shadow : 0 .1em .2em rgba(0,0,0,.45); /* 0 1px 2px */ + + /* Первое объявление - для бразуеров не поддерживающих линейный градиент. + Второе объявление - потому что основанные на WebKit браузеры еще не избавились от префикса в нем. + Если вам нужна поддержка устаревших браузеров, попробуйте http://www.colorzilla.com/gradient-editor/ */ + background : #F0F0F0; + background : -webkit-linear-gradient(90deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); + background : linear-gradient(0deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); +} + +.select .value { + /* Так как значение может быть шире, чем наш виджет, нужно быть уверенными, что оно не изменит + ширину виджета */ + display : inline-block; + width : 100%; + overflow : hidden; + + vertical-align: top; + + /* И, если содержимое слишком длинное, лучше иметь красивенькие точечки. */ + white-space : nowrap; + text-overflow: ellipsis; +}</pre> + +<p>Нам не нужен дополнительный элемент, чтобы создать стрелку вниз; вместо этого мы используем псевдоэлемент {{cssxref(":after")}}. Также её можно создать при помощи простого фонового изображения в классе <code>select</code>.</p> + +<pre class="brush: css">.select:after { + content : "▼"; /* Мы используем Unicode символ U+25BC; смотрите http://www.utf8-chartable.de */ + position: absolute; + z-index : 1; /* Важно чтобы стрелка не перекрывала элементы списка */ + top : 0; + right : 0; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + height : 100%; + width : 2em; /* 20px */ + padding-top : .1em; /* 1px */ + + border-left : .2em solid #000; /* 2px */ + border-radius: 0 .1em .1em 0; /* 0 1px 1px 0 */ + + background-color : #000; + color : #FFF; + text-align : center; +}</pre> + +<p>Далее стилизуем список вариантов:</p> + +<pre class="brush: css">.select .optList { + z-index : 2; /* Мы явно сказали, что список вариантов всегда будет перекрывать стрелку вниз */ + + /* это сбросит значения стиля по умолчанию для элемента ul */ + list-style: none; + margin : 0; + padding: 0; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + /* Это для того, чтобы убедиться что если значения будут короче виджета + то список вариантов останется таким же по размеру как и сам виджет */ + min-width : 100%; + + /* В случае, если список слишком длинный, его содержимое не будет помещаться по вертикали + (что автоматически добавит полосу прокрутки), но этого никогда не произойдет по горизонтали + (потому что мы не установили ширину и содержимое списка будет регулировать ее + автоматически. Если это будет невозможно - содержимое будет обрезано.) */ + max-height: 10em; /* 100px */ + overflow-y: auto; + overflow-x: hidden; + + border: .2em solid #000; /* 2px */ + border-top-width : .1em; /* 1px */ + border-radius: 0 0 .4em .4em; /* 0 0 4px 4px */ + + box-shadow: 0 .2em .4em rgba(0,0,0,.4); /* 0 2px 4px */ + background: #f0f0f0; +}</pre> + +<p>Для вариантов нам нужно добавить класс <code>highlight</code> чтобы сделать возможным индентифицировать значение которе пользователь выберет (или выбрал).</p> + +<pre class="brush: css">.select .option { + padding: .2em .3em; /* 2px 3px */ +} + +.select .highlight { + background: #000; + color: #FFFFFF; +}</pre> + +<p>Итак, вот результат с нашими тремя состояниями:</p> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">Основное состояние</th> + <th scope="col" style="text-align: center;">Активное состояние</th> + <th scope="col" style="text-align: center;">Развернутое состояние</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("Basic_state",120,130, "", "HTML/Forms/How_to_build_custom_form_widgets/Example_1")}}</td> + <td>{{EmbedLiveSample("Active_state",120,130, "", "HTML/Forms/How_to_build_custom_form_widgets/Example_1")}}</td> + <td>{{EmbedLiveSample("Open_state",120,130, "", "HTML/Forms/How_to_build_custom_form_widgets/Example_1")}}</td> + </tr> + <tr> + <td colspan="3" style="text-align: center;"><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_1" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_1">Посмотреть исходный код</a></td> + </tr> + </tbody> +</table> + +<h2 id="Оживи_свой_виджет_с_JavaScript">Оживи свой виджет с JavaScript</h2> + +<p>Теперь, когда наш дизайн и структура готовы, мы можем написать код на JavaScript чтобы виджет действительно заработал.</p> + +<div class="warning"> +<p><strong>Предупреждение:</strong> Следующий код представлен в образовательных целях и не может быть использован как-есть. Помимо прочего, как мы убедимся, он не пригоден для дальнейшего развития и не будет работать в устаревших браузерах. В нем также есть избыточность которую необходимо оптимизировать использования в рабочем режиме.</p> +</div> + +<div class="note"> +<p><strong>Замечание:</strong> Создание многократно используемых виджетов может быть немного сложнее. <a href="http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html" rel="external" title="http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html">W3C Web Component draft</a> является одним из ответов на этот конкретный вопрос. <a href="http://x-tags.org/" rel="external" title="http://x-tags.org/">The X-Tag project</a> попытка реализовать эту спецификацию; пожалуйста, посмотрите этот проект.</p> +</div> + +<h3 id="Почему_он_не_работает">Почему он не работает?</h3> + +<p>Прежде чем мы начнем, запомните одну важную вещь о JavaScript: в браузере <strong>это ненадежная технология</strong>. Когда вы создаете пользовательские виджеты, вы будете полагаться на JavaScript потому что это необходимое звено для связки. Однако во многих случаях JavaScript невозможно запустить в браузере:</p> + +<ul> + <li>Пользователь отключил JavaScript: Это самый редкий случай; сейчас очень мало людей отключают JavaScript.</li> + <li>Скрипт не загружается. Это один из самых распространенных случаев, особенно в мобильном мире, где сеть не очень надежная.</li> + <li>Скрипт глючит.Вы должны всегда учитывать эту возможность.</li> + <li>Скрипт конфликтует со сторонним скриптом. Это может случиться со скриптами отслеживания или любыми закладурками (bookmarklets), которые использует пользователь.</li> + <li>Скрипт конфликтует с расширением браузера или зависит от него (такими как расширение <a href="https://addons.mozilla.org/fr/firefox/addon/noscript/" rel="external" title="https://addons.mozilla.org/fr/firefox/addon/noscript/">NoScript</a> в Firefox, или расширенние <a href="https://chrome.google.com/webstore/detail/notscripts/odjhifogjcknibkahlpidmdajjpkkcfn" rel="external" title="https://chrome.google.com/webstore/detail/notscripts/odjhifogjcknibkahlpidmdajjpkkcfn">NotScripts</a> в Chrome).</li> + <li>Пользователь использует устаревший браузер, и одна из требуемых функций не поддерживается. Это часто случается, когда вы используете передовые API.</li> +</ul> + +<p>Из-за этого очень важно серьезно подумать о том, что произойдет, если JavaScript не сработает. Детальное рассмотрение этой проблемы выходит за рамки данной статьи, поскольку эта проблема тесно связана с тем, насколько универсальным и многократно используемым вы хотите сделать свой сценарий, но мы рассмотрим основы этого в нашем примере.</p> + +<p>В нашем примере, если наш JavaScript код не работает, мы используем стандартный элемент {{HTMLElement("select")}}. Для этого, нам нужны две вещи.</p> + +<p>Во-первых нам нужно добавить стандартный элемент {{HTMLElement("select")}} перед каждым использованием нашего пользовательского виджета. Это также необходимо, чтобы отправить данные из нашего пользовательского виджета вместе с остальными данными формы; подробнее рассмотрим это позже.</p> + +<pre class="brush: html"><body class="no-widget"> + <form> + <select name="myFruit"> + <option>Cherry</option> + <option>Lemon</option> + <option>Banana</option> + <option>Strawberry</option> + <option>Apple</option> + </select> + + <div class="select"> + <span class="value">Cherry</span> + <ul class="optList hidden"> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> + </div> + </form> + +</body></pre> + +<p>Во-вторых нам нужно два новых класса, чтобы скрыть ненужные элементы (то есть "настоящие" элементы {{HTMLElement("select")}}, если скрипт запустился, или наш пользовательский виджет, если скрипт не запустился). По умолчанию наш HTML код скрывает наш пользовательский виджет.</p> + +<pre class="brush: css">.widget select, +.no-widget .select { + /* Этот CSS селектор значит: + - или мы присваиваем классу body значение "widget" и таким образом мы скрываем элемент {{HTMLElement("select")}} + - или мы не меняем класс body, тогда класс body остается в значении "no-widget", + и элементы, чей класс "select" будут скрыты */ + position : absolute; + left : -5000em; + height : 0; + overflow : hidden; +}</pre> + +<p>Теперь нам нужен модуль JavaScript, чтобы определить, запущен скрипт или нет. Этот модуль очень простой: если наш скрипт запустится во время загрузки страницы, то он удалит класс класс <code>no-widget</code> и добавит класс <code>widget</code>, чем поменяет видимость элемента {{HTMLElement("select")}} и нашего пользовательского виджета.</p> + +<pre class="brush: js">window.addEventListener("load", function () { + document.body.classList.remove("no-widget"); + document.body.classList.add("widget"); +});</pre> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">Без JS</th> + <th scope="col" style="text-align: center;">С JS</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("No_JS",120,130, "", "HTML/Forms/How_to_build_custom_form_widgets/Example_2")}}</td> + <td>{{EmbedLiveSample("JS",120,130, "", "HTML/Forms/How_to_build_custom_form_widgets/Example_2")}}</td> + </tr> + <tr> + <td colspan="2" style="text-align: center;"><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_2" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_2">Посмотреть исходный код</a></td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Замечание:</strong> Если вы действительно хотите сделать свой код универсальным и многоразовым, то вместо переключения классов гораздо лучше просто добавить класс элементам {{HTMLElement("select")}} чтобы их скрыть, и динамически добавлять дерево DOM представляющее пользовательский виджет после каждого элемента {{HTMLElement("select")}} на странице.</p> +</div> + +<h3 id="Облегчение_работы">Облегчение работы</h3> + +<p>В коде который мы собираемся написать, для выполнения всех необходимых действий мы будем использовать стандартный DOM API. Однако, хотя поддержка DOM API в браузерах стала гораздо лучше, все еще есть нюансы с устраевшеними браузерами (особенно со старым добрым Internet Explorer).</p> + +<p>Чтобы избежать неприятностей с устаревшими браузерами есть два способа: использовать отдельный фреймворк такой как <a href="http://jquery.com/" rel="external" title="http://jquery.com/">jQuery</a>, <a href="https://github.com/julienw/dollardom" rel="external" title="https://github.com/julienw/dollardom">$dom</a>, <a href="http://prototypejs.org/" rel="external" title="http://prototypejs.org/">prototype</a>, <a href="http://dojotoolkit.org/" rel="external" title="http://dojotoolkit.org/">Dojo</a>, <a href="http://yuilibrary.com/" rel="external" title="http://yuilibrary.com/">YUI</a>, и т.п., или самостоятельно реализовать недостающие функции которые вам нужны (что можно легко сделать через условную загрузку, например используя библиотеку <a href="http://yepnopejs.com/" rel="external" title="http://yepnopejs.com/">yepnope</a>).</p> + +<p>Мы планируем использовать следующие функции (от самых рискованных до самых безопасных):</p> + +<ol> + <li>{{domxref("element.classList","classList")}}</li> + <li>{{domxref("EventTarget.addEventListener","addEventListener")}}</li> + <li><code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach" title="/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach">forEach</a></code> (This is not DOM but modern JavaScript)</li> + <li>{{domxref("element.querySelector","querySelector")}} and {{domxref("element.querySelectorAll","querySelectorAll")}}</li> +</ol> + +<p>Помимо доступности этих специфических функций, остается еще одна проблема чтобы начать. Объект возвращаемый функцией {{domxref("element.querySelectorAll","querySelectorAll()")}} имеет тип {{domxref("NodeList")}} что отличается от <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Array" title="/en-US/docs/JavaScript/Reference/Global_Objects/Array">Array</a></code>. Это важно потому, что объекты <code>Array</code> поддерживают функцию <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach" title="/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach">forEach</a></code>, а {{domxref("NodeList")}} не поддерживает. Так как {{domxref("NodeList")}} очень похож на <code>Array</code> и нам очень удобно использовать <code>forEach</code>, мы можем просто добавить <code>forEach</code> к объекту {{domxref("NodeList")}} чтобы облегчить нам жизнь, например так:</p> + +<pre class="brush: js">NodeList.prototype.forEach = function (callback) { + Array.prototype.forEach.call(this, callback); +}</pre> + +<p>Мы не шутили, когда сказали, что это легко сделать.</p> + +<h3 id="Создание_процедур_обработки_событий">Создание процедур обработки событий</h3> + +<p>Итак, начало положено, и мы можем приступить к функциям, которые будут использоваться для взаимодействия с пользователем.</p> + +<pre class="brush: js">// Эта функция будет вызываться каждый раз, когда наш виджет будет деактивирован +// Ей передается один параметр +// select : DOM нода класса `select` который должен быть деактивирован +function deactivateSelect(select) { + + // Если виджет не активен, то и делать-то нечего + if (!select.classList.contains('active')) return; + + // Получаем список опций для нашего виджета + var optList = select.querySelector('.optList'); + + // Закрываем список опций + optList.classList.add('hidden'); + + // и деактивируем сам виджет + select.classList.remove('active'); +} + +// Эта функция бедт вызываться какждый раз, когда пользователь захочет (де)активровать наш виджет +// Ей передаются два параметра: +// select : DOM нода класса `select` для активации +// selectList : список всех DOM нод с классом `select` +function activeSelect(select, selectList) { + + // Если виджет активен, то и делать-то нечего + if (select.classList.contains('active')) return; + + // Нам нужно отключить активное состояние всех наших виджетов + // Так как функция deactivateSelect соответствует всем требованиям + // функции forEach мы вызываем ее без использования промежуточной анонимной функции + selectList.forEach(deactivateSelect); + + // А теперь мы возвращаем активное состояние нужного виджета + select.classList.add('active'); +} + +// Эта функция будет вызываться каждый раз, когда пользователь будет открывать/закрывать список вариантов +// Ей передается один параметр: +// select : DOM нода со списком для переключения состояния +function toggleOptList(select) { + + // Список хранится в виджете + var optList = select.querySelector('.optList'); + + // Мы меняем класс виджета чтобы показать/скрыть его + optList.classList.toggle('hidden'); +} + +// Эта функция будет вызываться каждый раз, когда нам нужно подсветить вариант +// Ей передаются два параметра: +// select : DOM нода класса `select` содержащая вариант для подсветки +// option : DOM нода класса `option` для подсветки +function highlightOption(select, option) { + + // Мы получаем список всех вариантов доступных в нашем элементе + var optionList = select.querySelectorAll('.option'); + + // Мы удаляем подсветку всех вариантов + optionList.forEach(function (other) { + other.classList.remove('highlight'); + }); + + // Подсвечиваем нужный вариант + option.classList.add('highlight'); +};</pre> + +<p>Это все, что вам нужно для обработки различных состояний пользовательского виджета.</p> + +<p>Далее мы связываем эти функции с соответствующими событиями:</p> + +<pre class="brush: js">// Мы обрабатываем событие при загрузке документа. +window.addEventListener('load', function () { + var selectList = document.querySelectorAll('.select'); + + // Каждый наш собственный виджет должен быть проинициализирован + selectList.forEach(function (select) { + + // также как и его элементы `option` + var optionList = select.querySelectorAll('.option'); + + // Когда пользователь проводит мышью над элементом `option`, мы подсвечиваем этот вариант + optionList.forEach(function (option) { + option.addEventListener('mouseover', function () { + // Замечание: использование переменных `select` и `option` + // ограничено рамками нашей функции. + highlightOption(select, option); + }); + }); + + // Когда позоватль кликает на наш виджет + select.addEventListener('click', function (event) { + // Замечание: использование переменной `select` + // ограничено рамками нашей функции. + + // Мы переключаем видимость списка вариантов + toggleOptList(select); + }); + + // Когда виджет получает фокус + // Виджет получает фокус когда пользователь кликает на него + // или переходит на него клавишей табуляции + select.addEventListener('focus', function (event) { + // Замечание: использование переменных `select` и `selectList` + // ограничено рамками нашей функции. + + // Мы активируем наш виджет + activeSelect(select, selectList); + }); + + // Когда виджет теряет фокус + select.addEventListener('blur', function (event) { + // Замечание: использование переменной `select` + // ограничено рамками нашей функции. + + // Мы деактивируем виджет + deactivateSelect(select); + }); + }); +});</pre> + +<p>В этот момент наш виджет будет изменятт состояние в соответствии с нашим дизайном, но не будет обновлять его значение. С этим мы разберемся дальше.</p> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">Пример</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("Change_states",120,130, "", "HTML/Forms/How_to_build_custom_form_widgets/Example_3")}}</td> + </tr> + <tr> + <td style="text-align: center;"><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_3" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_3">Посмотреть исходный код</a></td> + </tr> + </tbody> +</table> + +<h3 id="Обработка_значения_виджета">Обработка значения виджета</h3> + +<p>Теперь, когда наш виджет работает, мы должны добавить код, чтобы обновить его значение в соответствии с выбором пользователя и сделать возможным отправку этого значения вместе с данными формы.</p> + +<p>Самый простой способ сделать это - использовать встроенный виджет который также есть в нашей форме. Такой виджет будет отслеживать значение со всеми встроенными элементами управления, предоставленными браузером, и значение будет отправлено, как обычно, при отправке формы. Нет смысла заново изобретать велосипед, когда все это уже сделано за нас.</p> + +<p>Как было показано ранее, у нас есть стандартный виджет {{HTMLElement("select")}} в качестве запасного варианта для повышения доступности; поэтому мы просто синхронизируем его значение с нашим собственнным виджетом:</p> + +<pre class="brush: js">// Эта функция обновляет отображенное значение и синхронизирует его со стандартным виджетом +// Ей передается два параметра: +// select : DOM нода класса `select` содержащая значение которое будет обновлено +// index : индекс выбранного значения +function updateValue(select, index) { + // Нам нужно получить стандартный виджет для данного пользовательского + // В нашем примере стандартный виджет является братом (sibling) пользовательского виджета + var nativeWidget = select.previousElementSibling; + + // Нам также нужно получить значение заполнителя нашего пользовательского виджета + var value = select.querySelector('.value'); + + // И нам нужен весь список вариантов + var optionList = select.querySelectorAll('.option'); + + // Установим значение текущего номера выбранного элемента равным index + nativeWidget.selectedIndex = index; + + // Соответственно установим значение заполнителя + value.innerHTML = optionList[index].innerHTML; + + // И мы подсвечиваем соответствующий вариант нашего пользовательского виджета + highlightOption(select, optionList[index]); +}; + +// Эта функция возвращает текущий номер выбранного элемента в стандартном виджете +// Ей передается один параметр: +// select : DOM нода класса `select` соответствующая стандарному виджету +function getIndex(select) { + // Нам нужно получить доступ к стандартному виджету соответствующему данному + // пользовательскому виджету + // В нашем примере стандартный виджет - брат (sibling) пользовательского виджета + var nativeWidget = select.previousElementSibling; + + return nativeWidget.selectedIndex; +};</pre> + +<p>Исползуя эти две функции мы можем связать стандартный виджет с пользовательским:</p> + +<pre class="brush: js">// Мы обрабатываем привязку события при загрузке документа. +window.addEventListener('load', function () { + var selectList = document.querySelectorAll('.select'); + + // Каждый пользовательский виджет необходимсо инциализировать: + selectList.forEach(function (select) { + var optionList = select.querySelectorAll('.option'), + selectedIndex = getIndex(select); + + // Мы делаем наш пользовательский виджет фокусируемым + select.tabIndex = 0; + + // Мы делаем стандартный виджет более не фокусируемым + select.previousElementSibling.tabIndex = -1; + + // Убеждаемся, что выбранное по умолчанию значение корректно отображено + updateValue(select, selectedIndex); + + // Кажды раз когда пользователь кликает на вариант, мы соответсвенно обновляем значение + optionList.forEach(function (option, index) { + option.addEventListener('click', function (event) { + updateValue(select, index); + }); + }); + + // Когда виджет находится в фокусе, с каждым нажатием на клаиатуре, мы соответственно + // обновляем значение + select.addEventListener('keyup', function (event) { + var length = optionList.length, + index = getIndex(select); + + // Когда пользователь нажимает стрелку вниз, мы переходим на следующий вариант + if (event.keyCode === 40 && index < length - 1) { index++; } + + // Когда пользователь нажимает стрелку вверх, мы переходим на предыдущий вариант + if (event.keyCode === 38 && index > 0) { index--; } + + updateValue(select, index); + }); + }); +});</pre> + +<p>В приведенном выше коде стоить отметить совйство <code><a href="/en-US/docs/Web/API/HTMLElement/tabIndex" title="/en-US/docs/Web/API/HTMLElement/tabIndex">tabIndex</a></code>. Использование этого свойства необходимо чтобы стандартный виджет никогда не получил фокус, и чтобы убедиться, что наш пользовательский виджет получает фокус когда пользователь использует клавиатуру или мышь.</p> + +<p>С этим мы закончили! Вот результат:</p> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">Пример</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("Change_states",120,130, "", "HTML/Forms/How_to_build_custom_form_widgets/Example_4")}}</td> + </tr> + <tr> + <td style="text-align: center;"><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_4" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_4">Посмотреть исходный код</a></td> + </tr> + </tbody> +</table> + +<p>Но секундочку, мы точно закончили?</p> + +<h2 id="Делаем_доступным">Делаем доступным</h2> + +<p>Мы создали нечто работающее, и, хотя это далеко от полнофункционального селектбокса, работает это хорошо. Однако то, что мы сделали, это не более, чем возня с DOM. У него нет настоящей семантики, и хотя оно выглыдит как селектбокс, с точки зрения браузера - это не так, поэтому вспомогательные технологии не смогут понять что это селектбокс. Короче говоря, этот хорошенький селектбокс не является доступным для людей с ограниченными возможностями!</p> + +<p>К счастью существует решение, и оно называется <a href="/en-US/docs/Accessibility/ARIA" title="/en-US/docs/Accessibility/ARIA">ARIA</a>. ARIA - аббревиатура для "Accessible Rich Internet Application" (Доступное всем интернет приложение), и представляет собой <a href="http://www.w3.org/TR/wai-aria/" rel="external" title="http://www.w3.org/TR/wai-aria/">W3C спецификацию</a> специально разработанную для того, что мы здесь делаем: делаем веб приложения и пользовательские виджеты ассистивными (доступными для людей с ограниченными возможностями). В основном, это набор атрибутов, которые расширяют HTML, чтобы мы смогли лучше описать роли, состояния и свойства, так что только что изобретенный элемент выглядит как будто он был тем стандартным, за которого он себя выдает. Использовать эти атрибуты очень просто, поэтому давайте сделаем это.</p> + +<h3 id="Аттрибут_role">Аттрибут <code>role</code></h3> + +<p>Ключевой аттрибут используемый в <a href="/en-US/docs/Accessibility/ARIA" title="/en-US/docs/Accessibility/ARIA">ARIA</a> - это <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques"><code>role</code></a>. Аттрибут <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques"><code>role</code></a> принимает значение, определяющее для чего используется элемент. Каждая роль определяет свои собственные требования и поведение. В нашем примере мы используем роль <code><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role">listbox</a></code>. Это "составная роль" ("composite role"), т.е. элементы такой роли имеют потомков, у каждого из которых есть отдельная роль (в данном случае, как минимум один дочерний элемент с ролью <code>option</code>).</p> + +<p>Стоит также отметить что ARIA определяет роли, которые по умолчанию применяются к стандартной разметке HTML. Например, элемент {{HTMLElement("table")}} соответствует роли <code>grid</code>, а элемент {{HTMLElement("ul")}} соответствует роли <code>list</code>. Так как мы используем элемент {{HTMLElement("ul")}}, то нам необходимо убедиться что роль <code>listbox</code> нашего виджета заменит роль <code>list</code> элемента {{HTMLElement("ul")}}. С этой целью, мы будем использовать роль <code>presentation</code>. Эта роль разработана чтобы можно было отметить, что элемент не имеет особого значения, а используется исключительно чтобы представить информацию. Мы применим его к нашему элемету {{HTMLElement("ul")}}.</p> + +<p>Чтобы ввести роль <code><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role">listbox</a></code> нам нужно просто внести следующие изменения в HTML:</p> + +<pre class="brush: html"><!-- Мы добавили аттрибут role="listbox" в наш элемент верхнего уровня --> +<div class="select" role="listbox"> + <span class="value">Cherry</span> + <!-- Также мы добавили аттрибут role="presentation" в элемент ul --> + <ul class="optList" role="presentation"> + <!-- И мы добавили аттрибут role="option" во все элементы li --> + <li role="option" class="option">Cherry</li> + <li role="option" class="option">Lemon</li> + <li role="option" class="option">Banana</li> + <li role="option" class="option">Strawberry</li> + <li role="option" class="option">Apple</li> + </ul> +</div></pre> + +<div class="note"> +<p><strong>Замечание:</strong> Включение как атрибута <code>role</code> так и атрибута <code>class</code> необходимо только если вы хотите обеспечить поддержку устаревших браузеров, которые не поддерживают <a href="/en-US/docs/CSS/Attribute_selectors">селекторы атрибутов CSS</a>.</p> +</div> + +<h3 id="Атрибут_aria-selected">Атрибут <code>aria-selected</code> </h3> + +<p>Использовать только аттрибут <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques"><code>role</code></a> недостаточно. <a href="/en-US/docs/Accessibility/ARIA" title="/en-US/docs/Accessibility/ARIA">ARIA</a> также предоставляет множество атрибутов состояний и свойств. Чем больше и уместнее вы их используете, тем ваш виджет будет более понятен для вспомогательных технологий. В нашем случае мы ограничимся использованием одного аттрибута: <code>aria-selected</code>.</p> + +<p>Атрибут <code>aria-selected</code> используется для отметки текущего выбранного варианта; это позволяет ассистивным технологиям информировать пользователя о текущем выборе. Мы будем используя JavaScript динамически отмечать выбранный вариант каждый раз, когда пользователь его выбирает. С этой целью нам нужно пересмотреть нашу функцию <code>updateValue()</code>:</p> + +<pre class="brush: js">function updateValue(select, index) { + var nativeWidget = select.previousElementSibling; + var value = select.querySelector('.value'); + var optionList = select.querySelectorAll('.option'); + + // Мы уверены что все варианты не выбраны + optionList.forEach(function (other) { + other.setAttribute('aria-selected', 'false'); + }); + + // Мы уверены что выбранный вариант отмечен + optionList[index].setAttribute('aria-selected', 'true'); + + nativeWidget.selectedIndex = index; + value.innerHTML = optionList[index].innerHTML; + highlightOption(select, optionList[index]); +};</pre> + +<p>Вот окончательный результат всех этих изменений (вы сможете это лучше прочувствовать если испробуете это со вспомогательными технологиями, такими как <a href="http://www.nvda-project.org/" rel="external" title="http://www.nvda-project.org/">NVDA</a> или <a href="http://www.apple.com/accessibility/voiceover/" rel="external" title="http://www.apple.com/accessibility/voiceover/">VoiceOver</a>):</p> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">Пример</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("Change_states",120,130, "", "HTML/Forms/How_to_build_custom_form_widgets/Example_5")}}</td> + </tr> + <tr> + <td style="text-align: center;"><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_5" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_2">Посмотреть исходный код</a></td> + </tr> + </tbody> +</table> + +<h2 id="Заключение">Заключение</h2> + +<p>Мы рассмотрели все основы создания пользовательского виджета формы, и это, как вы видите, нетривиальная задача, и часто проще и лучше положиться на сторонние библиотеки, чем писать их самому с нуля (если, конечно, ваша цель - не создать такую библиотеку).</p> + +<p>Вот несколько библиотек, которые вам стоит рассмотреть перед тем как создавать собственную:</p> + +<ul> + <li><a href="http://jqueryui.com/" rel="external" title="http://jqueryui.com/">jQuery UI</a></li> + <li><a href="https://github.com/marghoobsuleman/ms-Dropdown" rel="external" title="https://github.com/marghoobsuleman/ms-Dropdown">msDropDown</a></li> + <li><a href="http://www.emblematiq.com/lab/niceforms/" rel="external" title="http://www.emblematiq.com/lab/niceforms/">Nice Forms</a></li> + <li><a href="https://www.google.fr/search?q=HTML+custom+form+controls&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:fr:official&client=firefox-a" rel="external" title="https://www.google.fr/search?q=HTML+custom+form+controls&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:fr:official&client=firefox-a">и многие другие…</a></li> +</ul> + +<p>Если вы хотите двигаться далее, то код в этом примере нуждается в некоторм улучшении прежде чем станет универсальным и многоразовым. Это упражнение, которое вы можете попробовать выполнить. Две подсказки, которые помогут вам в этом: первый аргумент всех наших функций одинаков, это значит что эти функции должны быть в одном контексте. Было бы разумным создать объект для совместного использования этого контекста. Также вам нужно сделать его функциональным; это значит, что ему необходимо одинаково хорошо работать с различными браузерами, чья соместимость с Web стандартами очень отличается. Повеселись!</p> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/Form_validation", "Learn/HTML/Forms/Sending_forms_through_JavaScript", "Learn/HTML/Forms")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Ваша первая HTML форма</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">Как структурировать HTML форму</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5_%D0%B2%D0%B8%D0%B4%D0%B6%D0%B5%D1%82%D1%8B_%D1%84%D0%BE%D1%80%D0%BC">The native form widgets</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/%D0%9E%D1%82%D0%BF%D1%80%D0%B0%D0%B2%D0%BA%D0%B0_%D0%B8_%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85_%D1%84%D0%BE%D1%80%D0%BC%D1%8B">Отправка данных формы</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Проверка данных формы</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">Как создавать пользовательские виджеты форм</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML forms in legacy browsers</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li> +</ul> diff --git a/files/ru/learn/html/forms/how_to_structure_an_html_form/index.html b/files/ru/learn/html/forms/how_to_structure_an_html_form/index.html new file mode 100644 index 0000000000..741d773dba --- /dev/null +++ b/files/ru/learn/html/forms/how_to_structure_an_html_form/index.html @@ -0,0 +1,320 @@ +--- +title: Как структурировать HTML-формы +slug: Learn/HTML/Forms/How_to_structure_an_HTML_form +tags: + - HTML-форма + - Веб-форма + - Изучение + - Новичок + - Структурирование + - Форма +translation_of: Learn/Forms/How_to_structure_a_web_form +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Forms/Ваша_первая_HTML_форма", "Learn/HTML/Forms/Стандартные_виджеты_форм", "Learn/HTML/Forms")}}</div> + +<p class="summary">Получив базовые знания, теперь мы более подробно рассмотрим элементы, используемые для придания структуры и значения различным частям форм.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Уровень подготовки:</th> + <td>Основы компьютерной грамотности, и базовые <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">знания HTML</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Разобраться как структурировать HTML формы и задавать им семантику для того, чтобы они были удобны и доступны в использовании.</td> + </tr> + </tbody> +</table> + +<p>Гибкость HTML форм делает их одной из самых сложных структур в <a href="/en-US/docs/Learn/HTML" title="/en-US/docs/HTML">HTML</a>; вы можете создать любую форму, используя элементы и атрибуты форм. Использование правильной структуры, при создании HTML форм, поможет гарантировать их удобство и <a href="/en-US/docs/Learn/Accessibility">доступность</a>.</p> + +<h2 id="Элемент_<form>">Элемент <form></h2> + +<p>Элемент {{HTMLElement("form")}} формально определяет форму и атрибуты, которые определяют поведение этой формы. Каждый раз, когда вы хотите создать HTML-форму, вам нужно начать с создания элемента {{HTMLElement("form")}}, поместив внутрь него всё содержимое. Многие вспомогательные технологии или браузерные плагины могут обнаруживать элементы {{HTMLElement("form")}} и реализовывать специальные хуки, чтобы их было проще использовать.</p> + +<p>Мы уже встречались с этим в предыдущей статье.</p> + +<div class="blockIndicator warning"> +<p><strong>Внимание:</strong> Строго запрещается размещать форму внутри другой формы. Такое размещение может привести к непредсказуемому поведению форм, в зависимости от браузера. </p> +</div> + +<p>Стоит учесть, что всегда можно использовать элементы формы вне {{HTMLElement("form")}}. Тогда по умолчанию этот элемент формы не имеет ничего общего со всеми формами. Вы можете связать его с формой с помощью аттрибута <code>form</code>. В HTML5 был представлен аттрибут <code>form</code> для элементов HTML форм, который позволяет явно связать элемент с формой, даже если он не заключён внутри {{ HTMLElement("form") }}.</p> + +<h2 id="Элементы_<fieldset>_и_<legend>">Элементы <fieldset> и <legend></h2> + +<p>Элемент {{HTMLElement("fieldset")}} - это удобный способ стилистической и семантической группировки элементов формы. Вы можете установить заголовок {{HTMLElement("fieldset")}}, добавив элемент {{HTMLElement("legend")}} сразу после открывающего тега {{HTMLElement("fieldset")}}. Текст элемента {{HTMLElement("legend")}} формально описывает назначение содержимого {{HTMLElement("fieldset")}}.</p> + +<p>Различные вспомогательные технологии будут использовать {{HTMLElement("legend")}} как часть метки <code>label</code> всех элементов внутри {{HTMLElement("fieldset")}}. Например, такие экранные дикторы как <a href="http://www.freedomscientific.com/products/fs/jaws-product-page.asp" rel="external" title="http://www.freedomscientific.com/products/fs/jaws-product-page.asp">Jaws</a> или <a href="http://www.nvda-project.org/" rel="external" title="http://www.nvda-project.org/">NVDA</a> произносят заголовок формы {{HTMLElement("legend")}} перед произношением названия меток элементов.</p> + +<p>Небольшой пример:</p> + +<pre class="brush:html; notranslate"><form> + <fieldset> + <legend>Fruit juice size</legend> + <p> + <input type="radio" name="size" id="size_1" value="small"> + <label for="size_1">Small</label> + </p> + <p> + <input type="radio" name="size" id="size_2" value="medium"> + <label for="size_2">Medium</label> + </p> + <p> + <input type="radio" name="size" id="size_3" value="large"> + <label for="size_3">Large</label> + </p> + </fieldset> +</form></pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти этот пример в <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/fieldset-legend.html">fieldset-legend.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/fieldset-legend.html">также посмотрите на результат</a>).</p> +</div> + +<p>Читая эту форму, экранный диктор произнесёт "Fruit juice size small" для первого элемента, "Fruit juice size medium" - для второго, "Fruit juice size large" - для третьего.</p> + +<p>Вариант использования в этом примере является одним из наиболее важных. Каждый раз, когда у вас есть набор переключателей, вам нужно поместить их внутри {{HTMLElement("fieldset")}}. Также {{HTMLElement("fieldset")}} можно использовать для разделения формы. В идеале, длинную форму разделяют на несколько страниц, однако, если она должна находиться на одной странице, распределение связанных элементов в разные {{HTMLElement("fieldset")}} может повысить удобство использования.</p> + +<p>Из-за своего влияния на вспомогательные технологии элемент {{HTMLElement("fieldset")}} является одним из ключевых элементов для построения доступных форм; однако вы не должны им злоупотреблять. Если возможно, старайтесь проверять, как <a href="https://www.nvaccess.org/download/">экранный диктор</a> интерпретирует вашу форму. </p> + +<h2 id="Элемент_<label>">Элемент <label></h2> + +<p>В предыдущей статье мы увидели, что элемент {{HTMLElement("label")}} принято использовать для указания текстов-подсказок (лейблов) в HTML-формах. Это самый важный элемент для построения доступных форм — при правильной реализации скринридеры будут озвучивать текст-подсказку вместе со связанными элементами. Посмотрите на этот пример из предущей статьи:</p> + +<pre class="brush: html notranslate"><label for="name">Name:</label> <input type="text" id="name" name="user_name"></pre> + +<p>При правильно связанном элементе <code><label></code> с элементом <code><input></code> через атрибуты <code>for</code> и <code>id</code> соответственно (атрибут <code>for</code> ссылается на атрибут <code>id</code> соответствующего виджета формы), скринридер прочтет вслух что-то наподобие "Name, edit text".</p> + +<p>Если <code><label></code> не правильно установлен, скринридер прочитает это как "Edit text blank", что не несет в себе никакой уточняющей информации, позволяющей понять предназначение данного текстового поля.</p> + +<p>Обратите внимание на то, что виджет формы может быть вложен в элемент {{HTMLElement("label")}}, как на примере:</p> + +<pre class="brush: html notranslate"><label for="name"> + Name: <input type="text" id="name" name="user_name"> +</label></pre> + +<p>Однако даже в таких случаях лучшей всё равно указывать атрибут <code>for</code>, так как некоторые вспомогательные технологии не распознают неявную связь между текстами-подсказками и виджетами.</p> + +<h3 id="Лейблы_тоже_кликабельны!">Лейблы тоже кликабельны!</h3> + +<p>Ещё одно преимущество при правильно установленных текстах-подсказках заключается в том, что по ним можно кликнуть для активации связанных с ними виджетов. Это поддерживается во всех браузерах. Это удобно как для текстовых полей ввода, в которых устанавливается фокус при клике на текст-посказку, так и для радио-кнопок и чекбоксов — область попадания такого элемента управления может быть очень маленькой, поэтому полезно сделать ее как можно больше.</p> + +<p>Например:</p> + +<pre class="brush:html; notranslate"><form> + <p> + <label for="taste_1">I like cherry</label> + <input type="checkbox" id="taste_1" name="taste_cherry" value="1"> + </p> + <p> + <label for="taste_2">I like banana</label> + <input type="checkbox" id="taste_2" name="taste_banana" value="2"> + </p> +</form></pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете посмотреть этот пример тут <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/checkbox-label.html">checkbox-label.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/checkbox-label.html">также можно посмотреть код вживую</a>).</p> +</div> + +<h3 id="Несколько_лейблов">Несколько лейблов</h3> + +<p>На самом деле вы можете добавить несколько текстов-подсказок на один виджет формы, но это не очень хорошая идея, так как у некоторых вспомогательных технологий могут возникнуть проблемы с обработкой такой структуры. Вместо использования нескольких лейблов, лучше вложить виджет формы внутрь одного элемента {{htmlelement("label")}}. </p> + +<p>Рассмотрим этот пример:</p> + +<pre class="brush: html notranslate"><p>Required fields are followed by <abbr title="required">*</abbr>.</p> + +<!-- Тогда это: --> +<div> + <label for="username">Name:</label> + <input type="text" name="username"> + <label for="username"><abbr title="required">*</abbr></label> +</div> + +<!-- лучше сделать таким образом: --> +<div> + <label for="username"> + <span>Name:</span> + <input id="username" type="text" name="username"> + <abbr title="required">*</abbr> + </label> +</div> + +<!-- Но этот вариант лучше всего: --> +<div> + <label for="username">Name: <abbr title="required">*</abbr></label> + <input id="username" type="text" name="username"> +</div></pre> + +<p>{{EmbedLiveSample("Multiple_labels", 120, 120)}}</p> + +<p>Параграф на первой строке примера описывает правило для обязательных элементов. Вначале необходимо убедиться, что вспомогательные технологии, такие как программы чтения с экрана, отображают или озвучивают их пользователю, прежде чем он найдет требуемый элемент. Таким образом они будут знать, что означает звёздочка. Программа чтения с экрана будет произносить звёздочку как «звёздочку» или «обязательно», в зависимости от настроек программы чтения с экрана — в любом случае, первый абзац даёт понимание того, что будет означать звёздочка далее в форме.</p> + +<ul> + <li>В первом примере лейбл не будет прочитан вместе с текстовым полем — получится лишь "edit text blank" и отдельно читаемые тексты-подсказки. Множественные элементы <code><label></code> могут быть неправильно интерпретированы программой чтения с экрана.</li> + <li>Второй пример немного лучше — лейбл будет прочитан вместе с текстовым полем и будет звучать как "name star name edit text", однако тексты-подсказки всё ещё разделены. Это всё ещё немного сбивает с толку, но на этот раз ситуация немного лучше, потому что с текстовое поле связанао с текстом-подсказкой.</li> + <li>Третий пример — лучший, так как весь лейбл будет связан с текстовым полем и озвучен целиком, а при чтении текст будет звучать как "name star edit text".</li> +</ul> + +<div class="note"> +<p><strong>Примечение</strong>: В зависимости от программы для чтения с экрана результаты могут немного отличаться. В данной статье для тестирования использовался VoiceOver (NVDA ведет себя аналогично). Также мы были бы рады, если бы вы поделились своим опытом.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти этот пример на GitHub <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/required-labels.html">required-labels.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/required-labels.html">также можно посмотреть вживую</a>). Запускайте пример, закомментировав остальные, иначе скриридеры не смогут правильно распознать контент, если у вас будет несколько лейблов и несколько текстовых полей с одинаковым ID!</p> +</div> + +<h2 id="Частоиспользуемые_с_формами_HTML-структуры">Частоиспользуемые с формами HTML-структуры</h2> + +<p>Помимо структур, характерных только для HTML-форм, хорошо помнить, что формы — это просто HTML. Это означает, что вы можете использовать всю мощь HTML для структурирования HTML-формы.</p> + +<p>Как вы можете заметить в примерах, оборачивать лейбл и виджет формы в элемент {{HTMLElement("div")}} — это общепринятая практика. Элемент {{HTMLElement("p")}} также часто используется, как и HTML-списки (последние часто используются для структурирования множественных чекбоксом или радио-кнопок).</p> + +<p>В добавок к элементу {{HTMLElement("fieldset")}} часто используют HTML-заголовки (например, {{HTMLElement("h1")}}, {{HTMLElement("h2")}}) и секционирование (например, {{HTMLElement("section")}}) для стуктурирования сложных форм.</p> + +<p>Прежде всего, вам нужно найти стиль, который будет удобен именно вам для программирования и который также позволит создавать доступные и удобные формы.</p> + +<p>Каждый отдельный раздел функциональности содержится в элементах {{HTMLElement ("section")}} и {{HTMLElement ("fieldset")}}, содержащий переключатели. Каждый отдельный раздел функциональности должен находиться в отдельном элементе {{HTMLElement ("section")}} с элементами {{HTMLElement ("fieldset")}}, содержащими переключатели.</p> + +<h3 id="Активное_обучение_построение_структуры_формы">Активное обучение: построение структуры формы</h3> + +<p>Давайте применим эти идеи на практике и построим более сложноструктурируемую форму — формы оплаты. Форма будет содержать некоторые типы виджетов формы, которые вы можете пока не понять — не переживайте об этом, вы найдёте информацию в следующей статье (<a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">Основные нативные элементы управления формами</a>). А пока внимательно прочитайте описание, следуя приведенным ниже инструкциям, и начинайте формировать представление о том, какие элементы обёртки мы используем для структурирования формы и почему.</p> + +<ol> + <li>Для начала сделайте локальную копию <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">пустого шаблона</a> и <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/payment-form.css">CSS для нашей платёжной формы</a> в новой директории на вашем компьютере.</li> + <li>Сначала подключите CSS к HTML, добавив следующую строку кода внутрь HTML-елемента {{htmlelement("head")}}: + <pre class="brush: html notranslate"><link href="payment-form.css" rel="stylesheet"></pre> + </li> + <li>Далее начните создавать свою форму с добавления внешнего элемента {{htmlelement("form")}}: + <pre class="brush: html notranslate"><form> + +</form></pre> + </li> + <li>Внутри тега <code><form></code>, добавьте заголовок и параграф, информирующий пользователей о том, как помечены поля, обязательные для заполнения: + <pre class="brush: html notranslate"><h1>Payment form</h1> +<p>Required fields are followed by <strong><abbr title="required">*</abbr></strong>.</p></pre> + </li> + <li>Далее нам надо добавить более крупный кусок кода под нашей предыдущей записью. Здесь вы можете увидеть, что мы оборачиваем поля с контактной информацией в отдельный элемент {{htmlelement("section")}}. Более того, у нас есть набор из двух радио-кнопок, каждую из которых мы помещаем в отдельный элемент списка ({{htmlelement("li")}}). Наконец, у нас есть два текстовых поля {{htmlelement("input")}} и связанные с ними элементы {{htmlelement("label")}}, которые находятся внутри элементов {{htmlelement("p")}}, а также поле для ввода пароля. Добавьте этот код в вашу форму: + <pre class="brush: html notranslate"><section> + <h2>Contact information</h2> + <fieldset> + <legend>Title</legend> + <ul> + <li> + <label for="title_1"> + <input type="radio" id="title_1" name="title" value="M." > + Mister + </label> + </li> + <li> + <label for="title_2"> + <input type="radio" id="title_2" name="title" value="Ms."> + Miss + </label> + </li> + </ul> + </fieldset> + <p> + <label for="name"> + <span>Name: </span> + <strong><abbr title="required">*</abbr></strong> + </label> + <input type="text" id="name" name="username"> + </p> + <p> + <label for="mail"> + <span>E-mail: </span> + <strong><abbr title="required">*</abbr></strong> + </label> + <input type="email" id="mail" name="usermail"> + </p> + <p> + <label for="pwd"> + <span>Password: </span> + <strong><abbr title="required">*</abbr></strong> + </label> + <input type="password" id="pwd" name="password"> + </p> +</section></pre> + </li> + <li>Сейчас мы перейдём к второму разделу <code><section></code> нашей формы — платёжной информации. В этом разделе у нас есть три отдельных виджета формы со связанными с ними лейблами, находящимися внутри тега <code><p></code>. Первый — это выпадающее меню ({{htmlelement("select")}}) для выбора типа кредитной карты. Второй — это элемент <code><input></code> с типом <code>number</code> для ввода номера карты. Последний виджет — это элемент <code><input></code> с типом <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">date</span></font> для указания даты окончания действия карты (должен будет появиться виджет с выбором даты или обычное текстовое поле в браузерах, не поддерживающих данные тип). Более новые типы полей описаны в статье <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Forms/HTML5_input_types">The HTML5 input types</a>.<br> + <br> + Вставьте следующий код под предыдущим разделом: + <pre class="brush: html notranslate"><section> + <h2>Payment information</h2> + <p> + <label for="card"> + <span>Card type:</span> + </label> + <select id="card" name="usercard"> + <option value="visa">Visa</option> + <option value="mc">Mastercard</option> + <option value="amex">American Express</option> + </select> + </p> + <p> + <label for="number"> + <span>Card number:</span> + <strong><abbr title="required">*</abbr></strong> + </label> + <input type="number" id="number" name="cardnumber"> + </p> + <p> + <label for="date"> + <span>Expiration date:</span> + <strong><abbr title="required">*</abbr></strong> + <em>formatted as mm/yy</em> + </label> + <input type="date" id="date" name="expiration"> + </p> +</section></pre> + </li> + <li>Последняя секция, которую мы добавим выглядит намного проще и содержит в себе только элемент {{htmlelement("button")}} с типом <code>submit</code>, для отправки данных. Добавьте этот код в конец вашей формы: + <pre class="brush: html notranslate"><p> <button type="submit">Validate the payment</button> </p></pre> + </li> +</ol> + +<p>Вы можете увидеть законченную форму в действии ниже (также её можно найти на GitHub — посмотрите <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/payment-form.html">payment-form.html</a> и <a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/payment-form.html">живой пример</a>):</p> + +<p>{{EmbedLiveSample("A_payment_form","100%",620, "", "Learn/HTML/Forms/How_to_structure_an_HTML_form/Example")}}</p> + +<h2 id="Протестируйте_себя!">Протестируйте себя!</h2> + +<p>Вы дошли до конца статьи, но можете ли вспомнить самую важную информацию? Далее вы можете найти тест, который поможет убедиться, что вы усвоили знания прежде чем двигаться дальше — посмотрите <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Forms/Test_your_skills:_Form_structure">Test your skills: Form structure</a>.</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Теперь у вас есть все необходимые знания для того, чтобы правильно структурировать вашу HTML-форму. Мы подробнее раскроем затронутые здесь темы в нескольких последующих статьях. В следующей же статье мы изучим все возможные типы виджетов форм, которые могут понадобиться для сбора информации от ваших пользователей.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="http://www.alistapart.com/articles/sensibleforms/" rel="external" title="http://www.alistapart.com/articles/sensibleforms/">A List Apart: <em>Sensible Forms: A Form Usability Checklist</em></a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/Ваша_первая_HTML_форма", "Learn/HTML/Forms/Стандартные_виджеты_форм", "Learn/HTML/Forms")}}</p> + +<h2 id="В_этом_разделе">В этом разделе</h2> + +<ul> + <li><a href="/ru/docs/Learn/HTML/Forms/Ваша_первая_HTML_форма">Ваша первая HTML форма</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">Как структурировать HTML-формы</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/Стандартные_виджеты_форм">Стандартные виджеты форм</a></li> + <li><a href="/en-US/docs/Learn/Forms/HTML5_input_types">The HTML5 input types</a></li> + <li><a href="/en-US/docs/Learn/Forms/Other_form_controls">Other form controls</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/Styling_HTML_forms">Стили HTML-форм</a></li> + <li><a href="/en-US/docs/Learn/Forms/Advanced_form_styling">Advanced form styling</a></li> + <li><a href="/en-US/docs/Learn/Forms/UI_pseudo-classes">UI pseudo-classes</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/Валидация_формы">Проверка данных формы</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/Отправка_и_Получение_данных_формы">Отправка данных формы</a></li> +</ul> + +<h3 id="Дополнительные_темы">Дополнительные темы</h3> + +<ul> + <li><a href="/ru/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">Как создавать пользовательские виджеты форм</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li> +</ul> diff --git a/files/ru/learn/html/forms/index.html b/files/ru/learn/html/forms/index.html new file mode 100644 index 0000000000..02e36df560 --- /dev/null +++ b/files/ru/learn/html/forms/index.html @@ -0,0 +1,78 @@ +--- +title: Руководство по HTML-формам +slug: Learn/HTML/Forms +tags: + - HTML + - Web + - Начинающие + - Руководство + - Формы +translation_of: Learn/Forms +--- +<p>{{LearnSidebar}}</p> + +<p>Данное руководство представляет собой серию статей, которые помогут Вам освоить HTML-формы. HTML формы являются очень мощным инструментом для взаимодействия с пользователями; однако, в силу исторических и технических причин, не всегда очевидно, как использовать их в полной мере. В этом руководстве мы рассмотрим все аспекты HTML-форм, от структуры к стилизации, от обработки данных до пользовательских виджетов. Вы научитесь пользоваться Великой силой, которую они предлагают!</p> + +<h2 id="Необходимые_условия">Необходимые условия</h2> + +<p>Перед началом этого модуля вам следует изучить хотя бы <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>. На данный момент у вас не должно возникнуть сложностей с пониманием <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Forms#%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5_%D1%80%D1%83%D0%BA%D0%BE%D0%B2%D0%BE%D0%B4%D1%81%D1%82%D0%B2%D0%B0_2">Основных руководств</a> и использованием нашего руководства по <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Forms/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5_%D0%B2%D0%B8%D0%B4%D0%B6%D0%B5%D1%82%D1%8B_%D1%84%D0%BE%D1%80%D0%BC">Стандартным виджетам форм</a>.</p> + +<p>Остальные части модуля немного сложнее — легко поместить виджет формы на страницу, но вы не сможете много сделать без использования продвинутых особенностей форм, CSS и JavaScript. Поэтому, перед тем как вы перейдёте к другим частям модуля, мы рекомендуем изучить немного CSS и JavaScript.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание:</strong>Если компьютер/планшет/другое устройство, на котором вы работаете, не позволяет вам самостоятельно создавать файлы, то приводимые здесь примеры кода можно посмотреть в онлайновых программах для кодирования, например <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Основные_руководства_2"> Основные руководства<a id="Основные_руководства" name="Основные_руководства"></a></h2> + +<dl> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Forms/Ваша_первая_HTML_форма">Ваша первая HTML-форма</a></dt> + <dd>Первая статья в серии дает вам начальный опыт в создании HTML-форм, включая разработку простой формы, её реализация при помощи элементов HTML, стилизация при помощи CSS и то, как данные отправляются на сервер.</dd> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">Как структурировать HTML-форму</a></dt> + <dd>Изучив основы, рассмотрим более подробно элементы, используемые для структурирования и придания смысла различным частям HTML-форм.</dd> +</dl> + +<h2 id="Какие_виджеты_форм_доступны">Какие виджеты форм доступны?</h2> + +<dl> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Forms/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5_%D0%B2%D0%B8%D0%B4%D0%B6%D0%B5%D1%82%D1%8B_%D1%84%D0%BE%D1%80%D0%BC">Стандартные виджеты форм</a></dt> + <dd>Рассмотрим подробнее функционал различных виджетов форм; какие варианты доступны для сбора различных типов данных.</dd> +</dl> + +<h2 id="Валидация_и_подтверждение_данных_форм">Валидация и подтверждение данных форм</h2> + +<dl> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Forms/%D0%9E%D1%82%D0%BF%D1%80%D0%B0%D0%B2%D0%BA%D0%B0_%D0%B8_%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85_%D1%84%D0%BE%D1%80%D0%BC%D1%8B">Отправка данных форм </a></dt> + <dd>Данная статья рассматривает что происходит, когда пользователь подтверждает форму — куда отправляются данные и как мы их там обрабатываем. Мы также рассмотрим некоторые проблемы безопасности, связанные с отправкой данных формы.</dd> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Forms/%D0%92%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D1%8B">Валидация данных форм</a></dt> + <dd>Одной отправки данных не достаточно — нам нужно убедиться что данные, введенные пользователем в формы, в правильном формате и не испортят наши приложения. Мы также хотим помочь пользователям правильно заполнить формы и не разочароваться при использовании наших приложений. Валидация форм поможет нам в достижении этих целей — эта статья расскажет вам всё, что нужно знать.</dd> +</dl> + +<h2 id="Продвинутые_руководства"> Продвинутые руководства</h2> + +<dl> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">Как создавать собственные виджеты форм</a></dt> + <dd>В некоторых случая стандартные виджеты форм не предоставляют того, что вам нужно, например из-за стиля или функционала. В таких случаях вам придётся создать собственный виджет формы из чистого HTML. В этой статье(с практическим примером) объясняется, как вы это сделаете, а также особенности, на которые необходимо обратить внимание.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Отправка форм при помощи JavaScript</a></dt> + <dd>В этой статье рассматриваются способы использования формы для сборки HTTP-запроса и отправки его через пользовательский JavaScript вместо стандартного представления формы. А также почему вы захотите это сделать и способы реализации (см. использование объектов FormData).</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML-формы в старых браузерах</a></dt> + <dd>Статья раскрывает особенности обнаружения и т.д. (см. <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing">Кросс-браузерное тестирование</a> для более глубокого понимания)</dd> +</dl> + +<h2 id="Руководства_по_стилизации_форм">Руководства по стилизации форм</h2> + +<dl> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Стилизация HTML-форм</a></dt> + <dd>Вступительная статья по стилизации форм с помощью CSS, включая все необходимые основы.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Продвинутая стилизация HTML-форм</a></dt> + <dd>В этой статье мы рассмотрим продвинутые техники стилизации форм, которые необходимо использовать при работе с некоторыми более сложными для стилизации элементами.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Таблица совместимости свойств для виджетов форм</a></dt> + <dd>Последняя статья содержит удобный справочник, позволяющий узнать, с какими элементами формы совместимы свойства CSS.</dd> +</dl> + +<h2 id="Смотри_также">Смотри также</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element#Forms">Ссылка на элементы HTML-форм</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input">Ссылка на виды HTML-элемента <input></a> </li> +</ul> diff --git a/files/ru/learn/html/forms/sending_forms_through_javascript/index.html b/files/ru/learn/html/forms/sending_forms_through_javascript/index.html new file mode 100644 index 0000000000..d98ccea1ac --- /dev/null +++ b/files/ru/learn/html/forms/sending_forms_through_javascript/index.html @@ -0,0 +1,391 @@ +--- +title: Отправка форм при помощи JavaScript +slug: Learn/HTML/Forms/Sending_forms_through_JavaScript +translation_of: Learn/Forms/Sending_forms_through_JavaScript +--- +<div>{{LearnSidebar}}</div> + +<p><span class="seoSummary">HTML формы могут декларативно отправлять <a href="/en-US/docs/HTTP">HTTP</a>-запросы. Но формы также могут подготовить HTTP-запросы для отправки с помощью JavaScript, например при помощи <code>XMLHttpRequest</code>. В этой статье исследуются подобные подходы.</span></p> + +<h2 id="Формы_не_всегда_формы">Формы не всегда формы</h2> + +<p>В современных веб-приложениях, одностраничных приложениях и приложениях на основе фреймворков, обычно <a href="/en-US/docs/HTML/Forms">HTML-формы</a> используются для отправки данных без загрузки нового документа при получении данных ответа. В начале поговорим о том почему это требует другого подхода.</p> + +<h3 id="Получение_контроля_над_глобальным_интерфейсом">Получение контроля над глобальным интерфейсом</h3> + +<p>Отправка стандартной HTML формы, как описывалось в предыдущей статье, загружает URL-адрес, по которому были отправлены данные, это означает, что окно браузера перемещается с полной загрузкой страницы. Если избегать полную перезагрузку страницы, можно обеспечить более плавную работу, за счет предотвращения задержек в сети и возможных визуальных проблем (например, мерцания).</p> + +<p>Многие современные пользовательские интерфейсы используют HTML формы только для сбора пользовательского ввода, а не для для отправки данных. Когда пользователь пытатся отправить свои данные, приложение берет контроль и асинхронно передает данные в фоновом режиме, обновляя только ту часть всего интерфейса пользователя, которой требуется обновление.</p> + +<p>Асинхронная отправка произвольных данных обычно называется <a href="/en-US/docs/AJAX">AJAX</a>, что означает <strong>"Asynchronous JavaScript And XML" </strong>(Асинхронный JavaScript и XML).</p> + +<h3 id="Чем_он_отличается">Чем он отличается?</h3> + +<p>Объект {{domxref("XMLHttpRequest")}} (XHR) DOM может создавать HTTP-запросы, отправлять их, и получать их результат. Исторически, {{domxref("XMLHttpRequest")}} был разработан для получения и отправки <a href="/en-US/docs/XML">XML</a> в качестве формата обмена, который со временем был заменен на <a href="/en-US/docs/JSON">JSON</a>. Но ни XML, ни JSON не вписываются в кодировку запроса данных формы. Данные формы (<code>application/x-www-form-urlencoded</code>) состоят из списка пар ключ/значение в кодировке URL. Для передачи бинарных данных, HTTP-запрос преобразуется в <code>multipart/form-data</code>.</p> + +<div class="blockIndicator note"> +<p><strong>Замечание</strong>: Сейчас <a href="/en-US/docs/Web/API/Fetch_API">Fetch API</a> часто используется вместо XHR — это современная, обновленная версия XHR, которая работает в похожем стиле, но имеет несколько преимуществ. Большая часть XHR-кода, которую вы увидете в этой статье можно заменить на Fetch.</p> +</div> + +<p>Если вы управляете фронтендом (кодом, который выполняется в браузере) и бкендом (кодом, который выполняется на стороне сервера), вы можете отправлять JSON/XML и обрабатывать их как хотите.</p> + +<p>Но если вы хотите использовать сторонний сервис, то вам необходимо отправлять данные в формате, который требуется сервису.</p> + +<p>Так как нам следует отправлять подобные данные? Ниже обписаны различные необходимые вам техники.</p> + +<h2 id="Отправка_данных_формы">Отправка данных формы</h2> + +<p>Есть три способа отправки данных формы:</p> + +<ul> + <li>Создание <code>XMLHttpRequest</code> вручную.</li> + <li>Использование самостоятельного <code>FormData</code> объекта.</li> + <li>Использование <code>FormData</code> связанного с <code><form></code> элементом.</li> +</ul> + +<p>Давайте рассмотрим их подробнее:</p> + +<h3 id="Создание_XMLHttpRequest_вручную">Создание XMLHttpRequest вручную</h3> + +<p>{{domxref("XMLHttpRequest")}} это самый безопасный и надежный способ создавать HTTPзапросы. Для отправки данных формы с помощью {{domxref("XMLHttpRequest")}}, подготовьте данные с помощью URL-кодирования, и соблюдайте специфику запросов данных формы.</p> + +<p>Посмотрите на пример:</p> + +<pre class="brush: html notranslate"><button>Click Me!</button></pre> + +<p>И на JavaScript:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function sendData( data ) { + console.log( 'Sending data' ); + + const XHR = new XMLHttpRequest(); + + let urlEncodedData = "", + urlEncodedDataPairs = [], + name; + + // Turn the data object into an array of URL-encoded key/value pairs. + for( name in data ) { + urlEncodedDataPairs.push( encodeURIComponent( name ) + '=' + encodeURIComponent( data[name] ) ); + } + + // Combine the pairs into a single string and replace all %-encoded spaces to + // the '+' character; matches the behaviour of browser form submissions. + urlEncodedData = urlEncodedDataPairs.join( '&' ).replace( /%20/g, '+' ); + + // Define what happens on successful data submission + XHR.addEventListener( 'load', function(event) { + alert( 'Yeah! Data sent and response loaded.' ); + } ); + + // Define what happens in case of error + XHR.addEventListener( 'error', function(event) { + alert( 'Oops! Something went wrong.' ); + } ); + + // Set up our request + XHR.open( 'POST', 'https://example.com/cors.php' ); + + // Add the required HTTP header for form data POST requests + XHR.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' ); + + // Finally, send our data. + XHR.send( urlEncodedData ); +} + +btn.addEventListener( 'click', function() { + sendData( {test:'ok'} ); +} ) +</pre> + +<p>Это результат:</p> + +<p>{{EmbedLiveSample("Building_an_XMLHttpRequest_manually", "100%", 50)}}</p> + +<div class="note"> +<p><strong>Note:</strong> This use of {{domxref("XMLHttpRequest")}} is subject to the {{glossary('same-origin policy')}} if you want to send data to a third party web site. For cross-origin requests, you'll need <a href="/en-US/docs/HTTP/Access_control_CORS">CORS and HTTP access control</a>.</p> +</div> + +<h3 id="Using_XMLHttpRequest_and_the_FormData_object">Using XMLHttpRequest and the FormData object</h3> + +<p>Building an HTTP request by hand can be overwhelming. Fortunately, the <a href="http://www.w3.org/TR/XMLHttpRequest/" rel="external">XMLHttpRequest specification</a> provides a newer, simpler way to handle form data requests with the {{domxref("XMLHttpRequest/FormData","FormData")}} object.</p> + +<p>The {{domxref("XMLHttpRequest/FormData","FormData")}} object can be used to build form data for transmission, or to get the data within a form element to manage how it's sent. Note that {{domxref("XMLHttpRequest/FormData","FormData")}} objects are "write only", which means you can change them, but not retrieve their contents.</p> + +<p>Using this object is detailed in <a href="/en-US/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects">Using FormData Objects</a>, but here are two examples:</p> + +<h4 id="Using_a_standalone_FormData_object">Using a standalone FormData object</h4> + +<pre class="brush: html notranslate"><button>Click Me!</button></pre> + +<p>You should be familiar with that HTML sample. Now for the JavaScript:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function sendData( data ) { + const XHR = new XMLHttpRequest(), + FD = new FormData(); + + // Push our data into our FormData object + for( name in data ) { + FD.append( name, data[ name ] ); + } + + // Define what happens on successful data submission + XHR.addEventListener( 'load', function( event ) { + alert( 'Yeah! Data sent and response loaded.' ); + } ); + + // Define what happens in case of error + XHR.addEventListener(' error', function( event ) { + alert( 'Oops! Something went wrong.' ); + } ); + + // Set up our request + XHR.open( 'POST', 'https://example.com/cors.php' ); + + // Send our FormData object; HTTP headers are set automatically + XHR.send( FD ); +} + +btn.addEventListener( 'click', function() + { sendData( {test:'ok'} ); +} )</pre> + +<p>Here's the live result:</p> + +<p>{{EmbedLiveSample("Using_a_standalone_FormData_object", "100%", 50)}}</p> + +<h4 id="Using_FormData_bound_to_a_form_element">Using FormData bound to a form element</h4> + +<p>You can also bind a <code>FormData</code> object to an {{HTMLElement("form")}} element. This creates a <code>FormData</code> object that represents the data contained in the form.</p> + +<p>The HTML is typical:</p> + +<pre class="brush: html notranslate"><form id="myForm"> + <label for="myName">Send me your name:</label> + <input id="myName" name="name" value="John"> + <input type="submit" value="Send Me!"> +</form></pre> + +<p>But JavaScript takes over the form:</p> + +<pre class="brush: js notranslate">window.addEventListener( "load", function () { + function sendData() { + const XHR = new XMLHttpRequest(); + + // Bind the FormData object and the form element + const FD = new FormData( form ); + + // Define what happens on successful data submission + XHR.addEventListener( "load", function(event) { + alert( event.target.responseText ); + } ); + + // Define what happens in case of error + XHR.addEventListener( "error", function( event ) { + alert( 'Oops! Something went wrong.' ); + } ); + + // Set up our request + XHR.open( "POST", "https://example.com/cors.php" ); + + // The data sent is what the user provided in the form + XHR.send( FD ); + } + + // Access the form element... + const form = document.getElementById( "myForm" ); + + // ...and take over its submit event. + form.addEventListener( "submit", function ( event ) { + event.preventDefault(); + + sendData(); + } ); +} );</pre> + +<p>Here's the live result:</p> + +<p>{{EmbedLiveSample("Using_FormData_bound_to_a_form_element", "100%", 50)}}</p> + +<p>You can even get more involved with the process by using the form's {{domxref("HTMLFormElement.elements", "elements")}} property to get a list of all of the data elements in the form and manually manage them one at a time. To learn more about that, see the example in {{SectionOnPage("/en-US/docs/Web/API/HTMLFormElement.elements", "Accessing the element list's contents")}}.</p> + +<h2 id="Dealing_with_binary_data">Dealing with binary data</h2> + +<p>If you use a {{domxref("XMLHttpRequest/FormData","FormData")}} object with a form that includes <code><input type="file"></code> widgets, the data will be processed automatically. But to send binary data by hand, there's extra work to do.</p> + +<p>There are many sources for binary data, including {{domxref("FileReader")}}, {{domxref("HTMLCanvasElement","Canvas")}}, and <a href="/en-US/docs/WebRTC/navigator.getUserMedia">WebRTC</a>. Unfortunately, some legacy browsers can't access binary data or require complicated workarounds. To learn more about the <code>FileReader</code> API, see <a href="/en-US/docs/Using_files_from_web_applications">Using files from web applications</a>.</p> + +<p>The least complicated way of sending binary data is by using {{domxref("XMLHttpRequest/FormData","FormData")}}'s <code>append()</code> method, demonstrated above. If you have to do it by hand, it's trickier.</p> + +<p>In the following example, we use the {{domxref("FileReader")}} API to access binary data and then build the multi-part form data request by hand:</p> + +<pre class="brush: html notranslate"><form id="theForm"> + <p> + <label for="theText">text data:</label> + <input id="theText" name="myText" value="Some text data" type="text"> + </p> + <p> + <label for="theFile">file data:</label> + <input id="theFile" name="myFile" type="file"> + </p> + <button>Send Me!</button> +</form></pre> + +<p>As you see, the HTML is a standard <code><form></code>. There's nothing magical going on. The "magic" is in the JavaScript:</p> + +<pre class="brush: js notranslate">// Because we want to access DOM nodes, +// we initialize our script at page load. +window.addEventListener( 'load', function () { + + // These variables are used to store the form data + const text = document.getElementById( "theText" ); + const file = { + dom : document.getElementById( "theFile" ), + binary : null + }; + + // Use the FileReader API to access file content + const reader = new FileReader(); + + // Because FileReader is asynchronous, store its + // result when it finishes to read the file + reader.addEventListener( "load", function () { + file.binary = reader.result; + } ); + + // At page load, if a file is already selected, read it. + if( file.dom.files[0] ) { + reader.readAsBinaryString( file.dom.files[0] ); + } + + // If not, read the file once the user selects it. + file.dom.addEventListener( "change", function () { + if( reader.readyState === FileReader.LOADING ) { + reader.abort(); + } + + reader.readAsBinaryString( file.dom.files[0] ); + } ); + + // sendData is our main function + function sendData() { + // If there is a selected file, wait it is read + // If there is not, delay the execution of the function + if( !file.binary && file.dom.files.length > 0 ) { + setTimeout( sendData, 10 ); + return; + } + + // To construct our multipart form data request, + // We need an XMLHttpRequest instance + const XHR = new XMLHttpRequest(); + + // We need a separator to define each part of the request + const boundary = "blob"; + + // Store our body request in a string. + let data = ""; + + // So, if the user has selected a file + if ( file.dom.files[0] ) { + // Start a new part in our body's request + data += "--" + boundary + "\r\n"; + + // Describe it as form data + data += 'content-disposition: form-data; ' + // Define the name of the form data + + 'name="' + file.dom.name + '"; ' + // Provide the real name of the file + + 'filename="' + file.dom.files[0].name + '"\r\n'; + // And the MIME type of the file + data += 'Content-Type: ' + file.dom.files[0].type + '\r\n'; + + // There's a blank line between the metadata and the data + data += '\r\n'; + + // Append the binary data to our body's request + data += file.binary + '\r\n'; + } + + // Text data is simpler + // Start a new part in our body's request + data += "--" + boundary + "\r\n"; + + // Say it's form data, and name it + data += 'content-disposition: form-data; name="' + text.name + '"\r\n'; + // There's a blank line between the metadata and the data + data += '\r\n'; + + // Append the text data to our body's request + data += text.value + "\r\n"; + + // Once we are done, "close" the body's request + data += "--" + boundary + "--"; + + // Define what happens on successful data submission + XHR.addEventListener( 'load', function( event ) { + alert( 'Yeah! Data sent and response loaded.' ); + } ); + + // Define what happens in case of error + XHR.addEventListener( 'error', function( event ) { + alert( 'Oops! Something went wrong.' ); + } ); + + // Set up our request + XHR.open( 'POST', 'https://example.com/cors.php' ); + + // Add the required HTTP header to handle a multipart form data POST request + XHR.setRequestHeader( 'Content-Type','multipart/form-data; boundary=' + boundary ); + + // And finally, send our data. + XHR.send( data ); + } + + // Access our form... + const form = document.getElementById( "theForm" ); + + // ...to take over the submit event + form.addEventListener( 'submit', function ( event ) { + event.preventDefault(); + sendData(); + } ); +} );</pre> + +<p>Here's the live result:</p> + +<p>{{EmbedLiveSample("Dealing_with_binary_data", "100%", 150)}}</p> + +<h2 id="Conclusion">Conclusion</h2> + +<p>Depending on the browser and the type of data you are dealing with, sending form data through JavaScript can be easy or difficult. The {{domxref("XMLHttpRequest/FormData","FormData")}} object is generally the answer, and you can use a <a href="https://github.com/jimmywarting/FormData">polyfill</a> for it on legacy browsers.</p> + +<h2 id="See_also">See also</h2> + +<h3 id="Learning_path">Learning path</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Your first HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">How to structure an HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">The native form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/HTML5_input_types">HTML5 input types</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Additional_form_controls">Additional form controls</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/UI_pseudo-classes">UI pseudo-classes</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Sending form data</a></li> +</ul> + +<h3 id="Advanced_Topics">Advanced Topics</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML forms in legacy browsers</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li> +</ul> diff --git a/files/ru/learn/html/forms/styling_html_forms/index.html b/files/ru/learn/html/forms/styling_html_forms/index.html new file mode 100644 index 0000000000..f8cc1644dc --- /dev/null +++ b/files/ru/learn/html/forms/styling_html_forms/index.html @@ -0,0 +1,381 @@ +--- +title: Стили HTML форм +slug: Learn/HTML/Forms/Styling_HTML_forms +translation_of: Learn/Forms/Styling_web_forms +--- +<p>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/HTML_forms_in_legacy_browsers", "Learn/HTML/Forms/Advanced_styling_for_HTML_forms", "Learn/HTML/Forms")}}</p> + +<p class="summary"><span class="seoSummary">В этой статье Вы узнает, как использовать CSS с HTML-формами, чтобы сделать их (надеюсь) более красивыми. Удивительно, но это может быть немного сложнее. По историческим и техническим причинам виджеты форм плохо сочетаются с CSS. Из-за этих трудностей многие разработчики предпочитают создавать свои собственные HTML-виджеты, чтобы получить контроль над своим внешним видом. Однако в современных браузерах веб-дизайнеры все больше контролируют дизайн элементов формы. Давайте приступим!</span></p> + +<h2 id="Почему_так_сложно_стилизовать_виджеты_форм_с_помощью_CSS">Почему так сложно стилизовать виджеты форм с помощью CSS?</h2> + +<p>На заре Интернета, примерно в 1995 году, в <a href="http://www.ietf.org/rfc/rfc1866.txt">HTML 2</a> были добавлены элементы управления формой. Из-за сложности виджетов форм разработчики решили полагаться на базовую операционную систему для управления ими и их рендеринга.</p> + +<p>Несколько лет спустя был создан CSS, и то, что было технической необходимостью, то есть использование собственных виджетов для реализации элементов управления формой, стало требованием к стилю. В первые дни CSS, стилизация элементов управления формы не была приоритетом.</p> + +<p>Поскольку пользователи привыкли к внешнему виду своих соответствующих платформ, поставщики браузеров неохотно делают элементы управления формами стилевыми; и по сей день все еще чрезвычайно трудно перестроить все элементы управления, чтобы сделать их стилизованными.</p> + +<p>Даже сегодня ни один браузер полностью не реализует CSS 2.1. Однако со временем поставщики браузеров улучшили свою поддержку CSS для элементов формы, и, несмотря на плохую репутацию в отношении удобства использования, теперь вы можете использовать CSS для стилизации <a href="/en-US/docs/HTML/Forms">HTML форм</a>.</p> + +<h3 id="Не_все_виджеты_созданы_равными_когда_задействован_CSS">Не все виджеты созданы равными, когда задействован CSS</h3> + +<p>В настоящее время некоторые трудности остаются при использовании CSS с формами. Эти проблемы можно разделить на три категории:</p> + +<h4 id="Хорошая">Хорошая</h4> + +<p>Некоторые элементы могут быть стилизованы с небольшим количеством проблем на разных платформах. К ним относятся следующие структурные элементы:</p> + +<ol> + <li>{{HTMLElement("form")}}</li> + <li>{{HTMLElement("fieldset")}}</li> + <li>{{HTMLElement("label")}}</li> + <li>{{HTMLElement("output")}}</li> +</ol> + +<p>Сюда также входят все виджеты текстового поля (как однострочные, так и многострочные) и кнопки.</p> + +<h4 id="Плохая">Плохая</h4> + +<p>Некоторые элементы редко могут быть стилизованы, и могут потребовать некоторых сложных уловок, иногда требующих углубленных знаний CSS3.</p> + +<p>Они включают в себя элемент {{HTMLElement ("legend")}}, но его нельзя правильно расположить на всех платформах. Флажки и переключатели также не могут быть стилизованы напрямую, однако, благодаря CSS3 вы можете обойти это. Контент {{htmlattrxref ("placeholder", "input")}} не может быть стилизован каким-либо стандартным способом, однако все браузеры, которые его реализуют, также реализуют собственные псевдо-элементы CSS или псевдоклассы, которые позволяют его стилизовать.</p> + +<p>Мы опишем, как обрабатывать эти более конкретные случаи, в статье <a href="/en-US/docs/Advanced_styling_for_HTML_forms">«Расширенные стили для HTML-форм».</a></p> + +<h4 id="The_ugly">The ugly</h4> + +<p>Some elements simply can't be styled using CSS. These include: all advanced user interface widgets, such as range, color, or date controls; and all the dropdown widgets, including {{HTMLElement("select")}}, {{HTMLElement("option")}}, {{HTMLElement("optgroup")}} and {{HTMLElement("datalist")}} elements. The file picker widget is also known not to be stylable at all. The new {{HTMLElement("progress")}} and {{HTMLElement("meter")}} elements also fall in this category.</p> + +<p>The main issue with all these widgets, comes from the fact that they have a very complex structure, and CSS is not currently expressive enough to style all the subtle parts of those widgets. If you want to customize those widgets, you have to rely on JavaScript to build a DOM tree you'll be able to style. We explore how to do this in the article <a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a>.</p> + +<h2 id="Basic_styling">Basic styling</h2> + +<p>To style <a href="/en-US/docs/HTML/Forms/Styling_HTML_forms#The_good" title="/en-US/docs/HTML/Forms/Styling_HTML_forms#The_good">elements that are easy to style</a> with CSS, you shouldn't face any difficulties, since they mostly behave like any other HTML element. However, the user-agent style sheet of every browser can be a little inconsistent, so there are a few tricks that can help you style them in an easier way.</p> + +<h3 id="Search_fields">Search fields</h3> + +<p>Search boxes are the only kind of text fields that can be a little tricky to style. On WebKit based browsers (Chrome, Safari, etc.), you'll have to tweak it with the <code>-webkit-appearance</code> proprietary property. We discuss this property further in the article: <a href="/en-US/docs/Advanced_styling_for_HTML_forms" title="/en-US/docs/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a>.</p> + +<h4 id="Example">Example</h4> + +<pre class="brush: html"><form> + <input type="search"> +</form> +</pre> + +<pre class="brush: css">input[type=search] { + border: 1px dotted #999; + border-radius: 0; + + -webkit-appearance: none; +}</pre> + +<p><img alt="This is a screenshot of a search filed on Chrome, with and without the use of -webkit-appearance" src="/files/4153/search-chrome-macos.png" style="border-style: solid; border-width: 1px; height: 107px; width: 179px;"></p> + +<p>As you can see on this screenshot of the search field on Chrome, the two fields have a border set as in our example. The first field is rendered without using the <code>-webkit-appearance</code> property, whereas the second is rendered using <code>-webkit-appearance:none</code>. This difference is noticeable.</p> + +<h3 id="Fonts_and_text">Fonts and text</h3> + +<p>CSS font and text features can be used easily with any widget (and yes, you can use {{cssxref("@font-face")}} with form widgets). However, browsers' behaviors are often inconsistent. By default, some widgets do not inherit {{cssxref("font-family")}} and {{cssxref("font-size")}} from their parents. Many browsers use the system default appearance instead. To make your forms' appearance consistent with the rest of your content, you can add the following rules to your stylesheet:</p> + +<pre class="brush: css">button, input, select, textarea { + font-family : inherit; + font-size : 100%; +}</pre> + +<p>The screenshot below shows the difference; on the left is the default rendering of the element in Firefox on Mac OS X, with the platform's default font style in use. On the right are the same elements, with our font harmonization style rules applied.</p> + +<p><img alt="This is a screenshot of the main form widgets on Firefox on Mac OSX, with and without font harmonization" src="/files/4157/font-firefox-macos.png" style="border-style: solid; border-width: 1px; height: 234px; width: 420px;"></p> + +<p>There's a lot of debate as to whether forms look better using the system default styles, or customized styles designed to match your content. This decision is yours to make, as the designer of your site, or Web application.</p> + +<h3 id="Box_model">Box model</h3> + +<p>All text fields have complete support for every property related to the CSS box model ({{cssxref("width")}}, {{cssxref("height")}}, {{cssxref("padding")}}, {{cssxref("margin")}}, and {{cssxref("border")}}). As before, however, browsers rely on the system default styles when displaying these widgets. It's up to you to define how you wish to blend them into your content. If you want to keep the native look and feel of the widgets, you'll face a little difficulty if you want to give them a consistent size.</p> + +<p><strong>This is because each widget has their own rules for border, padding and margin.</strong> So if you want to give the same size to several different widgets, you have to use the {{cssxref("box-sizing")}} property:</p> + +<pre class="brush: css">input, textarea, select, button { + width : 150px; + margin: 0; + + -webkit-box-sizing: border-box; /* For legacy WebKit based browsers */ + -moz-box-sizing: border-box; /* For legacy (Firefox <29) Gecko based browsers */ + box-sizing: border-box; +}</pre> + +<p><img alt="This is a screenshot of the main form widgets on Chrome on Windows 7, with and without the use of box-sizing." src="/files/4161/size-chrome-win7.png" style="border-style: solid; border-width: 1px; height: 213px; width: 358px;"></p> + +<p>In the screenshot above, the left column is built without {{cssxref("box-sizing")}}, while the right column uses this property with the value <code>border-box</code>. Notice how this lets us ensure that all of the elements occupy the same amount of space, despite the platform's default rules for each kind of widget.</p> + +<h3 id="Positioning">Positioning</h3> + +<p>Positioning of HTML form widgets is generally not a problem; however, there are two elements you should take special note of:</p> + +<h4 id="legend">legend</h4> + +<p>The {{HTMLElement("legend")}} element is okay to style, except for positioning. In every browser, the {{HTMLElement("legend")}} element is positioned on top of the top border of its {{HTMLElement("fieldset")}} parent. There is absolutely no way to change it to be positioned within the HTML flow, away from the top border. You can, however, position it absolutely or relatively, using the {{cssxref("position")}} property. But otherwise it is part of the fieldset border.</p> + +<p>Because the {{HTMLElement("legend")}} element is very important for accessibility reasons, it will be spoken by assistive technologies as part of the label of each form element inside the fieldset, it's quite often paired with a title, and then hidden in an accessible way. For example:</p> + +<h5 id="HTML">HTML</h5> + +<pre class="brush: html"><fieldset> + <legend>Hi!</legend> + <h1>Hello</h1> +</fieldset></pre> + +<h5 id="CSS">CSS</h5> + +<pre class="brush: css">legend { + width: 1px; + height: 1px; + overflow: hidden; +}</pre> + +<h4 id="textarea">textarea</h4> + +<p>By default, all browsers consider the {{HTMLElement("textarea")}} element to be an inline block, aligned to the text bottom line. This is rarely what we actually want to see. To change from <code>inline-block</code> to <code>block</code>, it's pretty easy to use the {{cssxref("display")}} property. But if you want to use it inline, it's common to change the vertical alignment:</p> + +<pre class="brush: css">textarea { + vertical-align: top; +}</pre> + +<h2 id="Example_2">Example</h2> + +<p>Let's look at a concrete example of how to style an HTML form. This will help make a lot of these ideas clearer. We will build the following "postcard" contact form:</p> + +<p><img alt="This is what we want to achieve with HTML and CSS" src="/files/4149/screenshot.png" style="border-style: solid; border-width: 1px; height: 249px; width: 370px;"></p> + +<p>If you want to follow along with this example, make a local copy of our <a href="https://github.com/mdn/learning-area/blob/master/html/forms/postcard-example/postcard-start.html">postcard-start.html file</a>, and follow the below instructions.</p> + +<h3 id="The_HTML">The HTML</h3> + +<p>The HTML is only slightly more involved than the example we used in <a href="/en-US/docs/HTML/Forms/My_first_HTML_form" title="/en-US/docs/HTML/Forms/My_first_HTML_form">the first article of this guide</a>; it just has a few extra IDs and a title.</p> + +<pre class="brush: html"><form> + <h1>to: Mozilla</h1> + + <div id="from"> + <label for="name">from:</label> + <input type="text" id="name" name="user_name"> + </div> + + <div id="reply"> + <label for="mail">reply:</label> + <input type="email" id="mail" name="user_email"> + </div> + + <div id="message"> + <label for="msg">Your message:</label> + <textarea id="msg" name="user_message"></textarea> + </div> + + <div class="button"> + <button type="submit">Send your message</button> + </div> +</form></pre> + +<p>Add the above code into the body of your HTML.</p> + +<h3 id="Organizing_your_assets">Organizing your assets</h3> + +<p>This is where the fun begins! Before we start coding, we need three additional assets:</p> + +<ol> + <li>The postcard <a href="/files/4151/background.jpg" title="The postcard background">background</a> — download this image and save it in the same directory as your working HTML file.</li> + <li>A typewriter font: <a href="http://www.fontsquirrel.com/fonts/Secret-Typewriter" rel="external" title="http://www.fontsquirrel.com/fonts/Secret-Typewriter">The "Secret Typewriter" font from fontsquirrel.com</a> — download the TTF file into the same directory as above.</li> + <li>A handdrawn font: <a href="http://www.fontsquirrel.com/fonts/Journal" rel="external" title="http://www.fontsquirrel.com/fonts/Journal">The "Journal" font from fontsquirrel.com</a> — download the TTF file into the same directory as above.</li> +</ol> + +<p>Your fonts need some more processing before you start:</p> + +<ol> + <li>Go to the fontsquirrel <a href="https://www.fontsquirrel.com/tools/webfont-generator">Webfont Generator</a>.</li> + <li>Using the form, upload both your font files and generate a webfont kit. Download the kit to your computer.</li> + <li>Unzip the provided zip file.</li> + <li>Inside the unzipped contents you will find two <code>.woff</code> files and two <code>.woff2</code> files. Copy these four files into a directory called fonts, in the same directory as before. We are using two different files for each font to maximise browser compatibility; see our <a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">Web fonts</a> article for a lot more information.</li> +</ol> + +<h3 id="The_CSS">The CSS</h3> + +<p>Now we can dig into the CSS for the example. Add all the code blocks shown below inside the {{htmlelement("style")}} element, one after another.</p> + +<p>First, we prepare the ground by defining our {{cssxref("@font-face")}} rules, all the basics on the {{HTMLElement("body")}} element, and the {{HTMLElement("form")}} element:</p> + +<pre class="brush: css">@font-face { + font-family: 'handwriting'; + src: url('fonts/journal-webfont.woff2') format('woff2'), + url('fonts/journal-webfont.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'typewriter'; + src: url('fonts/veteran_typewriter-webfont.woff2') format('woff2'), + url('fonts/veteran_typewriter-webfont.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +body { + font : 21px sans-serif; + + padding : 2em; + margin : 0; + + background : #222; +} + +form { + position: relative; + + width : 740px; + height : 498px; + margin : 0 auto; + + background: #FFF url(background.jpg); +}</pre> + +<p>Now we can position our elements, including the title and all the form elements:</p> + +<pre class="brush: css">h1 { + position : absolute; + left : 415px; + top : 185px; + + font : 1em "typewriter", sans-serif; +} + +#from { + position: absolute; + left : 398px; + top : 235px; +} + +#reply { + position: absolute; + left : 390px; + top : 285px; +} + +#message { + position: absolute; + left : 20px; + top : 70px; +}</pre> + +<p>That's where we start working on the form elements themselves. First, let's ensure that the {{HTMLElement("label")}}s are given the right font:</p> + +<pre class="brush: css">label { + font : .8em "typewriter", sans-serif; +}</pre> + +<p>The text fields require some common rules. Simply put, we remove their {{cssxref("border","borders")}} and {{cssxref("background","backgrounds")}}, and redefine their {{cssxref("padding")}} and {{cssxref("margin")}}:</p> + +<pre class="brush: css">input, textarea { + font : .9em/1.5em "handwriting", sans-serif; + + border : none; + padding : 0 10px; + margin : 0; + width : 240px; + + background: none; +}</pre> + +<p>When one of these fields gains focus, we highlight them with a light grey, transparent, background. Note that it's important to add the {{cssxref("outline")}} property, in order to remove the default focus highlight added by some browsers:</p> + +<pre class="brush: css">input:focus, textarea:focus { + background : rgba(0,0,0,.1); + border-radius: 5px; + outline : none; +}</pre> + +<p>Now that our text fields are complete, we need to adjust the display of the single and multiple line text fields to match, since they won't typically look the same using the defaults.</p> + +<p>The single-line text field needs some tweaks to render nicely in Internet Explorer. Internet Explorer does not define the height of the fields based on the natural height of the font (which is the behavior of all other browsers). To fix this, we need to add an explicit height to the field, as follows:</p> + +<pre class="brush: css">input { + height: 2.5em; /* for IE */ + vertical-align: middle; /* This is optional but it makes legacy IEs look better */ +}</pre> + +<p>{{HTMLElement("textarea")}} elements default to being rendered as a block element. The two important things here are the {{cssxref("resize")}} and {{cssxref("overflow")}} properties. Because our design is a fixed-size design, we will use the <code>resize</code> property to prevent users from resizing our multi-line text field. The {{cssxref("overflow")}} property is used to make the field render more consistently across browsers. Some browsers default to the value <code>auto</code>, while some default to the value <code>scroll</code>. In our case, it's better to be sure every one will use <code>auto</code>:</p> + +<pre class="brush: css">textarea { + display : block; + + padding : 10px; + margin : 10px 0 0 -10px; + width : 340px; + height : 360px; + + resize : none; + overflow: auto; +}</pre> + +<p>The {{HTMLElement("button")}} element is really convenient with CSS; you can do whatever you want, even using <a href="/en-US/docs/CSS/Pseudo-elements" title="/en-US/docs/CSS/Pseudo-elements">pseudo-elements</a>:</p> + +<pre class="brush: css">button { + position : absolute; + left : 440px; + top : 360px; + + padding : 5px; + + font : bold .6em sans-serif; + border : 2px solid #333; + border-radius: 5px; + background : none; + + cursor : pointer; + +-webkit-transform: rotate(-1.5deg); + -moz-transform: rotate(-1.5deg); + -ms-transform: rotate(-1.5deg); + -o-transform: rotate(-1.5deg); + transform: rotate(-1.5deg); +} + +button:after { + content: " >>>"; +} + +button:hover, +button:focus { + outline : none; + background: #000; + color : #FFF; +}</pre> + +<p>And voila!</p> + +<div class="note"> +<p><strong>Note</strong>: If your example does not work quite like you expected and you want to check it against our version, you can find it on GitHub — see it <a href="https://mdn.github.io/learning-area/html/forms/postcard-example/">running live</a> (also see <a href="https://github.com/mdn/learning-area/tree/master/html/forms/postcard-example">the source code</a>).</p> +</div> + +<h2 id="Conclusion">Conclusion</h2> + +<p>As you can see, as long as we want to build forms with just text fields and buttons, it's easy to style them using CSS. If you want to know more of the little CSS tricks that can make your life easier when working with form widgets, take a look at the form part of <a href="http://necolas.github.com/normalize.css" rel="external" title="http://necolas.github.com/normalize.css">the normalize.css project</a>.</p> + +<p><a href="/en-US/docs/Web/Guide/HTML/Forms/Advanced_styling_for_HTML_forms" title="/en-US/docs/Advanced_styling_for_HTML_forms">In the next article</a>, we will see how to handle form widgets which fall in the "bad" and "ugly" categories.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/HTML_forms_in_legacy_browsers", "Learn/HTML/Forms/Advanced_styling_for_HTML_forms", "Learn/HTML/Forms")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Your first HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">How to structure an HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">The native form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Sending form data</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML forms in legacy browsers</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li> +</ul> diff --git a/files/ru/learn/html/forms/валидация_формы/index.html b/files/ru/learn/html/forms/валидация_формы/index.html new file mode 100644 index 0000000000..f2c5f362ac --- /dev/null +++ b/files/ru/learn/html/forms/валидация_формы/index.html @@ -0,0 +1,906 @@ +--- +title: Проверка данных формы (проверка валидности формы на стороне клиента) +slug: Learn/HTML/Forms/Валидация_формы +translation_of: Learn/Forms/Form_validation +--- +<p> + <audio class="audio-for-speech"></audio> +</p> + +<div class="translate-tooltip-mtz" style="left: 0px; top: 3716px;"> +<div class="header"> +<div class="header-controls"></div> + +<div class="translate-icons"><img class="from"> <img class="arrow"> <img class="to"></div> +</div> + +<div class="translated-text"> +<div class="words"></div> + +<div class="sentences"> +<div class="translated-sentence-wrapper sound-anchor"> +<div class="translated-sentence word-text"><</div> + +<div class="buttons"></div> +</div> + +<div class="translit"><</div> +</div> +</div> +</div> + +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms/How_to_build_custom_form_widgets", "Learn/HTML/Forms")}}</div> + +<p class="summary">Проверка данных формы позволяет нам удостовериться в том, что пользователи заполняют форму в правильном формате, убедиться, что отправленные данные будут успешно работать с нашими приложениями. Эта статья расскажет, что вам нужно знать о проверке формы.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Компьютерная грамотность, разумное понимание <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, и <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Понимать что такое проверка формы (валидация) формы, почему это важно и как это реализовать.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_валидация_формы">Что такое валидация формы?</h2> + +<p>Откройте любой популярный сайт с формой регистрации и вы заметите, что они дают вам обратную связь, когда вы вводите ваши данные не в том формате, который они ожидают от вас. Вы получите подобные сообщения:</p> + +<ul> + <li>"Это поле обязательно для заполнения" (вы не можете оставить это поле пустым)</li> + <li>"Пожалуйста введите ваш телефонный номер в формате xxx-xxxx" (вводит три цифры разделенные тире, за ними слеуют четыре цифры)</li> + <li>"Пожалуйста введите настоящий адрес электронной почты" (если ваша запись не в формате"somebody@example.com")</li> + <li>"Ваш пароль должен быть от 8 до 30 символов длиной, и содержать одну заглавную букву, один символ, и число"</li> +</ul> + +<p>Это называется валидация формы — когда вы вводите данные, веб-прилолжение проверяет, что данные корректны. Если данные верны, приложение позволяет данным быть отправленными на сервер и (как правило) быть сохраненными в базе данных; если нет - оно выдает вам сообщение об ошибке, обьясняющее какие исправления необходимо внести. Проверка формы может быть реализована несколькими различными способами.</p> + +<p>Мы хотим сделать заполнение веб-форм максимально простым. Итак, почему мы настаиваем на подтверждении наших форм? Существуют три основные причины:</p> + +<ul> + <li><strong>Мы хотим получить нужные данные в нужном формате</strong> — наши приложения не будут работать должным образом, если данные нашего пользователя хранятся в неправильном формате, если они вводят неправильную информацию или вообще не передают информацию.</li> + <li><strong>Мы хотим защитить учетные записи наших пользователей</strong> — заставляя наших пользователей вводить защищенные пароли, это упрощает защиту информации об их учетной записи.</li> + <li><strong>Мы хотим обезопасить себя</strong> — существует множество способов, которыми злоумышленники могут злоупотреблять незащищенными формами, чтобы повредить приложение, в которое они входят (см. <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Website_security">Безопасность веб-сайта</a>).</li> +</ul> + +<h3 id="Различные_типы_валидации_формы">Различные типы валидации формы</h3> + +<p>Существует два разных типа проверки формы, с которыми вы столкнетесь в Интернете:</p> + +<ul> + <li><strong>Проверка на стороне клиента - </strong>это проверка, которая происходит в браузере, прежде чем данные будут отправлены на сервер. Это удобнее, чем проверка на стороне сервера, так как дает мгновенный ответ. Ее можно далее подразделить на: + + <ul> + <li><strong>JavaScript</strong> проверка выполняется с использованием JavaScript. Полностью настраиваемая.</li> + <li><strong>Встроенная проверка формы, </strong>используя функции проверки формы HTML5. Для этого обычно не требуется JavaScript. Встроенная проверка формы имеет лучшую производительность, но она не такая настраиваемая, как с использованием JavaScript.</li> + </ul> + </li> + <li><strong>Проверка на стороне сервера</strong> - это проверка, которая возникает на сервере после отправки данных. Серверный код используется для проверки данных перед их сохранением в базе данных. Если данные не проходят проверку валидности, ответ отправляется обратно клиенту, чтобы сообщить пользователю, какие исправления должны быть сделаны. Проверка на стороне сервера не такая удобная, как проверка на стороне клиента, поскольку она не выдает ошибок до тех пор, пока не будет отправлена вся форма. Тем не менее, проверка на стороне сервера - это последняя линия защиты вашего приложения от неправильных или даже вредоносных данных. Все популярные <a href="/en-US/docs/Learn/Server-side/First_steps/Web_frameworks">серверные фреймворки</a> имеют функции для проверки и очистки данных (что делает их безопасными).</li> +</ul> + +<p>В реальном мире разработчики склонны использовать комбинацию проверки на стороне клиента и сервера.</p> + +<h2 id="Использование_встроенной_проверки_формы">Использование встроенной проверки формы</h2> + +<p>Одной из особенностей HTML5 является возможность проверки большинства пользовательских данных без использования скриптов. Это делается с помощью <a href="https://developer.mozilla.org/en-US/docs/HTML/HTML5/Constraint_validation">атрибутов проверки элементов формы</a>, которые позволяют вам указывать правила ввода формы, например, нужно ли заполнять значение, минимальная и максимальная длина данных, должно ли это быть число, адрес электронной почты, адрес или что-то еще, и шаблон, которому это должно соответствовать. Если введенные данные соответствуют всем этим правилам, данные считаются валидными; если нет - невалидными.</p> + +<p>Когда элемент валидный, следующие утверждения верны:</p> + +<ul> + <li>Элемент соответствует CSS псевдо-классу {{cssxref(":valid")}} ; это позволяет вам применить конкретный стиль к валидным элементам.</li> + <li>Если пользователь пытается отправить данные, браузер отправит форму, если нет ничего, остановит отправку (например, JavaScript).</li> +</ul> + +<p>Когда элемент невалидный, следующие утверждения верны:</p> + +<ul> + <li>Элемент соответствует CSS псевдо-классу {{cssxref(":invalid")}}, и иногда другим UI псевдо-классам (например, {{cssxref(":out-of-range")}}), в зависимости от ошибки; это позволяет вам применить конкретный стиль к невалидным элементам.</li> + <li>Если пользователь пытается отправить данные, браузер заблокирует форму и выдаст сообщение об ошибке.</li> +</ul> + +<div class="blockIndicator note"> +<p>Note: Вот несколько ошибок, которые не позволяют форме быть подтверждённой: {{domxref('validityState.badInput', 'badInput')}}, {{domxref('validityState.patternMismatch','patternMismatch')}}, {{domxref('validityState.rangeOverflow','rangeOverflow')}} or {{domxref('validityState.rangeUnderflow','rangeUnderflow')}}, {{domxref('validityState.stepMismatch','stepMismatch')}}, {{domxref('validityState.tooLong','tooLong')}} or {{domxref('validityState.tooShort','tooShort')}}, {{domxref('validityState.typeMismatch','typeMismatch')}}, {{domxref('validityState.valueMissing','valueMissing')}}, or a {{domxref('validityState.customError','customError')}}.</p> +</div> + +<h2 id="Примеры_встроенных_форм_валидации">Примеры встроенных форм валидации</h2> + +<h3 id="Ограничения_проверки_элементов_input_-_простое_начало">Ограничения проверки элементов input - простое начало</h3> + +<p>В этом разделе мы рассмотрим некоторые функции HTML5, которые можно использовать для проверки {{HTMLElement("input")}} элементов.</p> + +<p>Начнем с простого примера - input, который позволяет вам выбирать ваш любимый плод между бананом и вишней. Он включает простой текст {{HTMLElement("input")}} соответствующий ярлык (label) и отправку (submit) {{htmlelement("button")}}. Вы можете найти исходный код на GitHub <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-start.html">fruit-start.html</a>,и живой пример ниже:</p> + +<pre class="notranslate"><form> + <label for="choose">Would you prefer a banana or cherry?</label> + <input id="choose" name="i_like"> + <button>Submit</button> +</form></pre> + +<pre class="notranslate">input:invalid { + border: 2px dashed red; +} + +input:valid { + border: 2px solid black; +} +</pre> + +<p>{{EmbedLiveSample("Simple_start_file", "100%", 80)}}</p> + +<p>Для начала сделаем копию <code>fruit-start.html</code>в новом каталоге на жестком диске.</p> + +<h3 id="Требуемый_атрибут_required">Требуемый атрибут (required)</h3> + +<p>Простейшей функцией проверки HTML5 для использования является {{htmlattrxref("required", "input")}} атрибут. Если вы хотите сделать ввод обязательным, вы можете пометить элемент, используя этот атрибут. Если этот атрибут установлен, форма не будет отправляться (и будет отображаться сообщение об ошибке), когда поле пустое (поле input также будет считаться невалидным).</p> + +<p>Добавьте атрибут <code>required</code> в ваш input, как показано ниже:</p> + +<pre class="brush: html notranslate"><form> + <label for="choose">Would you prefer a banana or cherry?</label> + <input id="choose" name="i_like" required> + <button>Submit</button> +</form></pre> + +<p>Также обратите внимание на CSS, включенный в файл примера:</p> + +<pre class="notranslate">input:invalid { + border: 2px dashed red; +} + +input:invalid:required { + background-image: linear-gradient(to right, pink, lightgreen); +} + +input:valid { + border: 2px solid black; +}</pre> + +<p>В этом случае к input будет применяться ярко-красный пунктирный border, когда он невалидный, и более тонкая черная граница, когда он валидный. Попробуйте новое поведение в приведенном ниже примере:</p> + +<p>{{EmbedLiveSample("The_required_attribute", "100%", 80)}}</p> + +<div class="blockIndicator note"> +<p>Note: Вы можете найти этот пример на GitHub как <a href="https://mdn.github.io/learning-area/html/forms/form-validation/fruit-required.html">fruit-validation.html</a> (также смотрите <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-required.html">source code</a>.)</p> +</div> + +<p>Попробуйте эту форму без значения. Обратите внимание как невалидный ввод получает фокус, сообщение об ошибке ("Пожалуйста заполните поле") появляется, и форма не отправляется.</p> + +<h3 id="Проверка_с_регулярными_выражениями">Проверка с регулярными выражениями</h3> + +<p>Другая полезная функция проверки - это <kbd><a href="/ru/docs/Web/SVG/%D0%AD%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82/pattern">pattern</a> </kbd>атрибут , который ожидает <a href="/en-US/docs/JavaScript/Guide/Regular_Expressions">Regular Expression</a> в качестве значения. Регулярное выражение (regex) - это шаблон который используется для проверки соответствия символов в текстовых строках, поэтому он идеально подходит для проверки формы, а также для многих других целей в JavaScript.</p> + +<p>Регулярные выражения довольно сложны, и мы не будем подробно разбирать их в этой статье. Ниже приведены некоторые примеры, чтобы вы представляли себе, как они работают:</p> + +<ul> + <li><code>a</code> — соответствует одному символу <code>a</code> (не <code>b</code>, не <code>aa</code>, итд.)</li> + <li><code>abc</code> — соответствует <code>a</code>, далее <code>b</code>, далее <code>c</code>.</li> + <li><code>a*</code> — соответствует символу <code>a</code>, 0 или более раз (<code>+</code> соответствует символу один или несколько раз).</li> + <li><code>[^a]</code> — соответствует одному символу, <strong>не </strong>a.</li> + <li><code>a|b</code> — соответствует одному символу a или b.</li> + <li><code>[abc]</code> — соответствует одному символу a, b, или c.</li> + <li><code>[^abc]</code> — соответствует одному символу кроме a, b, или c.</li> + <li><code>[a-z]</code> — соответствует одному символу в диапазоне a–z, только в нижнем регистре (вы можете использовать <code>[A-Za-z]</code> для заглавных и прописных букв, и<code>[A-Z]</code> только для заглавных букв).</li> + <li><code>a.c</code> — соответсвует <code>a</code>, за ним следует любой элемент, за ним следует <code>c</code>.</li> + <li><code>a{5}</code> — соответствует <code>a</code>, 5 раз.</li> + <li><code>a{5,7}</code> — соответствует <code>a</code>, от 5 до 7 раз, но не больше и не меньше.</li> +</ul> + +<p>Вы также можете использовать числа и другие символы в этих выражениях, например:</p> + +<ul> + <li><code>[ -]</code> — соответствует пробелу или тире.</li> + <li><code>[0-9]</code> — соответствует любой цифре в диапазоне от 0 до 9.</li> +</ul> + +<p>Вы можете комбинировать их практически, как хотите, указывая разные части, одну за другой:</p> + +<ul> + <li><code>[Ll].*k</code> — Один символ L, в верхнем или нижнем регистре, за ним следует ни одного или несколько символов любого типа за которыми следует <code>k</code> в нижнем регистре.</li> + <li><code>[A-Z][A-Za-z' -]+</code> — Один символ верхнего регистра, за которым следует один или несколько символов, которые представляют собой букву верхнего или нижнего регистра, тире, апостроф или пробел. Это можно использовать для проверки названия городов / городов англоязычных стран, которые должны начинаться с заглавной буквы, но не содержать других символов. Примеры из UK включая Manchester, Ashton-under-lyne, и Bishop's Stortford.</li> + <li><code>[0-9]{3}[ -][0-9]{3}[ -][0-9]{4}</code> — Внутренний телефонный номер США — три цифры, затем пробел или тире, затем три цифры,затем пробел или тире, затем четыре цифры. Возможно, вам придется сделать это более сложным, поскольку некоторые люди пишут свой код области в круглых скобках, но это работает для простой демонстрации.</li> +</ul> + +<p>В любом случае, давайте реализуем пример - обновим ваш HTML, чтобы добавить атрибут шаблона, например:</p> + +<pre class="brush: html notranslate"><form> + <label for="choose">Would you prefer a banana or a cherry?</label> + <input id="choose" name="i_like" required pattern="banana|cherry"> + <button>Submit</button> +</form></pre> + +<div class="hidden"> +<pre class="brush: css notranslate">input:invalid { + border: 2px dashed red; +} + +input:valid { + border: 2px solid black; +}</pre> +</div> + +<p>{{EmbedLiveSample("Validating_against_a_regular_expression", "100%", 50)}}</p> + +<p>В этом примере {{HTMLElement("input")}} элемент принимает одно из двух возможных значений: строку "banana" или строку "cherry".</p> + +<p>На этом этапе попробуйте изменить значение внутри атрибута <code>pattern</code> чтобы сопоставить некоторые из примеров, которые вы видели ранее, и посмотрите, как это влияет на значения, которые вы можете ввести, чтобы сделать входное значение валидным. Попробуйте написать свои собственные, и посмотрите, как это работает! Попробуйте сделать их связанными с фруктами, где это возможно, поэтому ваши примеры имеют смысл!</p> + +<div class="note"> +<p><strong>Примечание:</strong> Некоторые {{HTMLElement("input")}} типы элементов не нуждаются в атрибуте {{htmlattrxref("pattern","input")}} чтобы быть валидными. Указание типа <code>email</code> например, проверяет введенное значение через регулярное выражение, соответствующее хорошо сформированному адресу электронной почты (или списку email адресов, разделенных запятыми, если в нем присутствует атрибут {{htmlattrxref("multiple","input")}} attribute). В качестве еще одного примера, поле с типом <code>url</code> автоматически требует правильно сформированного URL.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Элемент {{HTMLElement("textarea")}} не поддерживает атрибут {{htmlattrxref("pattern","input")}}.</p> +</div> + +<h3 id="Ограничение_длины_ваших_записей">Ограничение длины ваших записей</h3> + +<p>Все текстовые поля, созданные с помощью элементов ({{HTMLElement("input")}} или {{HTMLElement("textarea")}}) могут быть ограничены по размеру, используя атрибуты {{htmlattrxref("minlength","input")}} и{{htmlattrxref("maxlength","input")}}. Поле невалидно если его значение короче чем {{htmlattrxref("minlength","input")}} или значение длиннее значения {{htmlattrxref("maxlength","input")}}. Браузеры часто не позволяют пользователю вводить более длинное значение, чем ожидалось, в текстовые поля в любом случае, но полезно иметь этот мелкозернистый элемент управления.</p> + +<p>Для числовых полей (например <code><input type="number"></code>), атрибуты {{htmlattrxref("min","input")}} и {{htmlattrxref("max","input")}} также обеспечивают ограничение валидации. Если значение поля меньше атрибута {{htmlattrxref("min","input")}} или больше атрибута {{htmlattrxref("max","input")}}, поле будет невалидным.</p> + +<p>Давайте посмотрим на другой пример. Создайте новую копию файла <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-start.html">fruit-start.html</a>.</p> + +<p>Теперь удалите содержимое элемента <code><body></code>, и замените его следующим:</p> + +<pre class="brush: html notranslate"><form> + <div> + <label for="choose">Would you prefer a banana or a cherry?</label> + <input id="choose" name="i_like" required minlength="6" maxlength="6"> + </div> + <div> + <label for="number">How many would you like?</label> + <input type="number" id="number" name="amount" value="1" min="1" max="10"> + </div> + <div> + <button>Submit</button> + </div> +</form></pre> + +<ul> + <li>Здесь вы увидите, что мы задали полю <code>text</code> <code>minlength</code> <code>maxlength</code> равную 6 — такая же длина, как banana и cherry. Ввод меньшего количества символов будет отображаться как невалидный, а вводить больше в большинстве браузеров невозможно.</li> + <li>Мы также дали полю <code>number</code> <code>min</code> 1 и <code>max</code> 10 - числа введенные вне этого диапазона будут отображаться как невалидные, и вы не сможете использовать стрелки приращения / уменьшения, чтобы переместить значение за пределами этого диапазона.</li> +</ul> + +<div class="hidden"> +<pre class="notranslate">input:invalid { + border: 2px dashed red; +} + +input:valid { + border: 2px solid black; +} + +div { + margin-bottom: 10px; +}</pre> +</div> + +<p>Вот живой пример:</p> + +<p>{{EmbedLiveSample("Constraining_the_length_of_your_entries", "100%", 70)}}</p> + +<div class="note"> +<p><strong>Примечание</strong>: <code><input type="number"></code> (и другие типы, например <code>range</code>) могут также содержать атрибут {{htmlattrxref("step", "input")}} который указывает, какой инкремент будет увеличиваться или уменьшаться, когда используются элементы управления входом (например, номерные кнопки вверх и вниз)</p> +</div> + +<h3 id="Полный_пример">Полный пример</h3> + +<p>Вот полный пример, чтобы показать использование встроенных функций проверки HTML:</p> + +<pre class="brush: html notranslate"><form> + <p> + <fieldset> + <legend>Title<abbr title="This field is mandatory">*</abbr></legend> + <input type="radio" required name="title" id="r1" value="Mr"><label for="r1">Mr.</label> + <input type="radio" required name="title" id="r2" value="Ms"><label for="r2">Ms.</label> + </fieldset> + </p> + <p> + <label for="n1">How old are you?</label> + <!-- The pattern attribute can act as a fallback for browsers which + don't implement the number input type but support the pattern attribute. + Please note that browsers that support the pattern attribute will make it + fail silently when used with a number field. + Its usage here acts only as a fallback --> + <input type="number" min="12" max="120" step="1" id="n1" name="age" + pattern="\d+"> + </p> + <p> + <label for="t1">What's your favorite fruit?<abbr title="This field is mandatory">*</abbr></label> + <input type="text" id="t1" name="fruit" list="l1" required + pattern="[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range"> + <datalist id="l1"> + <option>Banana</option> + <option>Cherry</option> + <option>Apple</option> + <option>Strawberry</option> + <option>Lemon</option> + <option>Orange</option> + </datalist> + </p> + <p> + <label for="t2">What's your e-mail?</label> + <input type="email" id="t2" name="email"> + </p> + <p> + <label for="t3">Leave a short message</label> + <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea> + </p> + <p> + <button>Submit</button> + </p> +</form></pre> + +<pre class="brush: css notranslate">body { + font: 1em sans-serif; + padding: 0; + margin : 0; +} + +form { + max-width: 200px; + margin: 0; + padding: 0 5px; +} + +p > label { + display: block; +} + +input[type=text], +input[type=email], +input[type=number], +textarea, +fieldset { +/* требуется для правильной формы формы + элементов в браузерах на основе WebKit*/ + -webkit-appearance: none; + + width : 100%; + border: 1px solid #333; + margin: 0; + + font-family: inherit; + font-size: 90%; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +input:invalid { + box-shadow: 0 0 5px 1px red; +} + +input:focus:invalid { + outline: none; +}</pre> + +<p>{{EmbedLiveSample("Full_example", "100%", 420)}}</p> + +<h3 id="Индивидуальные_сообщения_об_ошибках">Индивидуальные сообщения об ошибках</h3> + +<p>Как видно из приведенных выше примеров, каждый раз, когда пользователь пытается отправить невалидную форму, браузер отображает сообщение об ошибке. Способ отображения этого сообщения зависит от браузера.</p> + +<p>Эти автоматизированные сообщения имеют два недостатка:</p> + +<ul> + <li>Нет стандартного способа изменить внешний вид используя CSS.</li> + <li>Они зависят от языка браузера, что означает, что у вас может быть страница на одном языке, но сообщение об ошибке отображаться на другом языке.</li> +</ul> + +<table> + <caption>Французская версия сообщений обратной связи на странице на английском языке</caption> + <thead> + <tr> + <th scope="col">Браузер</th> + <th scope="col">Отображение</th> + </tr> + </thead> + <tbody> + <tr> + <td>Firefox 17 (Windows 7)</td> + <td><img alt="Example of an error message with Firefox in French on an English page" src="/files/4329/error-firefox-win7.png" style="height: 97px; width: 228px;"></td> + </tr> + <tr> + <td>Chrome 22 (Windows 7)</td> + <td><img alt="Example of an error message with Chrome in French on an English page" src="/files/4327/error-chrome-win7.png" style="height: 96px; width: 261px;"></td> + </tr> + <tr> + <td>Opera 12.10 (Mac OSX)</td> + <td><img alt="Example of an error message with Opera in French on an English page" src="/files/4331/error-opera-macos.png" style="height: 83px; width: 218px;"></td> + </tr> + </tbody> +</table> + +<p>Чтобы настроить внешний вид и текст этих сообщений, вы должны использовать JavaScript; нет способа сделать это, используя только HTML и CSS.</p> + +<p>HTML5 предоставляет <a href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api">API проверки ограничений </a>(API - Application Programing interface, программный интерфейс приложения, англ.) для проверки и настройки состояния элемента формы. Помимо прочего, можно заменить текст сообщения об ошибке. Давайте посмотрим на небольшой пример:</p> + +<pre class="brush: html notranslate"><form> + <label for="mail">I would like you to provide me an e-mail</label> + <input type="email" id="mail" name="mail"> + <button>Submit</button> +</form></pre> + +<p>В JavaScript вы вызываете метод <a href="/en-US/docs/HTML/HTML5/Constraint_validation#Constraint_API's_element.setCustomValidity()"><code>setCustomValidity()</code></a>:</p> + +<pre class="brush: js notranslate">var email = document.getElementById("mail"); + +email.addEventListener("input", function (event) { + if (email.validity.typeMismatch) { + email.setCustomValidity("I expect an e-mail, darling!"); + } else { + email.setCustomValidity(""); + } +});</pre> + +<p>{{EmbedLiveSample("Customized_error_messages", "100%", 50)}}</p> + +<h2 id="Проверка_форм_с_использованием_JavaScript">Проверка форм с использованием JavaScript</h2> + +<p>Если вы хотите контролировать внешний вид собственных сообщений об ошибках или работать с браузерами, которые не поддерживают встроенную проверку формы HTML, вы должны использовать JavaScript.</p> + +<h3 id="API_проверки_валидности_HTML5">API проверки валидности HTML5</h3> + +<p>Все больше браузеров теперь поддерживают API проверки ограничений, и он становится надежным. Этот API состоит из набора методов и свойств, доступных для каждого элемента формы.</p> + +<h4 id="Свойства_API_проверки_валидности">Свойства API проверки валидности</h4> + +<table> + <thead> + <tr> + <th scope="col">Свойство</th> + <th scope="col">Описание</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>validationMessage</code></td> + <td>Локализованное сообщение, описывающее ограничения валидности, которым элемент управления не соответствует (если есть), или пустая строка, если элемент управления не является кандидатом для проверки ограничений (<code>willValidate</code> is <code>false</code>), или значение элемента удовлетворяет его ограничениям.</td> + </tr> + <tr> + <td><code>validity</code></td> + <td>объект {{domxref("ValidityState")}} , описывающий состояние действительности элемента.</td> + </tr> + <tr> + <td><code>validity.customError</code></td> + <td>Возвращает <code>true</code> если элемент содержит пользовательскую ошибку; <code>false</code> в противном случае.</td> + </tr> + <tr> + <td><code>validity.patternMismatch</code></td> + <td>Возвращает <code>true</code> если значение элемента не соответствует предоставленному шаблону; <code>false</code> в противном случае.<br> + <br> + если возвращает <code>true</code>, элемент будет соответствовать CSS псевдо-классу {{cssxref(":invalid")}}.</td> + </tr> + <tr> + <td><code>validity.rangeOverflow</code></td> + <td>Возвращает <code>true</code> если значение элемента выше заданного максимума; <code>false</code> в противном случае.<br> + <br> + Если возвращает <code>true</code>, элемент будет соответствовать {{cssxref(":invalid")}} и CSS псевдо-классу. {{cssxref(":out-of-range")}}.</td> + </tr> + <tr> + <td><code>validity.rangeUnderflow</code></td> + <td>Возвращает<code>true</code> если значение элемента меньше заданного минимума; <code>false</code> в противном случае.<br> + <br> + Если возвращает <code>true</code>, элемент будет соответствовать {{cssxref(":invalid")}} и CSS псевдо-классу {{cssxref(":out-of-range")}}.</td> + </tr> + <tr> + <td><code>validity.stepMismatch</code></td> + <td>Возвращает<code>true,</code> если значение элемента не соответствует правилам, предоставляемым атрибутом step; в противном случае <code>false</code> .<br> + <br> + <code><font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">Если возвращает </span></font>true</code>, элемент будет соответствовать {{cssxref(":invalid")}} и CSS псевдоклассу {{cssxref(":out-of-range")}}.</td> + </tr> + <tr> + <td><code>validity.tooLong</code></td> + <td>Возвращает <code>true</code> если значение элемента больше заданной максимальной длины; иначе будет false<br> + <br> + Если возвращает <code>true</code>, элемент будет соответствовать {{cssxref(":invalid")}} и CSS псевдоклассу {{cssxref(":out-of-range")}}.</td> + </tr> + <tr> + <td><code>validity.typeMismatch</code></td> + <td>Возвращает true если значение элемента не соответствует правильному синтаксису; в противном случае - false.<br> + Если возвращает <code>true</code>, элемент будет соответствовать CSS псевдоклассу {{cssxref(":invalid")}}.</td> + </tr> + <tr> + <td><code>validity.valid</code></td> + <td>Возвращае <code>true</code> если значение элемента не имеет проблем с валидностью; в противном случае <code>false</code>.<br> + <br> + Если возвращает <code>true</code>, элемент будет соответствовать CSS псевдоклассу {{cssxref(":valid")}} ; CSS псевдоклассу {{cssxref(":invalid")}} в противном случае.</td> + </tr> + <tr> + <td><code>validity.valueMissing</code></td> + <td>Возвращает true если элемент не имеет значения, но является обязательным полем; в противном случае false.<br> + <br> + Если возвращает <code>true</code>, элемент будет соответствовать CSS псевдоклассу {{cssxref(":invalid")}}.</td> + </tr> + <tr> + <td><code>willValidate</code></td> + <td>Возвращает <code>true</code> если элемент будет проверен при отправке формы; в противном случае <code>false</code>.</td> + </tr> + </tbody> +</table> + +<h4 id="Методы_API_проверки_ограничений">Методы API проверки ограничений</h4> + +<table> + <thead> + <tr> + <th scope="col">Метод</th> + <th scope="col">Описание</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>checkValidity()</code></td> + <td>Возвращает <code>true</code> если значение элемента не имеет проблем с валидностью; иначе <code>false</code>. Если элемент невалидный, этот метод также вызывает событие {{event("invalid")}} в элементе .</td> + </tr> + <tr> + <td><code>setCustomValidity(<em>message</em>)</code></td> + <td>Добавляет настраиваемое сообщение об ошибке в элемент; если вы установили собственное сообщение об ошибке, элемент считается невалидным, и отображается указанная ошибка. Это позволяет использовать код JavaScript для установления ошибки валидации, отличного от тех, которые предлагаются стандартным API ограничений валидности. Сообщение показывается пользователю при возникновении проблемы.<br> + <br> + Если аргументом является пустая строка, пользовательская ошибка очищается.</td> + </tr> + </tbody> +</table> + +<p>Для устаревших браузеров можно использовать полифилл как <a href="https://hyperform.js.org/" rel="external">Hyperform </a> чтобы компенсировать отсутствие поддержки API ограничений валидности. Поскольку вы уже используете JavaScript, использование полифилла не является дополнительным бременем для вашего веб-сайта или дизайна или реализации веб-приложения.</p> + +<h4 id="Пример_использования_API_проверки_ограничений">Пример использования API проверки ограничений</h4> + +<p>Давайте посмотрим, как использовать этот API для создания настраиваемых сообщений об ошибках. Сначала HTML:</p> + +<pre class="brush: html notranslate"><form novalidate> + <p> + <label for="mail"> + <span>Please enter an email address:</span> + <input type="email" id="mail" name="mail"> + <span class="error" aria-live="polite"></span> + </label> + </p> + <button>Submit</button> +</form></pre> + +<p>Эта простая форма использует атрибут {{htmlattrxref("novalidate","form")}} для отключения автоматической валидации браузера, что позволяет нашему скрипту контролировать валидацию. Однако это не отключает поддержку API ограничений валидации или применения псевдоклассов CSS {{cssxref(":valid")}}, {{cssxref(":invalid")}}, {{cssxref(":in-range")}} и {{cssxref(":out-of-range")}}. Это означает, что, хотя браузер не проверяет правильность формы перед отправкой своих данных, вы все равно можете сделать это самостоятельно и соответствующим образом сформировать форму.</p> + +<p>Атрибут <a href="/en-US/docs/Accessibility/ARIA/ARIA_Live_Regions"><code>aria-live</code></a> гарантирует, что наше индивидуальное сообщение об ошибке будет доступно всем, включая тех, кто использует вспомогательные технологии, такие как скрин-ридеры.</p> + +<h5 id="CSS">CSS</h5> + +<p>Этот CSS задает стили нашей форме и выводу ошибки, чтобы сделать их визуально более привлекательными.</p> + +<pre class="brush: css notranslate">/* Это просто, чтобы сделать пример более приятным */ +body { + font: 1em sans-serif; + padding: 0; + margin : 0; +} + +form { + max-width: 200px; +} + +p * { + display: block; +} + +input[type=email]{ + -webkit-appearance: none; + + width: 100%; + border: 1px solid #333; + margin: 0; + + font-family: inherit; + font-size: 90%; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +/* Наш стиль для невалидных полей */ +input:invalid{ + border-color: #900; + background-color: #FDD; +} + +input:focus:invalid { + outline: none; +} + +/* Это стиль для сообщений об ошибке */ +.error { + width : 100%; + padding: 0; + + font-size: 80%; + color: white; + background-color: #900; + border-radius: 0 0 5px 5px; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.error.active { + padding: 0.3em; +}</pre> + +<h5 id="JavaScript">JavaScript</h5> + +<p>Следующий код JavaScript обрабатывает выборочную проверку ошибок.</p> + +<pre class="brush: js notranslate">//Существует много способов выбрать DOM узел; здесь мы получаем форму и электронную почту +//поле ввода, а также элемент span, в который мы поместим сообщение об ошибке. +var form = document.getElementsByTagName('form')[0]; +var email = document.getElementById('mail'); +var error = document.querySelector('.error'); + +email.addEventListener("input", function (event) { + // Каждый раз, когда пользователь вводит что-либо, мы проверяем, + // является ли корректным поле электронной почты. + if (email.validity.valid) { + // В случае появления сообщения об ошибке, если поле + // является корректным, мы удаляем сообщение об ошибке. + error.innerHTML = ""; // Сбросить содержимое сообщения + error.className = "error"; // Сбросить визуальное состояние сообщения + } +}, false); +form.addEventListener("submit", function (event) { + // Каждый раз, когда пользователь пытается отправить данные, мы проверяем + // валидность поля электронной почты. + if (!email.validity.valid) { + + // Если поле невалидно, отображается пользовательское + // сообщение об ошибке. + error.innerHTML = "I expect an e-mail, darling!"; + error.className = "error active"; + // И мы предотвращаем отправку формы путем отмены события + event.preventDefault(); + } +}, false);</pre> + +<p>Вот живой результат:</p> + +<p>{{EmbedLiveSample("Example_using_the_constraint_validation_API", "100%", 130)}}</p> + +<p>API ограничений валидации дает вам мощный инструмент для проверки формы, позволяя вам получить контроль над пользовательским интерфейсом больше и лучше того, что вы можете делать только при помощи HTML и CSS.</p> + +<h3 id="Проверка_форм_без_встроенного_API">Проверка форм без встроенного API</h3> + +<p>Иногда, например, с устаревшими браузерами или <a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">пользовательскими виджетами</a>, вы не сможете (или не захотите) использовать API проверки ограничений. В этом случае вы все еще можете использовать JavaScript для проверки вашей формы. Проверка формы - это скорее вопрос пользовательского интерфейса, чем проверка валидности данных.</p> + +<p>Чтобы проверить форму, вы должны задать себе несколько вопросов:</p> + +<dl> + <dt>Какую проверку я должен выполнить?</dt> + <dd>Вам нужно определить, как проверить ваши данные: операции со строками, преобразование типов, регулярные выражения и т. д. Это зависит от вас. Просто помните, что данные формы всегда являются текстовыми и всегда предоставляются вашему скрипту как строки.</dd> + <dt>Что делать, если форма не проверяется?</dt> + <dd>Это явно вопрос интерфейса. Вы должны решить, как будет выглядеть форма: формально ли отправляет данные? Должны ли вы выделять поля, которые содержат ошибки? Должны отображаться сообщения об ошибках?</dd> + <dt>Как я могу помочь пользователю исправить невалидные данные?</dt> + <dd>Чтобы уменьшить разочарование пользователя, очень важно предоставить как можно больше полезной информации, чтобы помочь им в исправлении их исходных данных. Вы должны предлагать предварительные предложения, чтобы они знали, что ожидается, а также ясные сообщения об ошибках. Если вы хотите вникнуть в требования к пользовательскому интерфейсу проверки формы, есть некоторые полезные статьи, которые вы должны прочитать: + <ul> + <li>SmashingMagazine: <a href="http://uxdesign.smashingmagazine.com/2012/06/27/form-field-validation-errors-only-approach/" rel="external">Подтверждение формы поля: подход, основанный на ошибках</a></li> + <li>SmashingMagazine: <a href="http://www.smashingmagazine.com/2009/07/07/web-form-validation-best-practices-and-tutorials/" rel="external">Проверка веб-формы: лучшие практики и учебные пособия</a></li> + <li>Six Revision: <a href="http://sixrevisions.com/user-interface/best-practices-for-hints-and-validation-in-web-forms/" rel="external">Рекомендации по подсказкам и валидации в веб-формах</a></li> + <li>A List Apart: <a href="http://www.alistapart.com/articles/inline-validation-in-web-forms/" rel="external">Встроенная проверка в веб-формах</a></li> + </ul> + </dd> +</dl> + +<h4 id="Пример_который_не_использует_API_валидации_ограничений">Пример, который не использует API валидации ограничений</h4> + +<p>Чтобы проиллюстрировать это, давайте перестроим предыдущий пример, чтобы он работал с устаревшими браузерами:</p> + +<pre class="brush: html notranslate"><form> + <p> + <label for="mail"> + <span>Please enter an email address:</span> + <input type="text" class="mail" id="mail" name="mail"> + <span class="error" aria-live="polite"></span> + </label> + <p> + <!-- Some legacy browsers need to have the `type` attribute + explicitly set to `submit` on the `button`element --> + <button type="submit">Submit</button> +</form></pre> + +<p>Как вы можете видеть, HTML почти такой же; мы просто удалили функции проверки HTML. Обратите внимание, что <a href="/en-US/docs/Accessibility/ARIA">ARIA</a> является независимой спецификацией, которая специально не связана с HTML5.</p> + +<h5 id="CSS_2">CSS</h5> + +<p>Аналогично, CSS не нужно сильно менять; мы просто переводим CSS-псевдокласс {{cssxref(":invalid")}} в настоящий класс и избегаем использования селектора атрибутов, который не работает в Internet Explorer 6.</p> + +<pre class="brush: css notranslate">/* This is just to make the example nicer */ +body { + font: 1em sans-serif; + padding: 0; + margin : 0; +} + +form { + max-width: 200px; +} + +p * { + display: block; +} + +input.mail { + -webkit-appearance: none; + + width: 100%; + border: 1px solid #333; + margin: 0; + + font-family: inherit; + font-size: 90%; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +/* This is our style for the invalid fields */ +input.invalid{ + border-color: #900; + background-color: #FDD; +} + +input:focus.invalid { + outline: none; +} + +/* This is the style of our error messages */ +.error { + width : 100%; + padding: 0; + + font-size: 80%; + color: white; + background-color: #900; + border-radius: 0 0 5px 5px; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.error.active { + padding: 0.3em; +}</pre> + +<h5 id="JavaScript_2">JavaScript</h5> + +<p>Большие изменения в коде JavaScript, которые должны сделать намного больше тяжелой работы.</p> + +<pre class="brush: js notranslate">// Существует меньше способов выбрать узел DOM с устаревшими браузерами +var form = document.getElementsByTagName('form')[0]; +var email = document.getElementById('mail'); + +// Ниже приведен трюк для достижения следующего узла Element Element в DOM +// Это опасно, потому что вы можете легко построить бесконечный цикл. +// В современных браузерах вам следует использовать элемент element.nextElementSibling +var error = email; +while ((error = error.nextSibling).nodeType != 1); + +// As per the HTML5 Specification +var emailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/; + +// Многие устаревшие браузеры не поддерживают метод addEventListener. +// Вот простой способ справиться с этим; это далеко не единственный. +function addEvent(element, event, callback) { + var previousEventCallBack = element["on"+event]; + element["on"+event] = function (e) { + var output = callback(e); + + // Обратный вызов, который возвращает `false`, останавливает цепочку обратного вызова + // и прерывает выполнение обратного вызова события. + if (output === false) return false; + + if (typeof previousEventCallBack === 'function') { + output = previousEventCallBack(e); + if(output === false) return false; + } + } +}; + +// Теперь мы можем перестроить наше ограничение валидации +// Поскольку мы не полагаемся на псевдо-класс CSS, мы должны +// явно установить допустимый / недопустимый класс в поле электронной почты +addEvent(window, "load", function () { +// Здесь мы проверяем, пусто ли поле (помните, что поле не требуется) + // Если это не так, мы проверяем, является ли его контент корректным адресом электронной почты. + var test = email.value.length === 0 || emailRegExp.test(email.value); + + email.className = test ? "valid" : "invalid"; +}); + +// Это определяет, что происходит, когда пользователь вводит в поле +addEvent(email, "input", function () { + var test = email.value.length === 0 || emailRegExp.test(email.value); + if (test) { + email.className = "valid"; + error.innerHTML = ""; + error.className = "error"; + } else { + email.className = "invalid"; + } +}); + +// Это определяет, что происходит, когда пользователь пытается отправить данные +addEvent(form, "submit", function () { + var test = email.value.length === 0 || emailRegExp.test(email.value); + + if (!test) { + email.className = "invalid"; + error.innerHTML = "I expect an e-mail, darling!"; + error.className = "error active"; + + // Некоторые устаревшие браузеры не поддерживают метод event.preventDefault () + return false; + } else { + email.className = "valid"; + error.innerHTML = ""; + error.className = "error"; + } +});</pre> + +<p>Результат выглядит следующим образом:</p> + +<p>{{EmbedLiveSample("Example_that_doesn't_use_the_constraint_validation_API", "100%", 130)}}</p> + +<p>Как вы можете видеть, создать собственную систему проверки не сложно. Трудная часть состоит в том, чтобы сделать его достаточно общим, чтобы использовать его как в кросс-платформенной, так и в любой форме, которую вы могли бы создать. Существует множество библиотек для проверки формы; вы не должны колебаться, чтобы использовать их. Вот несколько примеров:</p> + +<ul> + <li>Автономная библиотека + <ul> + <li><a href="http://rickharrison.github.com/validate.js/" rel="external">Validate.js</a></li> + </ul> + </li> + <li>jQuery plug-in: + <ul> + <li><a href="http://bassistance.de/jquery-plugins/jquery-plugin-validation/" rel="external">Validation</a></li> + </ul> + </li> +</ul> + +<h4 id="Удаленная_проверка">Удаленная проверка</h4> + +<p>В некоторых случаях может быть полезно выполнить некоторую удаленную проверку. Такая проверка необходима, когда данные, введенные пользователем, привязаны к дополнительным данным, хранящимся на стороне сервера вашего приложения. Одним из вариантов использования является регистрационные формы, в которых вы запрашиваете имя пользователя. Чтобы избежать дублирования, разумнее выполнить AJAX запрос для проверки доступности имени пользователя, а не попросить пользователя отправить данные, а затем отправить форму с ошибкой.</p> + +<p>Выполнение такой проверки требует принятия нескольких мер предосторожности:</p> + +<ul> + <li>Для этого требуется публиковать API и некоторые данные; убедитесь, что это не конфиденциальные данные.</li> + <li>Сетевое отставание требует выполнения асинхронной проверки. Это требует некоторой работы пользовательского интерфейса, чтобы быть уверенным, что пользователь не будет заблокирован, если проверка не будет выполнена должным образом.</li> +</ul> + +<h2 id="Заключение">Заключение</h2> + +<p>Проверка формы не требует сложного JavaScript, но она требует тщательного изучения пользователя. Всегда помните, чтобы помочь вашему пользователю исправить данные, которые они предоставляют. Для этого обязательно выполните следующие действия:</p> + +<ul> + <li>Отображать явные сообщения об ошибках.</li> + <li>Будьте правдоподобны в отношении формата ввода.</li> + <li>Укажите, где именно происходит ошибка (особенно на больших формах).</li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms/How_to_build_custom_form_widgets", "Learn/HTML/Forms")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Ваша первая HTML-форма</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">Как структурировать форму HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">Нативная форма виджетов</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Отправка данных формы</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Проверка данных формы</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">Как создать пользовательские виджеты формы</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Отправка форм через JavaScript</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML-формы в старых браузерах</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Стилизация HTML-форм</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Расширенный стиль для HTML-форм</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Таблица совместимости свойств виджета формы</a></li> +</ul> diff --git a/files/ru/learn/html/forms/ваша_первая_html_форма/index.html b/files/ru/learn/html/forms/ваша_первая_html_форма/index.html new file mode 100644 index 0000000000..b68d433739 --- /dev/null +++ b/files/ru/learn/html/forms/ваша_первая_html_форма/index.html @@ -0,0 +1,305 @@ +--- +title: Ваша первая HTML форма +slug: Learn/HTML/Forms/Ваша_первая_HTML_форма +tags: + - HTML-форма + - Веб-форма + - Форма +translation_of: Learn/Forms/Your_first_form +--- +<div>{{LearnSidebar}}{{NextMenu("Learn/HTML/Forms/How_to_structure_an_HTML_form", "Learn/HTML/Forms")}}</div> + +<p class="summary">Первая статья в данной главе предоставит вам первый опыт создания веб-форм, в том числе проектирование простой формы, её реализацию с использованием HTML-элементов управления формой и других HTML-элементов, добавление стилей через CSS и описание того, как данные из формы отсылаются на сервер. Мы более подробно остановимся на каждой из этих подтем далее в статье.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовое представление о компьютерах и <a href="/ru/docs/Learn/HTML/Введение_в_HTML">базовое понимание HTML</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Ознакомиться с веб-формами, узнать, для чего они используются, как их проектировать, и какие базовые HTML-элементы могут понадобиться в простых ситуациях.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_Веб-форма">Что такое Веб-форма?</h2> + +<p><strong>Веб-формы</strong> являются одним из основных элементов взаимодействия между пользователем и сайтом или приложением. Формы позволяют пользователю ввести данные, которые затем отправляются на сервер для их дальнейшей обработки и хранения или используются на стороне клиента для обновления интерфейса (например, добавление нового элемента в список или открытие и закрытие элемента интерфейса).</p> + +<p><strong>Веб-формы</strong> — их также часто называют <strong>HTML-формы</strong> — состоят из одного или нескольких <strong>элементов управления форм</strong> (иногда их также называют <strong>виджетами</strong>) и некоторых дополнительных элементов для структурирования формы. Элементами управления могут быть однострочные или многострочные текстовые поля, выпадающие списки, кнопки, чекбоксы, радио-баттоны, большинство из которых создаются через html-элемент {{htmlelement("input")}}, однако есть и другие элементы, о которых тоже стоит узнать.</p> + +<p>В элементах управления форм можно задать правила, указывающие на определенный формат данных или значений, которые могут быть введены (<strong>валидация форм</strong>), а также к ним могут быть добавлены текстовые строки, описывающие эти элементы для зрячих и незрячих пользователей.</p> + +<h2 id="Проектирование_формы">Проектирование формы</h2> + +<p>Перед тем, как начать программировать, всегда лучше остановиться и подумать о вашей форме. Создание быстрого наброска поможет определить верный набор данных, которые вы хотите получить от пользователя. С точки зрения UX, удобства использования интерфейса, важно помнить о том, что чем длиннее ваша форма, тем больше риск потерять пользователей. Сделайте форму краткой и лаконичной: спрашивайте только о той информации, которая вам действительно необходима.</p> + +<p>Проектирование форм является важным этапом при создании сайта или приложения. Удобство использования форм (UX) выходит за рамки данной статьи, однако если вы хотите углубиться в эту тему, то вам следует прочитать следующие статьи:</p> + +<ul> + <li>На Smashing Magazine есть <a href="https://www.smashingmagazine.com/2018/08/ux-html5-mobile-form-part-1/" rel="external" title="http://uxdesign.smashingmagazine.com/tag/forms/">хорошие статьи на тему UX в HTML-формах</a>, включая старую, но всё ещё актуальную статью <a href="https://www.smashingmagazine.com/2011/11/extensive-guide-web-form-usability/" rel="external" title="http://uxdesign.smashingmagazine.com/2011/11/08/extensive-guide-web-form-usability/">Extensive Guide To Web Form Usability</a>.</li> + <li>Также есть UXMatters — хороший ресурс с полезными советами от <a href="http://www.uxmatters.com/mt/archives/2012/05/7-basic-best-practices-for-buttons.php" rel="external" title="http://www.uxmatters.com/mt/archives/2012/05/7-basic-best-practices-for-buttons.php">базовых лучших практик</a> до сложных решений, таких как <a href="http://www.uxmatters.com/mt/archives/2010/03/pagination-in-web-forms-evaluating-the-effectiveness-of-web-forms.php" title="http://www.uxmatters.com/mt/archives/2010/03/pagination-in-web-forms-evaluating-the-effectiveness-of-web-forms.php">мультистраничные формы</a>.</li> +</ul> + +<p>В этой статье мы создадим простую контактную форму. Давайте сделаем набросок.</p> + +<p><img alt="The form to build, roughly sketch" src="/files/4579/form-sketch-low.jpg" style="border-style: solid; border-width: 1px; display: block; height: 352px; margin: 0px auto; width: 400px;"></p> + +<p>Наша форма будет состоять из трёх текстовых полей и одной кнопки. Мы узнаём у пользователя его имя, e-mail и сообщение, которое он хочет отправить. После нажатия на кнопку данные будут отправлены на веб-сервер.</p> + +<h2 id="Активное_обучение_Реализация_HTML-формы">Активное обучение: Реализация HTML-формы</h2> + +<p>Итак, теперь мы готовы обратиться к HTML и создать нашу форму. Для этого мы будем использовать следующие HTML-элементы: {{HTMLelement("form")}}, {{HTMLelement("label")}}, {{HTMLelement("input")}}, {{HTMLelement("textarea")}} и {{HTMLelement("button")}}.</p> + +<p>Прежде, чем продолжить, скопируйте <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">простой HTML-шаблон</a> — вы будете создавать свою форму внутри него.</p> + +<h3 id="Элемент_HTMLelementform">Элемент {{HTMLelement("form")}}</h3> + +<p>Создание форм начинается с элемента {{HTMLelement("form")}}:</p> + +<pre class="brush:html; notranslate"><form action="/my-handling-form-page" method="post"> + +</form></pre> + +<p>Этот элемент формально определяет форму. Он является элементом-контейнером, как HTML-элементы {{HTMLelement("div")}} или {{HTMLelement("p")}}, но при этом он поддерживает некоторые специфические атрибуты для настройки поведения формы. Все атрибуты являются опциональными, но в стандартной практике принято указывать атрибуты <code>action</code> и <code>method</code>:</p> + +<ul> + <li>Атрибут <code>action</code> определяет адрес, куда должны быть посланы данные после отправки формы.</li> + <li>Атрибут <code>method</code> указывает, какой HTTP-метод будет использован при передаче данных (это может быть "get" или "post").</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Мы детальнее разберём работу этих атрибутов далее в статье <a href="/ru/docs/Learn/HTML/Forms/Отправка_и_Получение_данных_формы" title="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data">Отправка данных формы</a>.</p> +</div> + +<p>Теперь добавьте указанный выше код с элементом {{htmlelement("form")}} внутрь тега {{htmlelement("body")}} в вашем HTML.</p> + +<h3 id="Элементы_HTMLelementlabel_HTMLelementinput_и_HTMLelementtextarea">Элементы {{HTMLelement("label")}}, {{HTMLelement("input")}} и {{HTMLelement("textarea")}}</h3> + +<p>Наша контактная форма несложная: часть, в которую будут вводиться данные, состоит из трёх текстовых полей, каждое их которых связано с HTML-элементом {{HTMLelement("label")}}:</p> + +<ul> + <li>Поле ввода для имени — {{HTMLelement("input/text", "single-line text field")}}</li> + <li>Поле ввода для e-mail — {{HTMLelement("input/email", "input of type email")}}: однострочное текстовое поле, которое принимает только e-mail адреса.</li> + <li>Поле ввода для сообщения — {{HTMLelement("textarea")}}, многострочное текстовое поле.</li> +</ul> + +<p>В терминах HTML нам нужен код наподобие представленного ниже, чтобы добавить виджеты форм:</p> + +<pre class="brush:html; notranslate" dir="rtl"><form action="/my-handling-form-page" method="post"> + <ul> + <li> + <label for="name">Name:</label> + <input type="text" id="name" name="user_name"> + </li> + <li> + <label for="mail">E-mail:</label> + <input type="email" id="mail" name="user_mail"> + </li> + <li> + <label for="msg">Message:</label> + <textarea id="msg" name="user_message"></textarea> + </li> + </ul> +</form></pre> + +<p>Добавьте в вашу форму код, чтобы она выглядела так же, как форма выше.</p> + +<p>Здесь элементы {{HTMLelement("li")}} используются для структурирования кода и облегчения стилизации (будет разобрано далее в статье). Для доступности и удобства использования мы указали определённый текст-подсказку для каждого элемента управления. Обратите внимание на использование атрибута <code>for</code> на каждом элементе {{HTMLelement("label")}}, который принимает в качестве значение <code>id</code> элемента управления формы, с которым он связан — этот подход позволяет привязать тексты-подсказки к форме.</p> + +<p>Такой подход полезен тем, что позволяет пользователям с мышью, трекпадом и сенсорным устройством кликнуть на текст-подсказку для активации связанного с ним виджета формы, а также обеспечивает читабельное имя для пользователей скрин-ридеров. Вы найдёте более детальный разбор текстов-подсказок в статье <a href="/ru/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form" title="/en-US/docs/HTML/Forms/How_to_structure_an_HTML_form">Как структурировать HTML-форму</a>.</p> + +<p>В HTML-элементе {{HTMLelement("input")}} самым важным атрибутом является атрибут <code>type</code>. Этот атрибут чрезвычайно важен, потому что он определяет внешний вид и поведение элемента {{HTMLelement("input")}}. Вы найдёте больше информации об этом далее в статье <a href="/ru/docs/Learn/HTML/Forms/Стандартные_виджеты_форм" rel="external" title="/en-US/docs/HTML/Forms/The_native_forms_widgets">Стандартные виджеты форм</a>.</p> + +<ul> + <li>В нашем простом примере мы используем {{HTMLelement("input/text")}} для первого поля ввода — значение по умолчанию для данного атрибута. Оно представляет однострочное текстовое поле, которое может принимать любые значения.</li> + <li>Для второго поля ввода мы используем тип {{HTMLelement("input/email")}}, который представляет собой однострочное текстовое поле, которое принимает в качестве значения корректно составленный e-mail адрес. Он делает простое текстовое поле "умным", позволяя проверять введёные пользователем данные на корректность. Также это позволяет открывать более подходящие для ввода e-mail адреса клавиатуры (например, с символом @ при базовой раскладке) на устройствах с динамической клавиатурой, таких как смартфоны. Вы найдёте более подробную информацию про валидацию форм далее в статье <a href="/ru/docs/Learn/HTML/Forms/Валидация_формы" title="/en-US/docs/HTML/Forms/Data_form_validation">Валидация формы</a>.</li> +</ul> + +<p>Последнее, но не менее важное, обратите внимание на разницу синтаксиса у HTML-элементов <code><input></code> и <code><textarea></textarea></code>. Это одна из странностей HTML. Тег <code><input></code> — это пустой элемент, то есть он не нуждается в закрывающем теге. {{HTMLElement("textarea")}} — это непустой элемент, что говорит о том, что ему необходим закрывающий тег. Это важно при использовании одного из свойств форм: определения значения по умолчанию. Для определения начального значения для HTML-элемента {{HTMLElement("input")}} вам необходимо использовать атрибут <code>value</code> следующим образом:</p> + +<pre class="brush:html; notranslate"><input type="text" value="по умолчанию в этом элементе находится этот текст" /></pre> + +<p>Если вы хотите определить значение по умолчанию для HTML-элемента {{HTMLElement("textarea")}}, вам просто нужно поместить это начальное значение между открывающим и закрывающим тегами:</p> + +<pre class="brush:html; notranslate"><textarea> +по умолчанию в этом элементе находится этот текст +</textarea></pre> + +<h3 id="Элемент_HTMLelementbutton">Элемент {{HTMLelement("button")}}</h3> + +<p>Разметка нашей формы почти готова, но нам ещё необходимо добавить кнопку, которая позволит пользователю отправлять или "представлять" информацию после заполнения формы. Это делается с помощью HTML-элемента {{HTMLelement("button")}}. Необходимо добавить следующий код перед закрывающим тегом <code></form></code>:</p> + +<pre class="brush:html; notranslate"><li class="button"> + <button type="submit">Send your message</button> +</li></pre> + +<p>HTML-элемент {{HTMLelement("button")}} также принимает атрибут <code>type</code>, который может быть равен одному из трёх значений: <code>submit</code>, <code>reset</code> или <code>button</code>.</p> + +<ul> + <li>Клик по кнопке <code>submit</code> (значение по умолчанию) отправляет данные из формы на страницу, определённую в атрибуте <code>action</code> элемента {{HTMLelement("form")}}.</li> + <li>Клик по кнопке <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">reset</span></font> сбрасывает значения всех элементов управления формы к их начальному значению. С точки зрения UX, это считается плохой практикой.</li> + <li>Клик по кнопке <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">button</span></font> не делает ничего! Звучит странно, но на самом деле это очень удобно использовать для создания собственных кнопок — вы можете определить их поведение через JavaScript.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Вы также можете использовать HTML-элемент {{HTMLElement("input")}} с соответствующим атрибутом <code>type</code> , чтобы создать кнопку: <code><input type="submit"></code>. Главным преимуществом HTML-элемента {{HTMLelement("button")}} в сравнении с элементом {{HTMLelement("input")}} заключается в том, что {{HTMLelement("input")}} может принимать в себя только простой текст, в то время как {{HTMLelement("button")}} позволяет использовать весь HTML для создания более стилизованного текста внутри кнопки.</p> +</div> + +<h2 id="Базовая_стилизация_формы">Базовая стилизация формы</h2> + +<p>Теперь после того, как вы закончили писать HTML-код формы, сохраните его и откройте в браузере. Вы увидите, что на данный момент форма выглядит достаточно не красиво.</p> + +<p><img alt="" src="/files/4049/form-no-style.png" style="display: block; height: 170px; margin: 0px auto; width: 534px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Если вам кажется, что ваш HTML-код работает не правильно, попробуйте сравнить его с нашим примером — посмотрите <a href="https://github.com/mdn/learning-area/blob/master/html/forms/your-first-HTML-form/first-form.html">first-form.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/your-first-HTML-form/first-form.html">также можно посмотреть код вживую</a>).</p> +</div> + +<p>Красиво стилизовать формы достаточно сложно. Эта тема выходит за рамки этой статьи, поэтому на данный момент мы просто добавим некоторый CSS-код для приведения формы в нормальный вид.</p> + +<p>Сначала необходимо добавить HTML-элемент {{htmlelement("style")}} на вашу страницу внутрь тега <code>head</code> в HTML. Это должно выглядить следущим образом:</p> + +<pre class="brush: html notranslate"><style> + +</style></pre> + +<p>Внутри тега стилей добавьте следующий код:</p> + +<pre class="brush:css; notranslate">form { + /* Расположим форму по центру страницы */ + margin: 0 auto; + width: 400px; + /* Определим контур формы */ + padding: 1em; + border: 1px solid #CCC; + border-radius: 1em; +} + +ul { + list-style: none; + padding: 0; + margin: 0; +} + +form li + li { + margin-top: 1em; +} + +label { + /* Определим размер и выравнивание */ + display: inline-block; + width: 90px; + text-align: right; +} + +input, +textarea { + /* Убедимся, что все поля имеют одинаковые настройки шрифта + По умолчанию в textarea используется моноширинный шрифт */ + font: 1em sans-serif; + + /* Определим размер полей */ + width: 300px; + box-sizing: border-box; + + /* Стилизуем границы полей */ + border: 1px solid #999; +} + +input:focus, +textarea:focus { + /* Дополнительная подсветка для элементов в фокусе */ + border-color: #000; +} + +textarea { + /* Выровним многострочные текстовые поля с их текстами-подсказками */ + vertical-align: top; + + /* Предоставим пространство для ввода текста */ + height: 5em; +} + +.button { + /* Выровним кнопки с их текстами-подсказками */ + padding-left: 90px; /* same size as the label elements */ +} + +button { + /* Этот дополнительный внешний отступ примерно равен расстоянию + между текстами-подсказками и текстовыми полями */ + margin-left: .5em; +}</pre> + +<p>Теперь наша форма выглядит намного лучше.</p> + +<p><img alt="" src="/files/4051/form-style.png" style="height: 260px; width: 900px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти код на GitHub в <a href="https://github.com/mdn/learning-area/blob/master/html/forms/your-first-HTML-form/first-form-styled.html">first-form-styled.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/your-first-HTML-form/first-form-styled.html">также можно посмотреть код вживую</a>).</p> +</div> + +<h2 id="Отправка_данных_на_сервер">Отправка данных на сервер</h2> + +<p>Последняя и, наверно, самое сложное — это обработка данных формы на стороне сервера. HTML-элемент {{HTMLelement("form")}} определяет куда и каким способом отправить данные благодаря атрибутам <code>action</code> и <code>method</code>.</p> + +<p>Мы определяем имя <code>name</code> для каждого виджета формы. Указание имён важно как для браузера, так и для сервера: браузер узнаёт, какие имена дать каждой части данных, а сервер может получить эти данные, обратясь к ним по заданному имени. Данные форму отправляются на сервер в виде пары имя/значение.</p> + +<p>Чтобы проименовать данные, вам необходимо использовать атрибут <code>name</code> на каждом виджете формы, который будет собирать определённую часть информации. Давайте взглянем на код нашей формы ещё раз:</p> + +<pre class="brush:html; notranslate"><form action="/my-handling-form-page" method="post"> + <div> + <label for="name">Name:</label> + <input type="text" id="name" name="user_name" /> + </div> + <div> + <label for="mail">E-mail:</label> + <input type="email" id="mail" name="user_email" /> + </div> + <div> + <label for="msg">Message:</label> + <textarea id="msg" name="user_message"></textarea> + </div> + + ... +</pre> + +<p>В нашем примере форма отправит три куска данных с именами "<code>user_name</code>", "<code>user_email</code>" и "<code>user_message</code>". Эти данные будут отправлены на URL "<code>/my-handling-form-page</code>" через метод <a href="/ru/docs/Web/HTTP/Methods/POST">HTTP <code>POST</code></a>.</p> + +<p>На стороне сервера скрипт, расположенный на URL "<code>/my-handling-form-page</code>" получит данные в виде списка из 3 элементов вида ключ/значение, содержащихся в HTTP-запросе. То, как скрипт будет обрабатывать данные, зависит от вас. Каждый язык серверного программирования (PHP, Python, Ruby, Java, C# и т.д.) имеет свой механизм обработки данных из формы. Эта тема выходит за рамки данной статьи, если вы хотите углубиться в неё, мы привели несколько примеров далее в статье <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/HTML/Forms/Отправка_и_Получение_данных_формы" title="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data">Отправка данных формы</a>.</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Поздравляем! Вы создали свою первую HTML-форму. Вживую это выглядит так: </p> + +<p>{{ EmbedLiveSample('A_simple_form', '100%', '240', '', 'Learn/HTML/Forms/Your_first_HTML_form/Example') }}</p> + +<p>Однако это только начало — пришло время взглянуть глубже. HTML-формы намного мощнее, чем то, что мы видели здесь, и другие статьи этого раздела помогут освоить остальное.</p> + +<p>{{NextMenu("Learn/HTML/Forms/How_to_structure_an_HTML_form", "Learn/HTML/Forms")}}</p> + +<h2 id="В_этом_разделе">В этом разделе</h2> + +<ul> + <li><a href="/ru/docs/Learn/HTML/Forms/Ваша_первая_HTML_форма">Ваша первая HTML форма</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">Как структурировать HTML-формы</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/Стандартные_виджеты_форм">Стандартные виджеты форм</a></li> + <li><a href="/en-US/docs/Learn/Forms/HTML5_input_types">The HTML5 input types</a></li> + <li><a href="/en-US/docs/Learn/Forms/Other_form_controls">Other form controls</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/Styling_HTML_forms">Стили HTML-форм</a></li> + <li><a href="/en-US/docs/Learn/Forms/Advanced_form_styling">Advanced form styling</a></li> + <li><a href="/en-US/docs/Learn/Forms/UI_pseudo-classes">UI pseudo-classes</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/Валидация_формы">Проверка данных формы</a></li> + <li><a href="/ru/docs/Learn/HTML/Forms/Отправка_и_Получение_данных_формы">Отправка данных формы</a></li> +</ul> + +<h3 id="Дополнительные_темы">Дополнительные темы</h3> + +<ul> + <li><a href="/ru/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">Как создавать пользовательские виджеты форм</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li> +</ul> diff --git a/files/ru/learn/html/forms/отправка_и_получение_данных_формы/index.html b/files/ru/learn/html/forms/отправка_и_получение_данных_формы/index.html new file mode 100644 index 0000000000..9e7900f783 --- /dev/null +++ b/files/ru/learn/html/forms/отправка_и_получение_данных_формы/index.html @@ -0,0 +1,352 @@ +--- +title: Отправка данных формы +slug: Learn/HTML/Forms/Отправка_и_Получение_данных_формы +translation_of: Learn/Forms/Sending_and_retrieving_form_data +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/The_native_form_widgets", "Learn/HTML/Forms/Form_validation", "Learn/HTML/Forms")}}</div> + +<p class="summary">В этой статье рассматривается, что происходит, когда пользователь отправляет форму - куда передаются данные и как мы их обрабатываем, когда они туда попадают? Мы также рассмотрим некоторые проблемы безопасности, связанные с отправкой данных формы.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные знания:</th> + <td>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML">понимание HTML</a> и базовые знания по <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP">HTTP</a> и <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps">программированию на стороне сервера</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Понять, что происходит при отправке данных формы, в том числе получить представление о том, как данные обрабатываются на стороне сервера.</td> + </tr> + </tbody> +</table> + +<h2 id="Куда_отправляются_данные">Куда отправляются данные?</h2> + +<p>Здесь мы обсудим, что происходит с данными при отправке формы.</p> + +<h3 id="О_клиенсткойсерверной_архитектуре">О клиенсткой/серверной архитектуре</h3> + +<p>WEB основан на очень простой клиент-серверной архитектуре, которую можно обобщить следующим образом: клиент (обычно веб-браузер) отправляет запрос на сервер (в основном веб-сервер, такой как <a href="https://httpd.apache.org/" rel="external">Apache</a>, <a href="https://www.nginx.com/" rel="external">Nginx</a>, <a href="https://www.iis.net/" rel="external">IIS</a>, <a href="https://tomcat.apache.org/" rel="external">Tomcat</a>, и т. д.), используя протокол HTTP. Сервер отвечает на запрос, используя тот же протокол.<img alt="A basic schema of the Web client/server architecture" src="/files/4291/client-server.png" style="display: block; height: 141px; margin: 0px auto; width: 400px;"></p> + +<p>На стороне клиента HTML-форма - это не более чем удобный способ настройки HTTP-запроса для отправки данных на сервер. Это позволяет пользователю предоставлять информацию для доставки в HTTP-запросе .</p> + +<div class="note"> +<p><strong>Заметка</strong>: Для получения более полного представления о том, как работают клиент-серверные архитектуры, ознакомьтесь с модулем <a href="/en-US/docs/Learn/Server-side/First_steps">«Первые шаги в программировании на стороне сервера»</a>.</p> +</div> + +<h3 id="На_стороне_клиента_определение_способа_отправки_данных">На стороне клиента: определение способа отправки данных</h3> + +<p>Элемент {{HTMLElement("form")}} определяет способ отправки данных. Все его атрибуты предназначены для того, чтобы вы могли настроить запрос на отправку, когда пользователь нажимает кнопку отправки. Двумя наиболее важными атрибутами являются {{htmlattrxref("action","form")}} и {{htmlattrxref("method","form")}}.</p> + +<h4 id="Атрибут_htmlattrxrefactionform">Атрибут {{htmlattrxref("action","form")}}</h4> + +<p>Этот атрибут определяет, куда отправляются данные. Его значение должно быть действительным URL. Если этот атрибут не указан, данные будут отправлены на URL-адрес страницы, содержащей форму.</p> + +<p>В этом примере данные отправляются на абсолютный URL — <code>http://foo.com</code>:</p> + +<pre class="brush: html notranslate"><form action="http://foo.com"></pre> + +<p>Здесь мы используем относительный URL - данные отправляются на другой URL на сервере:</p> + +<pre class="brush: html notranslate"><form action="/somewhere_else"></pre> + +<p>Если атрибуты не указаны, как показано ниже, данные из формы {{HTMLElement("form")}} отправляются на ту же страницу, на которой размещается данная форма:</p> + +<pre class="brush: html notranslate"><form></pre> + +<p>Многие старые страницы используют следующий синтаксис, чтобы указать, что данные должны быть отправлены на ту же страницу, которая содержит форму; это было необходимо, потому что до появления HTML5 атрибут {{htmlattrxref("action", "form")}} был обязательным. Это больше не нужно.</p> + +<pre class="brush: html notranslate"><form action="#"></pre> + +<div class="note"> +<p><strong>Заметка:</strong> Можно указать URL, который использует протокол HTTPS (безопасный HTTP). Когда вы делаете это, данные шифруются вместе с остальной частью запроса, даже если сама форма размещается на небезопасной странице, доступ к которой осуществляется через HTTP. С другой стороны, если форма размещается на защищенной странице, но вы указываете небезопасный URL-адрес HTTP с атрибутом {{htmlattrxref("action","form")}}, все браузеры выдают пользователю предупреждение о безопасности при каждой попытке отправки данных, поскольку данные не шифруются.</p> +</div> + +<h4 id="Атрибут_htmlattrxrefmethodform">Атрибут {{htmlattrxref("method","form")}}</h4> + +<p>Этот атрибут определяет способ отправки данных. <a href="/en-US/docs/HTTP">Протокол HTTP</a> предоставляет несколько способов выполнить запрос; Данные HTML-формы могут передаваться несколькими различными способами, наиболее распространенными из которых являются метод <code>GET</code> и метод <code>POST</code>.</p> + +<p>Чтобы понять разницу между этими двумя методами, давайте вернёмся назад и рассмотрим, как работает HTTP. Каждый раз, когда вы хотите получить доступ к ресурсу в Интернете, браузер отправляет запрос на URL-адрес. HTTP-запрос состоит из двух частей: заголовка, который содержит набор глобальных метаданных о возможностях браузера, и тела, которое может содержать информацию, необходимую серверу для обработки конкретного запроса.</p> + +<h3 id="Метод_GET">Метод GET</h3> + +<p>Метод <code>GET</code> - это метод, используемый браузером, который говорит серверу, что нужно отправить назад данный ресурс: «Эй, сервер, я хочу получить этот ресурс». В этом случае браузер отправляет пустое тело. Поскольку тело пустое, если форма отправляется с использованием данного метода, данные, отправляемые на сервер, добавляются к URL-адресу.</p> + +<p>Рассмотрим следующую форму:</p> + +<pre class="brush: html notranslate"><form action="http://foo.com" method="get"> + <div> + <label for="say">What greeting do you want to say?</label> + <input name="say" id="say" value="Hi"> + </div> + <div> + <label for="to">Who do you want to say it to?</label> + <input name="to" id="to" value="Mom"> + </div> + <div> + <button>Send my greetings</button> + </div> +</form></pre> + +<p>Поскольку используется метод <code>GET</code>, вы увидите URL <code>www.foo.com/?say=Hi&to=Mom</code>, который появится в адресной строке браузера при отправке формы.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14685/url-parameters.png" style="display: block; margin: 0 auto;">Данные добавляются в URL как последовательность пар имя / значение. После того, как URL веб-адрес закончился, мы добавляем знак вопроса (<code>?</code>), за которым следуют пары имя / значение, каждая из которых разделена амперсандом (<code>&</code>). В этом случае мы передаем две части данных на сервер:</p> + +<ul> + <li><code>say</code>, со значением <code>Hi</code></li> + <li><code>to</code>, со значением <code>Mom</code></li> +</ul> + +<p>HTTP-запрос имеет следующий вид:</p> + +<pre class="notranslate">GET /?say=Hi&to=Mom HTTP/2.0 +Host: foo.com</pre> + +<div class="note"> +<p><strong>Заметка</strong>: Вы можете найти этот пример на GitHub — смотрите <a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/get-method.html">get-method.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/sending-form-data/get-method.html">see it live also</a>).</p> +</div> + +<h3 id="Метод_POST">Метод POST</h3> + +<p>Метод <code>POST</code> немного отличается. Браузер использует этот метод для связи с сервером при запросе ответа с учётом данных, представленные в теле HTTP-запроса: «Эй, сервер, взгляни на эти данные и отправь мне соответствующий результат». Если форма отправляется с использованием этого метода, данные добавляются в тело HTTP-запроса.</p> + +<p>Давайте рассмотрим пример — это та же самая форма, которую мы рассматривали в разделе <code>GET</code> выше, но с атрибутом {{htmlattrxref("method","form")}}, установленным в <code>post</code>.</p> + +<pre class="brush: html notranslate"><form action="http://foo.com" method="post"> + <div> + <label for="say">What greeting do you want to say?</label> + <input name="say" id="say" value="Hi"> + </div> + <div> + <label for="to">Who do you want to say it to?</label> + <input name="to" id="to" value="Mom"> + </div> + <div> + <button>Send my greetings</button> + </div> +</form></pre> + +<p>Когда форма отправляется с использованием метода <code>POST</code>, данные добавляются не к URL-адресу, а включаются в тело запроса. HTTP-запрос имеет следующий вид:</p> + +<pre class="notranslate">POST / HTTP/2.0 +Host: foo.com +Content-Type: application/x-www-form-urlencoded +Content-Length: 13 + +say=Hi&to=Mom</pre> + +<p>Заголовок <code>Content-Length</code> указывает размер тела, а заголовок <code>Content-Type</code> указывает тип данных, отправляемых на сервер. Мы обсудим эти заголовки позже.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Вы можете найти этот пример на GitHub — смотрите <a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/post-method.html">post-method.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/sending-form-data/post-method.html">see it live also</a>).</p> +</div> + +<h4 id="Просмотр_HTTP-запросов">Просмотр HTTP-запросов</h4> + +<p>HTTP-запросы никогда не отображаются пользователю (если вы хотите их видеть, Вам нужно использовать такие инструменты, как <a href="/en-US/docs/Tools/Network_Monitor">Firefox Network Monitor</a> или <a href="https://developers.google.com/chrome-developer-tools/">Chrome Developer Tools</a>). Например, данные формы можно увидеть на вкладке Сеть (Network) в Chrome следующим образом (после отправки формы):</p> + +<ol> + <li>Нажмите F12</li> + <li>Выберите Network</li> + <li>Выберите "All"</li> + <li>Выберите "foo.com" во вкладке "Name"</li> + <li>Выберите "Headers"</li> +</ol> + +<p>Затем вы можете получить данные формы, как показано на рисунке ниже.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14691/network-monitor.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>Единственное, что отображается пользователю — вызываемый URL. Как упоминалось раннее, запрос с методом <code>GET</code> позволит пользователю увидеть информацию из запроса в URL, а запрос с методом <code>POST</code> не позволит. Две причины, почему это может быть важно:</p> + +<ol> + <li>Если необходимо отправить пароль (или любую другую важную информацию), никогда не используйте метод <code>GET</code>, иначе рискуете отобразить эту информацию в URL-строке, что небезопасно.</li> + <li>Если необходимо отправить большой объем информации, <code>POST</code>-метод является предпочтительным, так как некоторые браузеры ограничивают длину URL. К тому же, многие сервера так же ограничивают длину обрабатываемых URL.</li> +</ol> + +<h3 id="На_стороне_сервера_получение_данных">На стороне сервера: получение данных</h3> + +<p>Какой бы HTTP вы не выбрали, сервер возвращает строку, которая будет последовательно проанализирована для получения данных в формате листа с парами ключ/значение. Способ получения доступа к этому листу зависит от платформы разработки или особенностей фреймворка, который вы можете использовать. Технологии, которые вы используете, определяют, как обрабатываются скопированные ключи. Часто, приоритетным является последнее полученное значение для данного ключа.</p> + +<h4 id="Пример_Чистый_PHP">Пример: Чистый PHP</h4> + +<p><a href="https://php.net/">PHP</a> предлагает несколько глобальных объектов для доступа к данным. Например, вы используете <code>POST</code>-метод, в приведенном ниже примере данные просто получаются и показываются пользователю. Разумеется, как использовать данные — решать только вам. Вы можете отобразить эти данные, поместить в базу данных, отправить по почте или передать эти данные куда-либо еще.</p> + +<pre class="brush: php notranslate"><?php + // The global $_POST variable allows you to access the data sent with the POST method by name + // To access the data sent with the GET method, you can use $_GET + $say = htmlspecialchars($_POST['say']); + $to = htmlspecialchars($_POST['to']); + + echo $say, ' ', $to; +?></pre> + +<p>Пример показывает страницу с данными, которые мы отправили. Вы можете посмотреть это в действии в нашем файле с примером: <a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/php-example.html">php-example.html</a> — который содержит те же данные, которые вы видели раньше: <code>method</code> : <code>post</code> и <code>action</code> из <code>php-example.php</code>. Когда данные переданы на отправку (submit), они переданы в форму <a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/php-example.php">php-example.php</a>, которая содержит PHP код из примера выше. Когда код будет выполнен, браузер выведет (output) обработанное сообщение: <code>Hi Mom</code>.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14693/php-result.png" style="display: block; margin: 0 auto;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Этот пример не будет работать, когда вы загружаете его в браузер локально — браузер не может интерпретировать PHP код, после отправки данных из формы, браузер просто предложит загрузить PHP файл. Чтобы пример заработал, необходимо отправить его на PHP сервер. Для тестирования PHP на локальных серверах можете пробовать <a href="https://www.mamp.info/en/downloads/">MAMP</a> (Mac and Windows) и/или <a href="http://ampps.com/download">AMPPS</a> (Mac, Windows, Linux).</p> +</div> + +<h4 id="Пример_Python">Пример: Python</h4> + +<p>Этот пример показывает, как вы можете использовать Python для решения той же задачи — отобразить отправленные данные на странице. В этом примере используется <a href="http://flask.pocoo.org/">Flask framework</a> для визуализации шаблонов, поддерживающих форму отправки данных (смотри <a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/python-example.py">python-example.py</a>).</p> + +<pre class="brush: python notranslate">from flask import Flask, render_template, request + +app = Flask(__name__) + +@app.route('/', methods=['GET', 'POST']) +def form(): + return render_template('form.html') + +@app.route('/hello', methods=['GET', 'POST']) +def hello(): + return render_template('greeting.html', say=request.form['say'], to=request.form['to']) + +if __name__ == "__main__": + app.run()</pre> + +<p>Два шаблона из коде выше взаимодействуют так:</p> + +<ul> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/templates/form.html">form.html</a>: Та же форма, что и выше {{anch("The POST method")}} , только с использованием <code>action</code> к <code>\{{ url_for('hello') }}</code>. (Это <a href="http://jinja.pocoo.org/docs/2.9/">Jinja2</a> шаблон, который изначально HTMLно может содержать вызовы Python кода в фигурных скобках, которые запустятся веб-сервером. <code>url_for('hello')</code> буквально говорит: после отправки данных переадресуй их в <code>/hello</code>.)</li> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/templates/greeting.html">greeting.html</a>: Этот шаблон просто содержит строку, которая отображает два бита данных, переданных ему при отображении. Это сделано с помощью функции <code>hello()</code>, указанной выше, которая выполняется, когда запрос направляется в <code>/hello</code> URL.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Опять же, этот код не будет работать, если вы просто попробуете загрузить его прямо в браузер. Python работает немного иначе, чем PHP — чтобы запустить этот код, нужно <a href="/en-US/docs/Learn/Server-side/Django/development_environment#Installing_Python_3">установить Python/PIP</a>, потом установить Flask используя команду: <code>pip3 install flask</code>. После этого, вы сможете запустить файл из примера, используя команду: <code>python3 python-example.py</code>, потом открыть <code>localhost:5000</code> в своем браузере.</p> +</div> + +<h4 id="Другие_языки_и_фреймворки">Другие языки и фреймворки</h4> + +<p>Существует множество других серверных технологий, которые вы можете использовать для работы с формами, включая языки Perl, Java, .Net, Ruby, и прочее. Выбирайте тот, который нравится больше. К тому же, использовать вышеупомянутые технологии непосредственно, без использования фреймворков, может быть сложно. Лучше использовать один из множества высококачественных фреймворков, таких как:</p> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django" rel="external">Django</a> для Python (немного тяжеловеснее, чем <a href="http://flask.pocoo.org/">Flask</a>, но больше инструментов и опций)</li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs">Express</a> для Node.js</li> + <li><a href="https://laravel.com/">Laravel</a> для PHP</li> + <li><a href="https://rubyonrails.org/" rel="external">Ruby On Rails</a> для Ruby</li> + <li><a href="https://phoenixframework.org/">Phoenix</a> для Elixir</li> +</ul> + +<p>Стоит отметить, что использование фреймворков и работа с формами - это не всегда легко. Но это намного легче, чем пытаться написать аналогичный функционал с нуля, и это определенно сэкономит время. </p> + +<div class="note"> +<p><strong>Примечание</strong>: Обучению фреймворкам и работе с серверами не входит в рамки этой статьи. Если хотите узнать больше, ссылки ниже помогут в этом. </p> +</div> + +<h2 id="Особый_случай_отправка_файлов">Особый случай: отправка файлов</h2> + +<p>Отправка файлов с помощью форм HTML — это особый случай. Файлы — это бинарные данные или рассматриваются как таковые, в то время как все остальные — это текстовые данные. Поскольку HTTP — это текстовый протокол, есть особые требования для работы с бинарными данными.</p> + +<h3 id="Атрибут_htmlattrxrefenctypeform">Атрибут {{htmlattrxref("enctype","form")}} </h3> + +<p>Этот атрибут позволяет конкретизировать значение в <code>Content-Type</code> HTTP заголовок, включенный в запрос, при генерировании отпавки формы. Этот заголовок очень важен, потому что указывает серверу, какой тип данных отправляется. По умолчанию это: <code>application/x-www-form-urlencoded</code>. На человеческом это значит: "Это форма с данными, которые были закодированы в URL параметры."</p> + +<p>Если хотите отправить файл, нужно сделать следующие три шага:</p> + +<ul> + <li>Указать {{htmlattrxref("method","form")}} атрибут <code>POST</code>, поскольку содержимое файла, как и сам файл, не могут быть отображены в URL параметрах.</li> + <li>Установить в {{htmlattrxref("enctype","form")}} значение <code>multipart/form-data</code>, потому что данные будут разбиты на несколько частей: одна часть на файл (две части на два файла), и одна часть на текстовые данные (при условии, если форма содержит поле для получения тестовых данных).</li> + <li>Подключите один или более <a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets#File_picker">File picker</a> виджетов, чтобы позволить своим пользователям выбрать, какие и сколько файлов будут загружены.</li> +</ul> + +<p>Пример:</p> + +<pre class="brush: html notranslate"><form method="post" enctype="multipart/form-data"> + <div> + <label for="file">Choose a file</label> + <input type="file" id="file" name="myFile"> + </div> + <div> + <button>Send the file</button> + </div> +</form></pre> + +<div class="note"> +<p><strong>Примечание:</strong> Некоторые браузеры поддерживают {{htmlattrxref("multiple","input")}} атрибут элемента {{HTMLElement("input")}} , который позволяет выбрать больше одного файла для загрузки, при использовании одного элемента <code><input></code> . То, как сервер работает с этими файлами, напрямую зависит от технологий, используемых на сервере. Как упоминалось ранее, использование фреймворков сделает вашу жизнь намного легче. </p> +</div> + +<div class="warning"> +<p><strong>Предупреждение:</strong> Многие сервера имеют заданные ограничения на размер загружаемых файлов и запросы от пользователей, чтобы защититься от возможных злоупотреблений. Важно проверять эти ограничения у администратора сервера, прежде чем загружать файлы.</p> +</div> + +<h2 id="Проблемы_безопасности">Проблемы безопасности</h2> + +<p>Каждый раз, когда вы отправляете данные на сервер, вы должны учитывать безопасность. HTML-формы являются наиболее распространенными векторами атак на серверы(места, где могут происходить атаки). Проблемы вытекают не из самих форм HTML, а из-за того, как сервер обрабатывает данные из этих форм.</p> + +<p>В зависимости от того, что вы делаете, вы можете столкнуться с некоторыми очень известными проблемами безопасности:</p> + +<h3 id="XSS_Межсайтовый_скриптинг_и_CSRF_Подделка_межсайтовых_запросов">XSS "Межсайтовый скриптинг" и CSRF "Подделка межсайтовых запросов"</h3> + +<p><a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B8%D0%BD%D0%B3">Межсайтовый скриптинг (XSS "Сross Site Request Forgery")</a> и <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D0%BB%D0%BA%D0%B0_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">подделка межсайтовых запросов (CSRF "Cross-Site Scripting")</a> - это распространенные типы атак, которые происходят при отображении данных после ответа сервера или другого пользователя.</p> + +<p><a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B8%D0%BD%D0%B3">Межсайтовый скриптинг (XSS "Сross Site Request Forgery")</a> позволяет злоумышленникам внедрить клиентский скрипт в веб-страницы, просматриваемые другими пользователями. <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D0%BB%D0%BA%D0%B0_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">Подделка межсайтовых запросов (CSRF "Cross-Site Scripting")</a> может использоваться злоумышленниками для обхода средств контроля доступа, таких как одна и та же <a href="/ru/docs/Web/Security/Same-origin_policy">политика происхождения</a>. Последствие от этих атак может варьироваться от мелких неудобств до значительного риска безопасности.</p> + +<p><a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D0%BB%D0%BA%D0%B0_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">CSRF-атаки</a> аналогичны <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B8%D0%BD%D0%B3">XSS-атакам</a> в том, что они начинаются одинаково - с внедрения клиентского скрипта в веб-страницы - но их конечные цели разные. Злоумышленники <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D0%BB%D0%BA%D0%B0_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">CSRF </a>пытаются назначить права пользователям с более высоким уровнем прав доступа(например, администратору сайта), чтобы выполнить действие, которое они не должны выполнять (например, отправка данных ненадежному пользователю). Атаки <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B8%D0%BD%D0%B3">XSS </a>используют доверие пользователя к веб-сайту, в то время как атаки <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D0%BB%D0%BA%D0%B0_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">CSRF </a>используют доверие веб-сайта к пользователю.</p> + +<p>Чтобы предотвратить эти атаки, вы всегда должны проверять данные, которые пользователь отправляет на ваш сервер, и (если вам нужно отобразить их) стараться не отображать HTML-контент, предоставленный пользователем. Вместо этого вы должны обработать предоставленные пользователем данные, чтобы не отображать их слово в слово. Сегодня почти все платформы на рынке реализуют минимальный "фильтр", который удаляет элементы HTML {{HTMLElement ("script")}}, {{HTMLElement ("iframe")}} и {{HTMLElement ("object")}} полученных от любого пользователя. Это помогает снизить риск, но не исключает его полностью.</p> + +<h3 id="SQL_-_вброс">SQL - вброс</h3> + +<p>SQL -вброс представляет собой тип атак, при которых осуществляется попытка выполнения действия с базой данных, используемой целевым веб-сайтом. В этих случаях обычно осуществляется отправка SQL-запроса в надежде, что сервер выполнит этот запрос (обычно при попытке сервера приложения сохранить данные, отправляемые пользователем). Данный вид атак является <a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project" rel="external">одним из самых направленных атак на веб-сайты</a>.</p> + +<p>Последствия могут быть ужасающими, начиная от потери данных и заканчивая утратой контроля над всей инфраструктурой веб-сайта за счет повышения привилегий. Это очень серьезная угроза, поэтому никогда не сохраняйте данные, отправляемые пользователем, без выполнения санитизации данных (например, с помощью <code><a href="http://us1.php.net/manual/en/mysqli.real-escape-string.php">mysqli_real_escape_string()</a></code>.</p> + +<h3 id="Вброс_HTTP-заголовка_и_email">Вброс HTTP-заголовка и email</h3> + +<p>Эти виды атак могут проявляться, когда ваше приложение создает заголовки HTTP или электронные почтовые адреса на основании данных, введенных пользователем в форму. Такие атаки напрямую не повреждают сервер или пользовалей, однако создают уязвимость для таких угроз, как перехват сессии, или для фишинговых атак.</p> + +<p>Такие атаки являются самыми незаметными, но при этом могут превратить ваш сервер в <a href="http://en.wikipedia.org/wiki/Zombie_(computer_science)" rel="exernal">зомби</a>.</p> + +<h3 id="Будьте_параноиком_никогда_не_доверяйте_вашим_пользователям">Будьте параноиком: никогда не доверяйте вашим пользователям</h3> + +<p>Как вы боретесь с такими угрозами? Этот вопрос выходит далеко за рамки данной статьи, но есть несколько общих правил, которые следует всегда соблюдать. Самое важное из них - никогда не доверяйте вашим пользователям, в том числе себе; даже проверенный пользователь может быть атакован.</p> + +<p>Все данные, поступающие на ваш сервер, необходимо проверять и санитизировать. Все и всегда. Без исключений.</p> + +<ul> + <li>Избегайте потенциально опасных символов. Конкретные символы, с которыми следует соблюдать осторожность, зависят от контекста, в котором используются данные, а также от используемой платформы. Однако, все языки на стороне сервера имеют соответствующие функции для обеспечения такой защиты.</li> + <li>Ограничьте входящий объем данных для поступления только реально необходимых данных.</li> + <li>Помещайте загруженные файлы в песочницу (храните их на другом сервере и предоставляйте доступ к фалам только через отдельный поддомен или даже через совершенно другое доменное имя).</li> +</ul> + +<p>Соблюдая эти три правила, вы сможете избежать многих/большинства проблем. При этом следует помнить, что периодически необходимо проводить анализ защищенности, желательно квалифицированной сторонней организацией. Не считайте, что вы уже сталкивались со всеми возможными угрозами.</p> + +<div class="note"> +<p><strong>Примечание</strong>: В статье <a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Безопасность веб-сайта</a> нашего раздела <a href="/en-US/docs/Learn/Server-side">серверного</a> обучения приведено подробное обсуждение упомянутых угроз и возможных способов их устранения.</p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>Как мы увидели, отправлять формы просто, однако защитить приложение может быть довольно трудно. Просто помните, что фронтенд разработчики не должны задавать модель безопасности для приложения. Да, как мы увидим далее, <a href="/ru/docs/Learn/HTML/Forms/Валидация_формы">мы можем проверить данные на стороне клиента</a>, однако сервер не может доверять этой проверке, потому что он никогда не может по-настоящему узнать что происходит на стороне клиента.</p> + +<h2 id="См._также">См. также</h2> + +<p>Если вы хотите узнать больше об обеспечении безопасности веб-приложений, вы можете использовать следущие источники информации:</p> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/First_steps">Первые шаги в программирование веб-сайтов на стороне сервера</a></li> + <li><a href="https://www.owasp.org/index.php/Main_Page" rel="external">Открытый проект обеспечения веб-безопасности приложений (OWASP)</a></li> + <li><a href="https://infosec.mozilla.org/guidelines/web_security">Веб-безопасность от Mozilla</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/The_native_form_widgets", "Learn/HTML/Forms/Form_validation", "Learn/HTML/Forms")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Ваша первая HTML-форма</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">Как структурировать HTML-форму</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">Предопределенные виджеты</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Отправка данных формы</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Валидация данных формы</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">Как создавать кастомные виджеты</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Отправка форм с помощью JavaScript</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML-формы в старых версиях браузеров</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Стилизация HTML-форм</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Продвинутая стилизация для HTML-форм</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Таблица совместимости свойств виджетов форм</a></li> +</ul> diff --git a/files/ru/learn/html/forms/стандартные_виджеты_форм/index.html b/files/ru/learn/html/forms/стандартные_виджеты_форм/index.html new file mode 100644 index 0000000000..eae3fbb32d --- /dev/null +++ b/files/ru/learn/html/forms/стандартные_виджеты_форм/index.html @@ -0,0 +1,690 @@ +--- +title: Стандартные виджеты форм +slug: Learn/HTML/Forms/Стандартные_виджеты_форм +translation_of: Learn/Forms/Basic_native_form_controls +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Forms/How_to_structure_an_HTML_form", "Learn/HTML/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms")}}</div> + +<p class="summary">Сейчас мы детально изучим возможности различных виджетов форм, посмотрим, какие функции доступны для получения информации в различных представлениях. Это исчерпывающая статья, описывающая все доступные стандартные виджеты форм.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Базовая компьютерная грамотность, базовое <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">понимание HTML</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять, какие типы стандартных виджетов форм доступны в браузерах для сбора информации, как внедрять их, используя HTML.</td> + </tr> + </tbody> +</table> + +<p>Сейчас мы сосредоточимся на виджетах форм, встроенных в браузеры, но поскольку формы HTML остаюстся несколько ограниченными и особенности их реализации различаются для разных браузеров, веб-разработчики иногда создают собственные виджеты форм - прочтите статью <a href="https://developer.mozilla.org/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">Как создать собственную форму</a> позже в данном модуле для более подробного изучения.</p> + +<div class="note"> +<p><strong>Note</strong>: Большая часть признаков обсуждаемых в этой статье имеют широкую поддержку в браузерах; мы отметим исключения из этого правила. Если вы хотите больше точных сведений, вам следует обратиться к <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element#Forms">HTML forms element reference, </a>и в частости к нашей обширной ссылке <a href="/en-US/docs/Web/HTML/Element/input"><input> types.</a></p> +</div> + +<h2 id="Стандартные_атрибуты">Стандартные атрибуты</h2> + +<p>Многие элементы, используемые для определения виджетов форм, имеют собственные атрибуты. Однако, существует набор атрибутов, общих для всех элементов формы, которые предоставляют вам контроль над их виджетами. Вот список этих общих атрибутов:</p> + +<table> + <thead> + <tr> + <th scope="col">Attribute name</th> + <th scope="col">Default value</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>autofocus</code></td> + <td>(<em>false</em>)</td> + <td>Этот атрибут логического типа позволяет вам определить, должен ли элемент автоматически попадать в фокус при загрузке страницы, пока пользователь не изменит это, например, печатая в другом виджете. Этот атрибут может явно определяться только для одного элемента в документе, ассоциированного с формой.</td> + </tr> + <tr> + <td><code>disabled</code></td> + <td>(<em>false</em>)</td> + <td>Этот атрибут логического типа определяет, может ли пользователь взаимодействовать с элементом. Если этот атрибут не определён, то элемент наследует его значение от элемента-родителя. Если атрибут не определён, то по умолчанию пользователь может взаимодействовать с элементом.</td> + </tr> + <tr> + <td><code>form</code></td> + <td></td> + <td>Элемент формы, с которым ассоциирован виджет. Значением данного атрибута должен быть атрибут <code>id</code> элемента {{HTMLElement("form")}} в том же документе. Теоретически, это позволяет вам помещать определение виджета за рамками элемента {{HTMLElement("form")}}. На практике, однако, не существует браузеров, поддерживающих данную функцию.</td> + </tr> + <tr> + <td><code>name</code></td> + <td></td> + <td>Название элемента; передаётся вместе с данными формы.</td> + </tr> + <tr> + <td><code>value</code></td> + <td></td> + <td>Начальное значение элемента.</td> + </tr> + </tbody> +</table> + +<h2 id="Поля_ввода_текста">Поля ввода текста</h2> + +<p>Текстовые поля {{htmlelement("input")}} являются самыми базовыми виджетами форм. Эти поля наиболее удобны для пользовательского ввода различной информации. Однако, некоторые текстовые поля отличаются от данного и используются для специфических нужд. Мы уже видели нескольк простых примеров.</p> + +<div class="note"> +<p><strong>Note</strong>: HTML form text fields are simple plain text input controls. This means that you cannot use them to perform <a href="/en-US/docs/Rich-Text_Editing_in_Mozilla" title="/en-US/docs/Rich-Text_Editing_in_Mozilla">rich editing</a> (bold, italic, etc.). All rich text editors you'll encounter out there are custom widgets created with HTML, CSS, and JavaScript.</p> +</div> + +<p>Все текстовые поля имеют общие атрибуты:</p> + +<ul> + <li>Они могут быть помечены как {{htmlattrxref("readonly","input")}} (пользователь не может изменять начальное значение) или даже {{htmlattrxref("disabled","input")}} начальное значение никогда не посылается вместе с остальными данными формами).</li> + <li>Они могут иметь атрибут {{htmlattrxref("placeholder","input")}}; это текст, который появляется внутри теста поля формы и кратко описывает, для чего используется данная форма.</li> + <li>Существуют общие характеристики {{htmlattrxref("size","input")}} (физический размер поля) и <a href="/en-US/docs/HTML/Element/input#attr-maxlength" title="/en-US/docs/HTML/Element/input#attr-maxlength">длину</a> (максимальное количество символов, которые может ввести пользователь).</li> + <li>Они могут быть определены с помощью <a href="/en-US/docs/HTML/Element/input#attr-spellcheck" title="/en-US/docs/HTML/Element/input#attr-spellcheck">spell checking</a>, если браузер поддерживает данную функцию.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: The {{htmlelement("input")}} element is special because it can be almost anything. By simply setting its <code>type</code> attribute, it can change radically, and it is used for creating most types of form widget including single line text fields, controls without text input, time and date controls, and buttons. However, there are some exceptions, like {{htmlelement("textarea")}} for multi-line inputs. Take careful note of these as you read the article.</p> +</div> + +<h3 id="Однострочные_текстовые_поля">Однострочные текстовые поля</h3> + +<p>Однострочные текстовые поля создаются с использованием элемента {{HTMLElement("input")}} чей атрибут {{htmlattrxref("type","input")}} имеет значение <code>text</code> (если вы не поставите другое значение атрибута {{htmlattrxref("type","input")}}, <code>text</code> является значением по умолчанию). Значение <code>text</code> для этого атрибута является возвратным, если значение которое вы определили для {{htmlattrxref("type","input")}} неизвестно браузеру (например, если вы определили <code>type="date"</code> а браузер не поддерживает выбор даты).</p> + +<div class="note"> +<p><strong>Note</strong>: Вы можете найти примеры всех типов однострочных текстовых полей на GitHub at <a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/single-line-text-fields.html">single-line-text-fields.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/single-line-text-fields.html">see it live also</a>).</p> +</div> + +<p>Пример базового одностраничного текстового поля:</p> + +<pre class="brush: html notranslate"><input type="text" id="comment" name="comment" value="I'm a text field"></pre> + +<p>Однострочное текстовое поле имеет только одно настоящее ограничение: если вы вводите текст с разрывами строки, браузер удаляет эти разрывы строк перед отправкой данных.</p> + +<p><img alt="Screenshots of single line text fields on several platforms." src="/files/4273/all-single-line-text-field.png" style="height: 235px; width: 655px;"></p> + +<p>HTML5 enhances the basic single line text field by adding special values for the {{htmlattrxref("type","input")}} attribute. Those values still turn an {{HTMLElement("input")}} element into a single line text field but they add a few extra constraints and features to the field.</p> + +<h4 id="E-mail_address_field">E-mail address field</h4> + +<p>Этот тип поля устонавливается со значеним <code>email</code> для атрибута {{htmlattrxref("type","input")}}:</p> + +<pre class="brush: html notranslate"><input type="email" id="email" name="email" multiple></pre> + +<p>Когда используется этот <code>type</code>, пользователь должен ввести в поле валидный адрес электронной почты; любое другое содержание будет отображено браузером при отправке формы как ошибка. Заметьте, что это проверка ошибок на стороне клиента, выполняемая браузером:</p> + +<p><img alt="An invalid email input showing the message Please enter an email address." src="https://mdn.mozillademos.org/files/14781/email-invalid.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>It's also possible to let the user type several e-mail addresses into the same input (separated by commas) by including the {{htmlattrxref("multiple","input")}} attribute.</p> + +<p>On some devices (especially on mobile), a different virtual keypad might be presented that is more suitable for entering email addresses.</p> + +<div class="note"> +<p><strong>Note</strong>: You can find out more about form validation in the article <a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a>.</p> +</div> + +<h4 id="Password_field">Password field</h4> + +<p>This type of field is set using the value <code>password</code> for the {{htmlattrxref("type","input")}} attribute:</p> + +<pre class="brush: html notranslate"><input type="password" id="pwd" name="pwd"></pre> + +<p>It doesn't add any special constraints to the entered text, but it does obscure the value entered into the field (e.g. with dots or asterisks) so it can't be read by others.</p> + +<p>Keep in mind this is just a user interface feature; unless you submit your form securely, it will get sent in plain text, which is bad for security — a malicious party could intercept your data and steal passwords, credit card details, or whatever else you've submitted. The best way to protect users from this is to host any pages involving forms over a secure connection (i.e. at an https:// ... address), so the data is encrypted before it is sent.</p> + +<p>Modern browsers recognize the security implications of sending form data over an insecure connection, and have implemented warnings to deter users from using insecure forms. For more information on what Firefox implements, see <a href="/en-US/docs/Web/Security/Insecure_passwords">Insecure passwords</a>.</p> + +<h4 id="Search_field">Search field</h4> + +<p>This type of field is set by using the value <code>search</code> for the {{htmlattrxref("type","input")}} attribute:</p> + +<pre class="brush: html notranslate"><input type="search" id="search" name="search"></pre> + +<p>The main difference between a text field and a search field is how the browser styles it — often, search fields are rendered with rounded corners, and/or given an "x" to press to clear the entered value. However, there is another added feature worth noting: their values can be automatically saved to be auto completed across multiple pages on the same site.</p> + +<p><img alt="Screenshots of search fields on several platforms." src="/files/4269/all-search-field.png" style="height: 235px; width: 655px;"></p> + +<h4 id="Phone_number_field">Phone number field</h4> + +<p>This type of field is set using <code>tel</code> as the value of the {{htmlattrxref("type","input")}} attribute:</p> + +<pre class="brush: html notranslate"><input type="tel" id="tel" name="tel"></pre> + +<p>Due to the wide variety of phone number formats around the world, this type of field does not enforce any constraints on the value entered by a user (this can include letters, etc.). This is primarily a semantic difference, although on some devices (especially on mobile), a different virtual keypad might be presented that is more suitable for entering phone numbers.</p> + +<h4 id="URL_field">URL field</h4> + +<p>This type of field is set using the value <code>url</code> for the {{htmlattrxref("type","input")}} attribute:</p> + +<pre class="brush: html notranslate"><input type="url" id="url" name="url"></pre> + +<p>It adds special validation constraints to the field, with the browser reporting an error if invalid URLs are entered.</p> + +<div class="note"><strong>Note:</strong> Just because the URL is well-formed doesn't necessarily mean that it refers to a location that actually exists.</div> + +<div class="note"> +<p><strong>Note</strong>: Fields that have special constraints and are in error prevent the form from being sent; in addition, they can be styled so as to make the error clear. We will discuss this in detail in the article: <a href="/en-US/docs/HTML/Forms/Data_form_validation" title="/en-US/docs/HTML/Forms/Data_form_validation">Data form validation</a>.</p> +</div> + +<h3 id="Multi-line_text_fields">Multi-line text fields</h3> + +<p>A multi-line text field is specified using a {{HTMLElement("textarea")}} element, rather than using the {{HTMLElement("input")}} element.</p> + +<pre class="brush: html notranslate"><textarea cols="30" rows="10"></textarea></pre> + +<p>The main difference between a textarea and a regular single line text field is that users are allowed to type text that includes hard line breaks (i.e. pressing return).</p> + +<p><img alt="Screenshots of multi-lines text fields on several platforms." src="/files/4271/all-multi-lines-text-field.png" style="height: 330px; width: 745px;"></p> + +<div class="note"> +<p><strong>Note</strong>: You can find an example of a multi-line text field on GitHub at <a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/multi-line-text-field.html">multi-line-text-field.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/multi-line-text-field.html">see it live also</a>). Have a look at it, and notice how in most browsers, the text area is given a drag handle on the bottom right to allow the user to resize it. This resizing ability can be turned off by setting the text area's {{cssxref("resize")}} property to <code>none</code> using <a href="/en-US/docs/Learn/CSS">CSS</a>.</p> +</div> + +<p>{{htmlelement("textarea")}} also accepts a few extra attributes to control its rendering across several lines (in addition to several others):</p> + +<table> + <caption>Attributes for the {{HTMLElement("textarea")}} element</caption> + <thead> + <tr> + <th scope="col">Attribute name</th> + <th scope="col">Default value</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("cols","textarea")}}</td> + <td><code>20</code></td> + <td>The visible width of the text control, in average character widths.</td> + </tr> + <tr> + <td>{{htmlattrxref("rows","textarea")}}</td> + <td></td> + <td>The number of visible text lines for the control.</td> + </tr> + <tr> + <td>{{htmlattrxref("wrap","textarea")}}</td> + <td><code>soft</code></td> + <td>Indicates how the control wraps text. Possible values are: <code>hard</code> or <code>soft</code></td> + </tr> + </tbody> +</table> + +<p>Note that the {{HTMLElement("textarea")}} element is written a bit differently from the {{HTMLElement("input")}} element. The {{HTMLElement("input")}} element is an empty element, which means that it cannot contain any child elements. On the other hand, the {{HTMLElement("textarea")}} element is a regular element that can contain text content children.</p> + +<p>There are two key related points to note here:</p> + +<ul> + <li>If you want to define a default value for an {{HTMLElement("input")}} element, you have to use the <code>value</code> attribute; for a {{HTMLElement("textarea")}} element on the other hand you put the default text between the starting tag and the closing tag of the {{HTMLElement("textarea")}}.</li> + <li>Because of its nature, the {{HTMLElement("textarea")}} element only accepts text content; this means that any HTML content put inside a {{HTMLElement("textarea")}} is rendered as if it was plain text content.</li> +</ul> + +<h2 id="Drop-down_content">Drop-down content</h2> + +<p>Drop-down widgets are a simple way to let users select one of many options without taking up much space in the user interface. HTML has two forms of drop down content: the <strong>select box</strong>, and <strong>autocomplete box</strong>. In both cases the interaction is the same — once the control is activated, the browser displays a list of values the user can select between.</p> + +<div class="note"> +<p>Note: You can find examples of all the drop-down box types on GitHub at <a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/drop-down-content.html">drop-down-content.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/drop-down-content.html">see it live also</a>).</p> +</div> + +<h3 id="Select_box">Select box</h3> + +<p>A select box is created with a {{HTMLElement("select")}} element with one or more {{HTMLElement("option")}} elements as its children, each of which specifies one of its possible values.</p> + +<pre class="brush: html notranslate"><select id="simple" name="simple"> + <option>Banana</option> + <option>Cherry</option> + <option>Lemon</option> +</select></pre> + +<p>If required, the default value for the select box can be set using the {{htmlattrxref("selected","option")}} attribute on the desired {{HTMLElement("option")}} element — this option is then preselected when the page loads. The {{HTMLElement("option")}} elements can also be nested inside {{HTMLElement("optgroup")}} elements to create visually associated groups of values:</p> + +<pre class="brush: html notranslate"><select id="groups" name="groups"> + <optgroup label="fruits"> + <option>Banana</option> + <option selected>Cherry</option> + <option>Lemon</option> + </optgroup> + <optgroup label="vegetables"> + <option>Carrot</option> + <option>Eggplant</option> + <option>Potato</option> + </optgroup> +</select></pre> + +<p><img alt="Screenshots of single line select box on several platforms." src="/files/4517/all-select.png" style="height: 636px; width: 887px;"></p> + +<p>If an {{HTMLElement("option")}} element is set with a <code>value</code> attribute, that attribute's value is sent when the form is submitted. If the <code>value</code> attribute is omitted, the content of the {{HTMLElement("option")}} element is used as the select box's value.</p> + +<p>On the {{HTMLElement("optgroup")}} element, the <code>label</code> attribute is displayed before the values, but even if it looks somewhat like an option, it is not selectable.</p> + +<h3 id="Multiple_choice_select_box">Multiple choice select box</h3> + +<p>By default, a select box only lets the user select a single value. By adding the {{htmlattrxref("multiple","select")}} attribute to the {{HTMLElement("select")}} element, you can allow users to select several values, by using the default mechanism provided by the operating system (e.g. holding down <kbd>Cmd</kbd>/<kbd>Ctrl</kbd> and clicking multiple values).</p> + +<p>Note: In the case of multiple choice select boxes, the select box no longer displays the values as drop-down content — instead, they are all displayed at once in a list.</p> + +<pre class="brush: html notranslate"><select multiple id="multi" name="multi"> + <option>Banana</option> + <option>Cherry</option> + <option>Lemon</option> +</select></pre> + +<p><img alt="Screenshots of multi-lines select box on several platforms." src="/files/4559/all-multi-lines-select.png" style="height: 531px; width: 734px;"></p> + +<div class="note"><strong>Note:</strong> All browsers that support the {{HTMLElement("select")}} element also support the {{htmlattrxref("multiple","select")}} attribute on it.</div> + +<h3 id="Autocomplete_box">Autocomplete box</h3> + +<p>You can provide suggested, automatically-completed values for form widgets using the {{HTMLElement("datalist")}} element with some child {{HTMLElement("option")}} elements to specify the values to display.</p> + +<p>The data list is then bound to a text field (usually an <code><input></code> element) using the {{htmlattrxref("list","input")}} attribute.</p> + +<p>Once a data list is affiliated with a form widget, its options are used to auto-complete text entered by the user; typically, this is presented to the user as a drop-down box listing possible matches for what they've typed into the input.</p> + +<pre class="brush: html notranslate"><label for="myFruit">What's your favorite fruit?</label> +<input type="text" name="myFruit" id="myFruit" list="mySuggestion"> +<datalist id="mySuggestion"> + <option>Apple</option> + <option>Banana</option> + <option>Blackberry</option> + <option>Blueberry</option> + <option>Lemon</option> + <option>Lychee</option> + <option>Peach</option> + <option>Pear</option> +</datalist></pre> + +<div class="note"><strong>Note:</strong> According to <a href="http://www.w3.org/TR/html5/common-input-element-attributes.html#attr-input-list" rel="external" title="http://www.w3.org/TR/html5/common-input-element-attributes.html#attr-input-list">the HTML specification</a>, the {{htmlattrxref("list","input")}} attribute and the {{HTMLElement("datalist")}} element can be used with any kind of widget requiring a user input. However, it is unclear how it should work with controls other than text (color or date for example), and different browsers behave differently from case to case. Because of that, be cautious using this feature with anything but text fields.</div> + +<div><img alt="Screenshots of datalist on several platforms." src="/files/4593/all-datalist.png" style="height: 329px; width: 437px;"></div> + +<div></div> + +<h4 id="Datalist_support_and_fallbacks">Datalist support and fallbacks</h4> + +<p>The {{HTMLElement("datalist")}} element is a very recent addition to HTML forms, so browser support is a bit more limited than what we saw earlier. Most notably, it isn't supported in IE versions below 10, and Safari still doesn't support it at the time of writing.</p> + +<p>To handle this, here is a little trick to provide a nice fallback for those browsers:</p> + +<pre class="brush:html; notranslate"><label for="myFruit">What is your favorite fruit? (With fallback)</label> +<input type="text" id="myFruit" name="fruit" list="fruitList"> + +<datalist id="fruitList"> + <label for="suggestion">or pick a fruit</label> + <select id="suggestion" name="altFruit"> + <option>Apple</option> + <option>Banana</option> + <option>Blackberry</option> + <option>Blueberry</option> + <option>Lemon</option> + <option>Lychee</option> + <option>Peach</option> + <option>Pear</option> + </select> +</datalist> +</pre> + +<p>Browsers that support the {{HTMLElement("datalist")}} element will ignore all the elements that are not {{HTMLElement("option")}} elements and will work as expected. On the other hand, browsers that do not support the {{HTMLElement("datalist")}} element will display the label and the select box. Of course, there are other ways to handle the lack of support for the {{HTMLElement("datalist")}} element, but this is the simplest (others tend to require JavaScript).</p> + +<table> + <tbody> + <tr> + <th scope="row">Safari 6</th> + <td><img alt="Screenshot of the datalist element fallback with Safari on Mac OS" src="/files/4583/datalist-safari.png" style="height: 32px; width: 495px;"></td> + </tr> + <tr> + <th scope="row">Firefox 18</th> + <td><img alt="Screenshot of the datalist element with Firefox on Mac OS" src="/files/4581/datalist-firefox-macos.png" style="height: 102px; width: 353px;"></td> + </tr> + </tbody> +</table> + +<h2 id="Checkable_items">Checkable items</h2> + +<p>Checkable items are widgets whose state you can change by clicking on them. There are two kinds of checkable item: the check box and the radio button. Both use the {{htmlattrxref("checked","input")}} attribute to indicate whether the widget is checked by default or not.</p> + +<p>It's worth noting that these widgets do not behave exactly like other form widgets. For most form widgets, once the form is submitted all widgets that have a {{htmlattrxref("name","input")}} attribute are sent, even if no value has been filled out. In the case of checkable items, their values are sent only if they are checked. If they are not checked, nothing is sent, not even their name.</p> + +<div class="note"> +<p><strong>Note</strong>: You can find the examples from this section on GitHub as <a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/checkable-items.html">checkable-items.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/checkable-items.html">see it live also</a>).</p> +</div> + +<p>For maximum usability/accessibility, you are advised to surround each list of related items in a {{htmlelement("fieldset")}}, with a {{htmlelement("legend")}} providing an overall description of the list. Each individual pair of {{htmlelement("label")}}/{{htmlelement("input")}} elements should be contained in its own list item (or similar). This is shown in the examples. </p> + +<p>You also need to provide values for these kinds of inputs inside the <code>value</code> attribute if you want them to be meaningful — if no value is provided, check boxes and radio buttons are given a value of <code>on</code>.</p> + +<h3 id="Check_box">Check box</h3> + +<p>A check box is created using the {{HTMLElement("input")}} element with its {{htmlattrxref("type","input")}} attribute set to the value <code>checkbox</code>.</p> + +<pre class="brush: html notranslate"><input type="checkbox" checked id="carrots" name="carrots" value="carrots"> +</pre> + +<p>Including the <code>checked</code> attribute makes the checkbox checked automatically when the page loads.</p> + +<p><img alt="Screenshots of check boxes on several platforms." src="/files/4595/all-checkbox.png" style="height: 198px; width: 352px;"></p> + +<h3 id="Radio_button">Radio button</h3> + +<p>A radio button is created using the {{HTMLElement("input")}} element with its {{htmlattrxref("type","input")}} attribute set to the value <code>radio</code>.</p> + +<pre class="brush: html notranslate"><input type="radio" checked id="soup" name="meal"></pre> + +<p>Several radio buttons can be tied together. If they share the same value for their {{htmlattrxref("name","input")}} attribute, they will be considered to be in the same group of buttons. Only one button in a given group may be checked at the same time; this means that when one of them is checked all the others automatically get unchecked. When the form is sent, only the value of the checked radio button is sent. If none of them are checked, the whole pool of radio buttons is considered to be in an unknown state and no value is sent with the form.</p> + +<pre class="brush: html notranslate"><fieldset> + <legend>What is your favorite meal?</legend> + <ul> + <li> + <label for="soup">Soup</label> + <input type="radio" checked id="soup" name="meal" value="soup"> + </li> + <li> + <label for="curry">Curry</label> + <input type="radio" id="curry" name="meal" value="curry"> + </li> + <li> + <label for="pizza">Pizza</label> + <input type="radio" id="pizza" name="meal" value="pizza"> + </li> + </ul> +</fieldset></pre> + +<p><img alt="Screenshots of radio buttons on several platforms." src="/files/4597/all-radio.png" style="height: 198px; width: 352px;"></p> + +<h2 id="Buttons">Buttons</h2> + +<p>Within HTML forms, there are three kinds of button:</p> + +<dl> + <dt>Submit</dt> + <dd>Sends the form data to the server.</dd> + <dt>Reset</dt> + <dd>Resets all form widgets to their default values.</dd> + <dt>Anonymous</dt> + <dd>Buttons that have no automatic effect but can be customized using JavaScript code. If you omit the <code>type</code> attribute, this is the default value.</dd> +</dl> + +<div class="note"> +<p><strong>Note</strong>: You can find the examples from this section on GitHub as <a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/button-examples.html">button-examples.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/button-examples.html">see it live also</a>).</p> +</div> + +<p>A button is created using a {{HTMLElement("button")}} element or an {{HTMLElement("input")}} element. It's the value of the {{htmlattrxref("type","input")}} attribute that specifies what kind of button is displayed:</p> + +<h3 id="submit">submit</h3> + +<pre class="brush: html notranslate"><button type="submit"> + This a <br><strong>submit button</strong> +</button> + +<input type="submit" value="This is a submit button"></pre> + +<h3 id="reset">reset</h3> + +<pre class="brush: html notranslate"><button type="reset"> + This a <br><strong>reset button</strong> +</button> + +<input type="reset" value="This is a reset button"></pre> + +<h3 id="anonymous">anonymous</h3> + +<pre class="brush: html notranslate"><button type="button"> + This an <br><strong>anonymous button</strong> +</button> + +<input type="button" value="This is an anonymous button"></pre> + +<p>Buttons always behave the same whether you use a {{HTMLElement("button")}} element or an {{HTMLElement("input")}} element. There are, however, some notable differences:</p> + +<ul> + <li>As you can see from the examples, {{HTMLElement("button")}} elements let you use HTML content in their labels, which are inserted inside the opening and closing <code><button></code> tags. {{HTMLElement("input")}} elements on the other hand are empty elements; their labels are inserted inside <code>value</code> attributes, and therefore only accept plain text content.</li> + <li>With {{HTMLElement("button")}} elements, it's possible to have a value different than the button's label (by setting it inside a <code>value</code> attribute). This isn't reliable in versions of Internet Explorer prior to IE 8.</li> +</ul> + +<p><img alt="Screenshots of buttons on several platforms." src="/files/4599/all-buttons.png" style="height: 235px; width: 464px;"></p> + +<p>Technically speaking, there is almost no difference between a button defined with the {{HTMLElement("button")}} element or the {{HTMLElement("input")}} element. The only noticeable difference is the label of the button itself. Within an {{HTMLElement("input")}} element, the label can only be character data, whereas in a {{HTMLElement("button")}} element, the label can be HTML, so it can be styled accordingly.</p> + +<h2 id="Advanced_form_widgets">Advanced form widgets</h2> + +<p>In this section we cover those widgets that let users input complex or unusual data. This includes exact or approximate numbers, dates and times, or colors.</p> + +<div class="note"> +<p><strong>Note</strong>: You can find the examples from this section on GitHub as <a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/advanced-examples.html">advanced-examples.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/advanced-examples.html">see it live also</a>).</p> +</div> + +<h3 id="Numbers">Numbers</h3> + +<p>Widgets for numbers are created with the {{HTMLElement("input")}} element, with its {{htmlattrxref("type","input")}} attribute set to the value <code>number</code>. This control looks like a text field but allows only floating-point numbers, and usually provides some buttons to increase or decrease the value of the widget.</p> + +<p>It's also possible to:</p> + +<ul> + <li>Constrain the value by setting the {{htmlattrxref("min","input")}} and {{htmlattrxref("max","input")}} attributes.</li> + <li>Specify the amount by which the increase and decrease buttons change the widget's value by setting the {{htmlattrxref("step","input")}} attribute.</li> +</ul> + +<h4 id="Example">Example</h4> + +<pre class="brush: html notranslate"><input type="number" name="age" id="age" min="1" max="10" step="2"></pre> + +<p>This creates a number widget whose value is restricted to any value between 1 and 10, and whose increase and decrease buttons change its value by 2.</p> + +<p><code>number</code> inputs are not supported in versions of Internet Explorer below 10.</p> + +<h3 id="Sliders">Sliders</h3> + +<p>Another way to pick a number is to use a slider. Visually speaking, sliders are less accurate than text fields, therefore they are used to pick a number whose exact value is not necessarily important.</p> + +<p>A slider is created by using the {{HTMLElement("input")}} with its {{htmlattrxref("type","input")}} attribute set to the value <code>range</code>. It's important to properly configure your slider; to that end, it's highly recommended that you set the {{htmlattrxref("min","input")}}, {{htmlattrxref("max","input")}}, and {{htmlattrxref("step","input")}} attributes.</p> + +<h4 id="Example_2">Example</h4> + +<pre class="brush: html notranslate"><input type="range" name="beans" id="beans" min="0" max="500" step="10"></pre> + +<p>This example creates a slider whose value may range between 0 and 500, and whose increment/decrement buttons change the value by +10 and -10.</p> + +<p>One problem with sliders is that they don't offer any kind of visual feedback as to what the current value is. You need to add this yourself with JavaScript, but this is relatively easy to do. In this example we add an empty {{htmlelement("span")}} element, in which we will write the current value of the slider, updating it as it is changed.</p> + +<pre class="brush: html notranslate"><label for="beans">How many beans can you eat?</label> +<input type="range" name="beans" id="beans" min="0" max="500" step="10"> +<span class="beancount"></span></pre> + +<p>This can be implemented using some simple JavaScript:</p> + +<pre class="brush: js notranslate">var beans = document.querySelector('#beans'); +var count = document.querySelector('.beancount'); + +count.textContent = beans.value; + +beans.oninput = function() { + count.textContent = beans.value; +}</pre> + +<p>Here we store references to the range input and the span in two variables, then we immediately set the span's <code><a href="/en-US/docs/Web/API/Node/textContent">textContent</a></code> to the current <code>value</code> of the input. Finally, we set up an <code>oninput</code> event handler so that every time the range slider is moved, the span <code>textContent</code> is updated to the new input value.</p> + +<p><code>range</code> inputs are not supported in versions of Internet Explorer below 10.</p> + +<h3 id="Date_and_time_picker">Date and time picker</h3> + +<p>Gathering date and time values has traditionally been a nightmare for web developers. HTML5 brings some enhancements here by providing a special control to handle this specific kind of data.</p> + +<p>A date and time control is created using the {{HTMLElement("input")}} element and an appropriate value for the {{htmlattrxref("type","input")}} attribute, depending on whether you wish to collect dates, times, or both.</p> + +<h4 id="datetime-local"><code>datetime-local</code></h4> + +<p>This creates a widget to display and pick a date with time, but without any specific time zone information.</p> + +<pre class="brush: html notranslate"><input type="datetime-local" name="datetime" id="datetime"></pre> + +<h4 id="month"><code>month</code></h4> + +<p>This creates a widget to display and pick a month with a year.</p> + +<pre class="brush: html notranslate"><input type="month" name="month" id="month"></pre> + +<h4 id="time"><code>time</code></h4> + +<p>This creates a widget to display and pick a time value.</p> + +<pre class="brush: html notranslate"><input type="time" name="time" id="time"></pre> + +<h4 id="week"><code>week</code></h4> + +<p>This creates a widget to display and pick a week number and its year.</p> + +<pre class="brush: html notranslate"><input type="week" name="week" id="week"></pre> + +<p>All date and time control can be constrained using the {{htmlattrxref("min","input")}} and {{htmlattrxref("max","input")}} attributes.</p> + +<pre class="brush: html notranslate"><label for="myDate">When are you available this summer?</label> +<input type="date" name="myDate" min="2013-06-01" max="2013-08-31" id="myDate"></pre> + +<p>Warning — The date and time widgets don't have the deepest support. At the moment, Chrome, Edge, Firefox, and Opera support them well, but there is no support in Internet Explorer and Safari has patchy support.</p> + +<h3 id="Color_picker">Color picker</h3> + +<p>Colors are always a bit difficult to handle. There are many ways to express them: RGB values (decimal or hexadecimal), HSL values, keywords, etc. The color widget lets users pick a color in both textual and visual ways.</p> + +<p>A color widget is created using the {{HTMLElement("input")}} element with its {{htmlattrxref("type","input")}} attribute set to the value <code>color</code>.</p> + +<pre class="brush: html notranslate"><input type="color" name="color" id="color"></pre> + +<p>Warning — Color widget support it currently not very good. There is no support in Internet Explorer, and Safari currently doesn't support it either. The other major browsers do support it.</p> + +<h2 id="Other_widgets">Other widgets</h2> + +<p>There are a few other widgets that cannot be easily classified due to their very specific behaviors, but which are still very useful.</p> + +<div class="note"> +<p><strong>Note</strong>: You can find the examples from this section on GitHub as <a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/other-examples.html">other-examples.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/other-examples.html">see it live also</a>).</p> +</div> + +<h3 id="File_picker">File picker</h3> + +<p>HTML forms are able to send files to a server; this specific action is detailed in the article <a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data" title="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data">Sending and retrieving form data</a>. The file picker widget is how the user can choose one or more files to send.</p> + +<p>To create a file picker widget, you use the {{HTMLElement("input")}} element with its {{htmlattrxref("type","input")}} attribute set to <code>file</code>. The types of files that are accepted can be constrained using the {{htmlattrxref("accept","input")}} attribute. In addition, if you want to let the user pick more than one file, you can do so by adding the {{htmlattrxref("multiple","input")}} attribute.</p> + +<h4 id="Example_3">Example</h4> + +<p>In this example, a file picker is created that requests graphic image files. The user is allowed to select multiple files in this case.</p> + +<pre class="brush: html notranslate"><input type="file" name="file" id="file" accept="image/*" multiple></pre> + +<h3 id="Hidden_content">Hidden content</h3> + +<p>It's sometimes convenient for technical reasons to have pieces of data that are sent with a form but not displayed to the user. To do this, you can add an invisible element in your form. Use an {{HTMLElement("input")}} with its {{htmlattrxref("type","input")}} attribute set to the value <code>hidden</code>.</p> + +<p>If you create such an element, it's required to set its <code>name</code> and <code>value</code> attributes:</p> + +<pre class="brush: html notranslate"><input type="hidden" id="timestamp" name="timestamp" value="1286705410"></pre> + +<h3 id="Image_button">Image button</h3> + +<p>The <strong>image button</strong> control is one which is displayed exactly like an {{HTMLElement("img")}} element, except that when the user clicks on it, it behaves like a submit button (see above).</p> + +<p>An image button is created using an {{HTMLElement("input")}} element with its {{htmlattrxref("type","input")}} attribute set to the value <code>image</code>. This element supports exactly the same set of attributes as the {{HTMLElement("img")}} element, plus all the attributes supported by other form buttons.</p> + +<pre class="brush: html notranslate"><input type="image" alt="Click me!" src="my-img.png" width="80" height="30" /></pre> + +<p>If the image button is used to submit the form, this widget doesn't submit its value; instead the X and Y coordinates of the click on the image are submitted (the coordinates are relative to the image, meaning that the upper-left corner of the image represents the coordinate 0, 0). The coordinates are sent as two key/value pairs:</p> + +<ul> + <li>The X value key is the value of the {{htmlattrxref("name","input")}} attribute followed by the string "<em>.x</em>".</li> + <li>The Y value key is the value of the {{htmlattrxref("name","input")}} attribute followed by the string "<em>.y</em>".</li> +</ul> + +<p>So for example when you click on the image of this widget, you are sent to a URL like the following:</p> + +<pre class="notranslate">http://foo.com?pos.x=123&pos.y=456</pre> + +<p>This is a very convenient way to build a "hot map". How these values are sent and retrieved is detailed in the <a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data" title="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data"><span>Sending and retrieving form data</span></a> article.</p> + +<h3 id="Meters_and_progress_bars">Meters and progress bars</h3> + +<p>Meters and progress bars are visual representations of numeric values.</p> + +<h4 id="Progress">Progress</h4> + +<p>A progress bar represents a value that changes over time up to a maximum value specified by the {{htmlattrxref("max","progress")}} attribute. Such a bar is created using a {{ HTMLElement("progress")}} element.</p> + +<pre class="brush: html notranslate"><progress max="100" value="75">75/100</progress></pre> + +<p>This is for implementing anything requiring progress reporting, such as the percentage of total files downloaded, or the number of questions filled in on a questionnaire.</p> + +<p>The content inside the {{HTMLElement("progress")}} element is a fallback for browsers that don't support the element and for assistive technologies to vocalize it.</p> + +<h4 id="Meter">Meter</h4> + +<p>A meter bar represents a fixed value in a range delimited by a {{htmlattrxref("min","meter")}} and a {{htmlattrxref("max","meter")}} value. This value is visualy rendered as a bar, and to know how this bar looks, we compare the value to some other set values:</p> + +<ul> + <li>The {{htmlattrxref("low","meter")}} and {{htmlattrxref("high","meter")}} values divide the range in three parts: + <ul> + <li>The lower part of the range is between the {{htmlattrxref("min","meter")}} and {{htmlattrxref("low","meter")}} values (including those values).</li> + <li>The medium part of the range is between the {{htmlattrxref("low","meter")}} and {{htmlattrxref("high","meter")}} values (excluding those values).</li> + <li>The higher part of the range is between the {{htmlattrxref("high","meter")}} and {{htmlattrxref("max","meter")}} values (including those values).</li> + </ul> + </li> + <li>The {{htmlattrxref("optimum","meter")}} value defines the optimum value for the {{HTMLElement("meter")}} element. In conjuction with the {{htmlattrxref("low","meter")}} and {{htmlattrxref("high","meter")}} value, it defines which part of the range is prefered: + <ul> + <li>If the {{htmlattrxref("optimum","meter")}} value is in the lower part of the range, the lower range is considered to be the prefered part, the medium range is considered to be the average part and the higher range is considered to be the worst part.</li> + <li>If the {{htmlattrxref("optimum","meter")}} value is in the medium part of the range, the lower range is considered to be an average part, the medium range is considered to be the prefered part and the higher range is considered to be average as well.</li> + <li>If the {{htmlattrxref("optimum","meter")}} value is in the higher part of the range, the lower range is considered to be the worst part, the medium range is considered to be the average part and the higher range is considered to be the prefered part.</li> + </ul> + </li> +</ul> + +<p>All browsers that implement the {{HTMLElement("meter")}} element use those values to change the color of the meter bar:</p> + +<ul> + <li>If the current value is in the prefered part of the range, the bar is green.</li> + <li>If the current value is in the average part of the range, the bar is yellow.</li> + <li>If the current value is in the worst part of the range, the bar is red.</li> +</ul> + +<p>Such a bar is created using a {{HTMLElement("meter")}} element. This is for implementing any kind of meter, for example a bar showing total space used on a disk, which turns red when it starts to get full.</p> + +<pre class="brush: html notranslate"><meter min="0" max="100" value="75" low="33" high="66" optimum="50">75</meter></pre> + +<p>The content inside the {{HTMLElement("meter")}} element is a fallback for browsers that don't support the element and for assistive technologies to vocalize it.</p> + +<p>Support for progress and meter is fairly good — there is no support in Internet Explorer, but other browsers support it well.</p> + +<h2 id="Conclusion">Conclusion</h2> + +<p>As you'll have seen above, there are a lot of different types of available form elements — you don't need to remember all of these details at once, and can return to this article as often as you like to check up on details.</p> + +<h2 id="See_also">See also</h2> + +<p>To dig into the different form widgets, there are some useful external resources you should check out:</p> + +<ul> + <li><a href="http://wufoo.com/html5/" rel="external" title="http://wufoo.com/html5/">The Current State of HTML5 Forms</a> by Wufoo</li> + <li><a href="http://www.quirksmode.org/html5/inputs.html" rel="external" title="http://www.quirksmode.org/html5/inputs.html">HTML5 Tests - inputs</a> on Quirksmode (also <a href="http://www.quirksmode.org/html5/inputs_mobile.html" rel="external" title="http://www.quirksmode.org/html5/inputs_mobile.html">available for mobile</a> browsers)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/How_to_structure_an_HTML_form", "Learn/HTML/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Your first HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">How to structure an HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">The native form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Sending form data</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML forms in legacy browsers</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li> +</ul> diff --git a/files/ru/learn/html/index.html b/files/ru/learn/html/index.html new file mode 100644 index 0000000000..75e8f2485b --- /dev/null +++ b/files/ru/learn/html/index.html @@ -0,0 +1,60 @@ +--- +title: 'Изучение HTML: руководства и уроки' +slug: Learn/HTML +tags: + - HTML + - Введение + - Для начинающих + - Изучение + - Интро + - Новичок + - Руководство + - С нуля + - Тема +translation_of: Learn/HTML +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Чтобы создавать веб-сайты, вы должны знать о {{Glossary('HTML')}} — фундаментальной технологии, которая используется для определения структуры веб-страницы. HTML применяется для того, чтобы определить как должен отображаться ваш контент: в виде абзаца, списка, заголовка, ссылки, изображения, мультимедийного проигрывателя, формы или же в виде одного из множества других доступных элементов, а также возможного нового элемента, который вы сами создадите.</p> + +<h2 id="Путь_обучения_(образовательная_траектория)">Путь обучения (образовательная траектория)</h2> + +<p>В идеале вы должны начать свое учебное путешествие с изучения HTML. Начните с прочтения раздела <a href="/ru/docs/Web/Guide/HTML/Introduction">"Введение в HTML"</a>. Затем вы можете перейти к изучению более продвинутых тем, таких как:</p> + +<ul> + <li><a href="/ru/docs/Learn/CSS">"CSS (Каскадные таблицы стилей)"</a>, и как их использовать для оформления (стилизации) HTML-документа (например, изменение шрифта и его размера, добавление границы и теней для элементов, разбиение страницы на несколько столбцов, добавление анимации и других визуальных эффектов).</li> + <li><a href="/ru/docs/Learn/JavaScript">"JavaScript"</a>, и как его использовать для придания динамической функциональности веб-страницам (например, определение вашего местоположения и отображение его на карте, создание элементов, которые будут появлятся/исчезать при нажатии на кнопку, сохранение данных пользователей локально на их компьютерах и многое другое).</li> +</ul> + +<p>Прежде чем приступить к этой теме, вы должны иметь хотя бы базовое представление об использовании компьютеров вообще и уметь "пассивно" использовать Интернет (т.е. уметь просматривать веб-страницы, быть потребителем контента). У вас должна быть базовая рабочая среда, описанная в <a href="/ru/docs/Learn/Getting_started_with_the_web/Installing_basic_software">разделе "Установка базового программного обеспечения"</a>, а также вы должны понимать, как создавать файлы и управлять ими, что подробно описано в <a href="/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">разделе "Работа с файлами"</a> — обе статьи являются частью нашего модуля для новичков - <a href="/ru/docs/Learn/Getting_started_with_the_web">"Начало работы с вебом"</a>.</p> + +<p>Перед тем, как начать эту тему, рекомендуется пройтись по разделу <a href="/ru/docs/Learn/Getting_started_with_the_web">"Начало работы с вебом"</a>, однако это необязательно; многое из того, что описано в статье <a href="/ru/docs/Learn/Getting_started_with_the_web/HTML_basics">"Основы HTML"</a>, также рассматривается и во <a href="/ru/docs/Learn/HTML/Введение_в_HTML">"Введении в HTML"</a>, причём даже более подробно.</p> + +<h2 id="Модули">Модули</h2> + +<p>Данный раздел содержит модули, которые расположены в порядке, наиболее оптимальном для их изучения. Вам определённо следует начать с первого модуля.</p> + +<dl> + <dt><a href="/ru/docs/Learn/HTML/Введение_в_HTML">Введение в HTML</a></dt> + <dd>Этот модуль дает основу, которая позволит вам использовать важные понятия и синтаксис, вы рассмотрите применение HTML к тексту, узнаете как создать гиперссылки и как использовать HTML для структурирования веб-страницы.</dd> + <dt><a href="/ru/docs/Learn/HTML/Multimedia_and_embedding">Мультимедиа и встраивание</a></dt> + <dd>В этом модуле рассматривается использование HTML для подключения мультимедиа-контента к вашим веб-страницам, включая различные способы встраивания изображений, видео и аудио и даже других веб-страниц.</dd> + <dt> </dt> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Tables">HTML Таблицы</a></dt> + <dd>Представление табличных данных на веб-странице в понятном, {{glossary("Accessibility", "доступном")}} образе, может стать проблемой. Этот модуль описывает основы табличной разметки, а также более сложные функции, такие как реализация подписок и резюме.</dd> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Forms">HTML Формы</a></dt> + <dd>Формы - очень важная часть интернета, они обеспечивают большую часть функциональных возможностей, необходимых для взаимодействия с веб-сайтом, например, регистрация и вход в систему, отправка отзывов, покупка продуктов и многое другое. В этом модуле вы начнете с создания частей форм на стороне клиента.</dd> +</dl> + +<h2 id="Решение_общих_HTML_задач">Решение общих HTML задач</h2> + +<p><a href="/ru/docs/Learn/HTML/Howto">Использование HTML для решения общих задач</a> содержит ссылки на разделы контента, объясняющего, как использовать HTML для решения очень распространенных проблем при создании веб-страницы: работа с заголовками, добавление изображений или видео, выделение содержимого, создание базовой формы и т.д.</p> + +<h2 id="Смотрите_также">Смотрите также:</h2> + +<div class="document-head" id="wiki-document-head"> +<dl> + <dt><a href="/ru/docs/Web/HTML">HTML (HyperText Markup Language)</a> на MDN.</dt> + <dd>Отправная точка HTML документации на MDN, там вы сможете найти как подробное описание основных элементов и их атрибутов, так и более продвинутые уроки по языку, это отличное место для старта.</dd> +</dl> +</div> diff --git a/files/ru/learn/html/multimedia_and_embedding/index.html b/files/ru/learn/html/multimedia_and_embedding/index.html new file mode 100644 index 0000000000..6cf2856997 --- /dev/null +++ b/files/ru/learn/html/multimedia_and_embedding/index.html @@ -0,0 +1,57 @@ +--- +title: Мультимедиа и встраивание +slug: Learn/HTML/Multimedia_and_embedding +translation_of: Learn/HTML/Multimedia_and_embedding +--- +<p>{{LearnSidebar}}</p> + +<p>Мы уже прочли много текста в этом курсе. МНОГО текста. Но веб был бы скучным, если бы состоял только из текста, поэтому давайте посмотрим, как оживить веб при помощи более интересного контента! Этот модуль объясняет, как при помощи HTML вставлять мультимедиа в ваши web-страницы, включая разные способы вставки изображений, видео, аудио и также других страниц целиком.</p> + +<h2 id="Перед_стартом">Перед стартом</h2> + +<p>Перед изучением этого модуля, вам необходимо изучить азы HTML, изложенные во <a href="/ru/docs/Learn/HTML/Введение_в_HTML">Введении HTML</a>. <span style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>Если вы не прошли этот модуль (или что-нибудь подобное), сначала пройдите его, затем возвращайтесь!</span></p> + +<div class="note"> +<p><strong>Внимание: </strong>Если вы работаете на компьютере/планшете/другом устройстве, на котором у вас нет возможности создавать файлы, вы можете попробовать сделать упражнения на программирование (большинство из) в онлайн сервисах, например в <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководство">Руководство</h2> + +<p>Этот модуль содержит следующие статьи, которые проведут вас через все основы внедрения мультимедиа на веб-страницах.</p> + +<dl> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Multimedia_and_embedding/Изображения_в_HTML">Изображения в HTML</a></dt> + <dd> + <p>Можно рассматривать другие типы мультимедиа, но логично начать с простого элемента {{htmlelement("img")}}, используемого для встраивания простого изображения в веб-страницу. В этой статье мы увидим, как использовать его в целом, включая основы, подписывать ее используя {{htmlelement("figure")}} и как он взаимодействует с фоновым изображением CSS.</p> + </dd> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Видео и аудио контент</a></dt> + <dd><span style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>Далее мы увидим, как использовать </span><span lang="EN-US" style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>HTML</span><span style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>5-элементы {{htmlelement("video")}} и {{htmlelement("audio")}} для встраивания видео и аудио в наши страницы, включая основы, обеспечение доступа к файлам разного формата для различных браузеров, добавление надписей и субтитров, и как добавлять откаты для старых браузеров.</span></dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">От <object> до <iframe> — другие технологии встраивания</a></dt> + <dd><span style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>В этом месте мы бы хотели сделать шаг в сторону, чтобы изучить пару элементов, которые позволят встраивать широкий спектр типов контента в ваши веб-страницы: элементы {{htmlelement("iframe")}}, {{htmlelement("embed")}} и{{htmlelement("object")}}. <iframe> используется для встраивания других веб-страниц, а другие два элемента позволяют встраивать </span><span lang="EN-US" style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>PDF</span><span style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>, </span><span lang="EN-US" style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>SVG</span><span lang="EN-US" style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'> </span><span style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>и даже </span><span lang="EN-US" style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'>Flash</span><span style='font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%;'> – устаревающая технология, но все еще часто встречаемая.</span></dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Добавление векторной графики в Веб</a></dt> + <dd>Векторная графика может быть очень полезной в определенных ситуациях. В отличие от обычных форматов типа PNG/JPG, они не деформируются/пикселизируются при растяжении – они могут остаться гладкими при растягивании. Эта статья знакомит вас с понятием векторной графики и учит вас встраивать популярный формат {{glossary("SVG")}} в веб-страницы.</dd> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Адаптивные изображения</a></dt> + <dd> + <p>В этой статье мы познакомимся с концепцией адаптивных изображений - изображений, которые хорошо работают на устройствах с сильно различающимися размерами экрана, разрешением и другими подобными функциями, и рассмотрим, какие инструменты предоставляет HTML для их реализации. Это помогает повысить производительность различных устройств. Адаптивные изображения - это всего лишь одна часть адаптивного дизайна, будущая тема CSS, которую вы должны изучить.</p> + </dd> +</dl> + +<h2 id="Аттестация">Аттестация</h2> + +<p>Следующая аттестация проверит ваше понимание основ HTML, изложенных в перечисленных выше статьях.</p> + +<dl> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Страница приветствия Mozilla</a></dt> + <dd>В этой аттестации мы проверим ваши знания по некоторым технологиям, которые обсуждались в статьях этого модуля, заставляя вас добавить несколько изображений и видео на примитивную приветственную страницу, посвященную Mozilla!</dd> +</dl> + +<h2 id="Смотри_также">Смотри также</h2> + +<dl> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Add_a_hit_map_on_top_of_an_image">Как добавить карту кликов поверх изображения</a></dt> + <dd>Карта изображения предоставляет способ разделить изображение на части, которые ссылаются на разные места (представьте себе географическую карту, которая показывает подробную информацию о каждой стране, когда вы кликаете на нее.) Эта технология иногда может быть полезной.</dd> + <dt><a href="https://learning.mozilla.org/en-US/activities/web-lit-basics-two/">Основы Веб-грамотности 2</a></dt> + <dd> + <p>Превосходный курс от фонда Mozilla , который освещает и проверяет некоторые навыки, полученные в модуле<em>Мультимедиа и встраивание</em>. Погрузитесь глубже в основы верстки веб-страниц, проектирования для доступности, обмена ресурсами, использования интернет-СМИ и работы с открытым кодом.</p> + </dd> +</dl> diff --git a/files/ru/learn/html/multimedia_and_embedding/other_embedding_technologies/index.html b/files/ru/learn/html/multimedia_and_embedding/other_embedding_technologies/index.html new file mode 100644 index 0000000000..7ad838ef1b --- /dev/null +++ b/files/ru/learn/html/multimedia_and_embedding/other_embedding_technologies/index.html @@ -0,0 +1,373 @@ +--- +title: От <object> к <iframe> - другие технологии внедрения +slug: Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies +translation_of: Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<p class="summary">К настоящему моменту вы уже должны уметь прикреплять вложения на свои веб-страницы, включая изображения, видео и аудио. На этом этапе мы хотели бы сделать шаг в сторону, рассматривая некоторые элементы, которые позволяют встраивать в ваши веб-страницы самые разнообразные типы контента: {{htmlelement ("iframe")}}, {{htmlelement ( "embed")}} и {{htmlelement ("object")}}. <iframe> предназначен для встраивания других веб-страниц, а два других позволяют встраивать PDF-файлы, SVG и даже Flash - устаревшую технологию, которую вы все равно иногда увидите.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Базовая компьютерная грамотность, <a href="/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">установка базового программного обеспечения</a>, базовые знания <a href="/ru/docs/Learn/Getting_started_with_the_web/Dealing_with_files">работы с файлами</a>, знакомство с основами HTML (как описано в разделе <a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a>) и предыдущими статьями в этом модуле.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Узнать, как встраивать элементы в веб-страницы, используя {{htmlelement ("object")}}, {{htmlelement ("embed")}} и {{htmlelement ("iframe")}}, например, флеш-ролики и другие веб-страницы </td> + </tr> + </tbody> +</table> + +<h2 id="Краткая_история_внедрения">Краткая история внедрения</h2> + +<p>Давным-давно в Интернете было популярно использовать <strong>фреймы</strong> для создания веб-сайтов - небольших частей веб-сайта, хранящихся на отдельных страницах HTML. Они были встроены в главный документ, называемый <strong>набором фреймов</strong>, который позволял вам указать область на экране, которую заполнял каждый фрейм, а не столбец и строку таблицы. Они были популярны в середине и конце 90-х годов и были доказательством того, что разделение веб-страницы на более мелкие куски лучше сказывается на скорости загрузки, особенно это заметно, когда сетевые соединения были медленными. Однако у них было много проблем, которые намного перевешивали любые положительные моменты, когда скорость сети становилась выше. Поэтому вы больше не увидите, чтобы их использовали.</p> + +<p>Спустя некоторое время (конец 90-х, начало 2000-х годов) технологии плагинов, такие как Java-апплеты и Flash, стали очень популярными - это позволило веб-разработчикам встраивать богатый контент в веб-страницы, такие как видео и анимации, которые просто не были доступны только через HTML. Внедрение этих технологий осуществлялось посредством таких элементов, как {{htmlelement ("object")}} и менее используемого {{htmlelement ("embed")}}, и они были очень полезны в то время. С тех пор они вышли из моды из-за многих проблем, включая доступность, безопасность, размер файла и многое другое; в наши дни большинство мобильных устройств больше не поддерживают такие плагины, и поддержка на компьютерах также уменьшается.</p> + +<p>Наконец, появился элемент {{htmlelement ("iframe")}} (наряду с другими способами встраивания контента, например {{htmlelement ("canvas")}}, {{htmlelement ("video")}} и т. д. ) Он позволяет встраивать целый веб-документ внутри другого, как если бы это был {{htmlelement ("img")}} или другой подобный элемент, и сегодня используется повсеместно.</p> + +<p>Урок истории закончен, давайте двигаться дальше и посмотрим, как использовать некоторые из них.</p> + +<h2 id="Активное_обучение_использование_классического_внедрения">Активное обучение: использование классического внедрения</h2> + +<p>В этой статье мы собираемся перейти прямо в раздел активного обучения, чтобы сразу дать вам реальное представление о том, для чего используются технологии внедрения. Нам очень хорошо знаком Youtube, но многие не знают о некоторых доступных для него средствах совместного доступа. Давайте посмотрим, как Youtube позволяет нам встраивать видео на любую страницу, которая нам нравится, используя {{htmlelement ("iframe")}}.</p> + +<ol> + <li>Сначала перейдите на Youtube и найдите понравившееся вам видео.</li> + <li>Под видео вы найдете кнопку «Поделиться» - нажмите, чтобы отобразить параметры совместного доступа.</li> + <li>Выберите кнопку «Вставить», и вам будет предоставлен код <iframe> - скопируйте его.</li> + <li>Вставьте его в поле ввода ниже и посмотрите на результат в Output.</li> +</ol> + +<p>Дополнительно вы также можете попробовать внедрить карту Google следующим образом:</p> + +<ol> + <li>Перейдите в Карты Google и найдите подходящую вам карту.</li> + <li>Нажмите «Меню» (три горизонтальные линии) в верхнем левом углу пользовательского интерфейса.</li> + <li>Выберите параметр Ссылка/код.</li> + <li>Выберите параметр Встраивание карт, который даст вам код <iframe> - скопируйте его.</li> + <li>Вставьте его в поле ввода ниже и посмотрите на результат в Output.</li> +</ol> + +<p>Если вы допустили ошибку, вы всегда можете сбросить ее с помощью кнопки «Сброс». Если вы действительно застряли, нажмите кнопку «Показать решение», чтобы увидеть ответ.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> + +<div class="output" style="min-height: 250px;"> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="input" style="width: 95%;min-height: 100px;"> +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var htmlSolution = '<iframe width="420" height="315" src="https://www.youtube.com/embed/QH2-TGUlwu4" frameborder="0" allowfullscreen>\n</iframe>\n\n<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d37995.65748333395!2d-2.273568166412784!3d53.473310471916975!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x487bae6c05743d3d%3A0xf82fddd1e49fc0a1!2sThe+Lowry!5e0!3m2!1sen!2suk!4v1518171785211" width="600" height="450" frameborder="0" style="border:0" allowfullscreen>\n</iframe>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 600, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Подробно_об_Iframes">Подробно об Iframes</h2> + +<p>Итак, это было легко и весело, не так ли? Элементы {{htmlelement ("iframe")}} предназначены для размещения других веб-документов в текущем документе. Это отлично подходит для включения стороннего контента на ваш сайт, который, возможно, не имеет прямого контроля и не хочет реализовывать вашу собственную версию - например, видео от поставщиков онлайн-видео, системы комментариев, такие как Disqus, карты от поставщиков онлайн-карт, рекламных баннеров и т. д. Живые редактируемые примеры, которые вы использовали в этом курсе, реализованы с помощью <iframe>.</p> + +<p>Есть несколько серьезных {{anch("Проблемы безопасности", "Проблем безопасности")}} при использовании <iframe>, которые мы обсудим ниже, но это не значит, что вы не должны использовать их на своих сайтах - они просто требуют некоторых знаний и тщательного обдумывания. Давайте рассмотрим код немного подробнее. Скажем, вы хотите добавить глоссарий MDN на одну из своих веб-страниц. Вы можете попробовать что-то вроде этого:</p> + +<pre class="notranslate"><iframe src="https://developer.mozilla.org/en-US/docs/Glossary" + width="100%" height="500" frameborder="0" + allowfullscreen sandbox> + <p> <a href="https://developer.mozilla.org/en-US/docs/Glossary"> + Fallback link for browsers that don't support iframes + </a> </p> +</iframe></pre> + +<p>Этот пример включает основы, необходимые для использования <iframe>:</p> + +<dl> + <dt>{{htmlattrxref('allowfullscreen','iframe')}}</dt> + <dd>Если установлено, <iframe> может быть помещен в полноэкранный режим с использованием полноэкранного API (что несколько выходит за рамки этой статьи).</dd> + <dt>{{htmlattrxref('frameborder','iframe')}}</dt> + <dd>Если установлено значение 1, это указывает браузеру нарисовать границу между этим фреймом и другими фреймами, что является поведением по умолчанию. 0 удаляет границу. Использование этого на самом деле не рекомендуется, так как тот же эффект можно улучшить, используя {{cssxref ('border')}}: none; в {{Glossary ('CSS')}}.</dd> + <dt>{{htmlattrxref('src','iframe')}}</dt> + <dd>Этот атрибут, как и {{htmlelement ("video")}} / {{htmlelement ("img")}}, содержит путь, указывающий на URL-адрес внедряемого документа.</dd> + <dt>{{htmlattrxref('width','iframe')}} and {{htmlattrxref('height','iframe')}}</dt> + <dd>Эти атрибуты определяют ширину и высоту, в которых вы хотите использовать iframe.</dd> + <dt>Резервный контент</dt> + <dd>Точно так же, как и другие подобные элементы, такие как {{htmlelement ("video")}}, вы можете включить резервный контент между тегами открытия и закрытия <iframe> </ iframe>, которые появятся, если браузер не поддерживает < IFRAME>. В этом случае мы включили ссылку на страницу. Вряд ли вы столкнетесь с таким браузером, который не поддерживает <iframe> в наше время.</dd> + <dt>{{htmlattrxref('sandbox','iframe')}}</dt> + <dd>Этот атрибут, который работает в более современных браузерах, чем остальные функции <iframe> (например, IE 10 и выше). Он запрашивает повышенные настройки безопасности. Об этом мы расскажем в следующем разделе.</dd> +</dl> + +<div class="note"> +<p><strong>Примечание: </strong>Чтобы повысить скорость загрузки, рекомендуется установить атрибут src iframe'а с помощью JavaScript после того, как основное содержимое будет загружено. Это ускорит вашу страницу и уменьшит время загрузки официальной страницы (важный показатель {{glossary ("SEO")}}.)</p> +</div> + +<h3 id="Проблемы_безопасности">Проблемы безопасности</h3> + +<p>Выше мы упомянули о проблемах безопасности. Давайте рассмотрим это чуть подробнее. Мы не ожидаем, что вы всё поймете с первого раза. Мы просто хотим сообщить вам о проблеме и предоставить ссылку, чтобы вы могли вернуться к ней, когда станете более опытными и начнете рассматривать использование iframe в своих экспериментах и работе. Кроме того, нет необходимости бояться и не использовать <iframe> - вам просто нужно быть осторожным. Продолжим...</p> + +<p>Разработчики браузеров и веб-разработчики на горьком опыте усвоили, что iframe - частая цель (официальный термин: вектор атаки) плохих людей в Интернете (часто называемых хакерами, или, более точно, крекерами) для атаки при попытке злонамеренно изменить ваши веб-страницы или обманом заставить посетителей делать то, чего они не хотят, например, раскрыть конфиденциальную информацию вроде имени пользователя и пароли. Чтобы избежать этого, авторы спецификаций и разработчики браузеров разработали различные механизмы безопасности для обеспечения защиты <iframe>, лучшие из которых мы рассмотрим ниже.</p> + +<div class="note"> +<p>{{interwiki('wikipedia','Clickjacking')}} – это один из видов обычной атаки iframe, когда хакеры внедряют невидимый iframe в ваш документ (или внедряют ваш документ на свой собственный вредоносный веб-сайт) и используют его для захвата взаимодействия пользователей. Это обычный способ ввести пользователей в заблуждение или украсть конфиденциальные данные.</p> +</div> + +<p>Быстрый пример - попробуйте загрузить предыдущий пример, который мы показали выше, в ваш браузер (вы можете найти его живой пример на Github (см. Также исходный код). На самом деле, вы ничего не увидите на странице, т.к. если вы посмотрите в консоль в инструментах разработчика браузера, вы увидите сообщение, объясняющее вам, почему. В Firefox вы получите сообщение <em>«Отказано в доступе» в связи с X-Frame-Options: https://developer.mozilla.org/en-US/docs/Glossary не разрешает кадрирование</em>. Это связано с тем, что разработчики, которые построили MDN, включили параметр на сервере, который обслуживает страницы веб-сайта, запрещая им внедряться внутри <iframe> (см. {{Anch ("Настройка директивы CSP")}} ниже). Суть здесь такова - целой странице MDN на самом деле нет смысла встраиваться в другие страницы - конечно, если вы не хотите сделать что-то вроде встраивания их на свой сайт и выставлять их как свои собственные; или пытаться украсть данные с помощью clickjacking, что очень плохо. Плюс, если все начнут это делать, вся дополнительная пропускная способность начнет стоить Mozilla больших денег.</p> + +<h4 id="Используйте_только_при_необходимости">Используйте только при необходимости</h4> + +<p>Иногда имеет смысл вставлять сторонний контент - например, видео и карты, но вы избежите головной боли, если будете вставлять сторонний контент только тогда, когда это абсолютно необходимо. Хорошее эмпирическое правило для веб-безопасности: «Вы никогда не можете быть слишком осторожным. Если вы что-то сделали, дважды проверьте это. Если кто-то другой сделал это, считайте, что это опасно, пока не будет доказано обратное».</p> + +<div> +<p>Помимо безопасности, <span id="result_box" lang="ru"><span>вы также должны знать об интеллектуальной собственности</span></span>. Большинство контента находится под защитой авторских прав, даже тот, от которого вы не могли ожидать (например, большинство картинок на <a href="https://commons.wikimedia.org/wiki/Main_Page">Wikimedia Commons</a>). Никогда не выводите контент на свою страницу, если он вам не принадлежит или если нет однозначного письменного разрешения от правообладателя. Наказания за нарушения авторских прав строги. И, повторимся, вы никогда не можете быть слишком осторожными.</p> + +<p>Если контент лицензирован, вы должны соблюдать условия лицензии. Например, контент на MDN лицензирован на <a href="/en-US/docs/MDN/About#Copyrights_and_licenses">licensed under CC-BY-SA</a>. Это означает, что вы <a href="https://wiki.creativecommons.org/wiki/Best_practices_for_attribution">должны относиться к нам с уважением</a>, когда цитируете наш контент, даже если внесли в него существенные изменения.</p> +</div> + +<h4 id="Используйте_HTTPS">Используйте HTTPS</h4> + +<p>{{Glossary("HTTPS")}} это зашифрованная версия {{Glossary("HTTP")}}. <span id="result_box" lang="ru"><span>Вы должны обслуживать свои веб-сайты, используя HTTPS, всегда, когда это возможно</span></span> :</p> + +<ol> + <li>HTTPS уменьшает вероятность того, что контент был изменен по пути;</li> + <li>HTTPS запрещает доступ внедренного контента к контенту в вашем исходном документе и наоборот.</li> +</ol> + +<p>Использование HTTPS требует сертификат безопасности, что может обходиться в копеечку (хотя есть <a href="https://letsencrypt.org/">Let's Encrypt</a>, что облегчает задачу). Если вы не можете его получить, вы можете отдавать свой родительский документ с помощью HTTP. Однако, из-за второго преимущества HTTPS <em>во что бы то ни стало</em> вы не должны внедрять сторонний контент с HTTP. (В лучшем случае ваш браузер выдаст угрожающее предупреждение.) Все уважаемые компании, которые делают контент доступным для внедрения через <iframe>, доступны через HTTPS - посмотрите URL-адреса внутри <iframe> src при встраивании, например, содержимого из Карт Google или Youtube.</p> + +<div class="note"> +<p><strong>Примечание</strong>: <a href="/en-US/docs/Learn/Common_questions/Using_Github_pages">Github pages</a> позволяют предоставлять контент через HTTPS по умолчанию, поэтому это полезно для размещения контента. Если вы используете другой хостинг и не уверены, спросите хостинг-провайдера об этом.</p> +</div> + +<h4 id="Всегда_используйте_атрибут_sandbox">Всегда используйте атрибут <code>sandbox</code></h4> + +<p>Вы хотите дать хакерам как можно меньше возможностей, чтобы делать плохие вещи на вашем веб-сайте, поэтому вы должны позволять копипастить встроенный контент только с разрешений, необходимых для выполнения этого действия. Конечно, это относится и к вашему собственному контенту. Контейнер для кода, в котором он может использоваться надлежащим образом или для тестирования, но не может нанести вред остальной части кодовой базы (случайной или злонамеренной), называется <a href="https://en.wikipedia.org/wiki/Sandbox_(computer_security)">sandbox</a>.</p> + +<p>Контент, не ограниченный sandbox, может сделать слишком многое (выполнение JavaScript, отправка форм, всплывающие окна и т. д.). По умолчанию включайте все возможные ограничения, используя атрибут <code>sandbox</code> без параметров, как показано в предыдущем примере.</p> + +<p>Если это необходимо, вы можете добавлять разрешения один за другим (внутри значения атрибута <code>sandbox=""</code>) — смотри {{htmlattrxref('sandbox','iframe')}} ссылка для всех доступных опций. Важно отметить, что вы <em>никогда</em> не должны добавлять атрибуты <code>allow-scripts</code> и <code>allow-same-origin</code> в свой <code>sandbox</code> атрибут одновременно — в таком случае, встроенный контент может обходить политику безопасности, которая запрещает сайтам выполнять скрипты и использовать JavaScript для отключения "песочницы" sandbox .</p> + +<div class="note"> +<p>Примечание. "Песочница" не обеспечивает защиту, если злоумышленники могут обманывать людей через прямое посещение вредоносного контента (вне iframe). Если есть вероятность, что определенный контент может быть вредоносным (например, созданный пользователями контент), пожалуйста, используйте его из другого {{glossary("domain")}} на ваш основной сайт.</p> +</div> + +<h4 id="Настройка_директив_CSP"><span id="result_box" lang="ru"><span>Настройка директив CSP</span></span></h4> + +<p>{{Glossary("CSP")}} означает <strong><a href="/en-US/docs/Web/Security/CSP">политику безопасности контента</a></strong> и обеспечивает <a href="/en-US/docs/Web/Security/CSP/CSP_policy_directives">набор заголовков HTTP</a> (метаданные, отправленные вместе с вашими веб-страницами, когда они обслуживаются с веб-сервера), предназначенных для улучшения безопасности вашего HTML-документа. Когда дело доходит до обеспечения безопасности <code><iframe></code>, вы можете <em><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/X-Frame-Options">настроить сервер для отправки соответствующего <code>X-Frame-Options</code> заголовка.</a></em> Это может помешать другим веб-сайтам встраивать ваш контент на их веб-страницы (что позволило бы использовать {{interwiki('wikipedia','clickjacking')}} и множество других атак), что и было сделано разработчиками MDN, как мы видели ранее..</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете прочитать пост Фредерика Брауна <a href="https://blog.mozilla.org/security/2013/12/12/on-the-x-frame-options-security-header/">On the X-Frame-Options Security Header</a> для более детальной информации по теме. Разумеется, объяснение в этой статье далеко не полное.</p> +</div> + +<h2 id="Элементы_<embed>_и_<object>">Элементы <embed> и <object></h2> + +<p>Элементы {{htmlelement("embed")}} и {{htmlelement("object")}} служат другой функции, в отличие от iframe - эти элементы являются инструментами общего назначения для встраивания нескольких типов внешнего контента, включая плагиновые технологии, такие как Java Applets и Flash, PDF (которые могут отображаться в браузере с плагином PDF) и даже такой контент, как видео, SVG и изображения!</p> + +<div class="note"> +<p><span id="result_box" lang="ru"><span><strong>Примечание</strong>. <strong>Плагин </strong>- это программное обеспечение, обеспечивающее доступ к контенту, который браузер не может читать изначально.</span></span></p> +</div> + +<p>Тем не менее, вы вряд ли будете использовать эти элементы очень часто. Апплеты не использовались годами, Flash в настоящее время не очень популярен из-за ряда причин (см. {{Anch ("Случай с плагинами")}}, ниже), PDF-файлы, как правило, лучше открывать по ссылке, а другой контент - такой, как изображения и видео, могут обрабатываться намного проще. Плагины и эти методы внедрения действительно являются устаревшими технологиями, и мы упоминаем их здесь на случай, если вы столкнетесь с ними в определенных обстоятельствах, таких как интрасети или корпоративные проекты.</p> + +<p><span id="result_box" lang="ru"><span>Если вам нужно внедрить контент плагина, ниже исчерпывающая информация, которая вам понадобится:</span></span></p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col"></th> + <th scope="col">{{htmlelement("embed")}}</th> + <th scope="col">{{htmlelement("object")}}</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{glossary("URL")}} встраиваемого контента</td> + <td>{{htmlattrxref('src','embed')}}</td> + <td>{{htmlattrxref('data','object')}}</td> + </tr> + <tr> + <td><em>точный </em>{{glossary("MIME type", 'media type')}} встраиваемого контента</td> + <td>{{htmlattrxref('type','embed')}}</td> + <td>{{htmlattrxref('type','object')}}</td> + </tr> + <tr> + <td>высота и ширина (в пикселях) элемента, управляемого плагином</td> + <td>{{htmlattrxref('height','embed')}}<br> + {{htmlattrxref('width','embed')}}</td> + <td>{{htmlattrxref('height','object')}}<br> + {{htmlattrxref('width','object')}}</td> + </tr> + <tr> + <td>имена и значения, предоставляемые плагину в качестве параметров</td> + <td>Особые атрибуты,с их именами и значениями</td> + <td>одиночные элементы {{htmlelement("param")}}, находящиеся внутри <code><object></code></td> + </tr> + <tr> + <td>независимый HTML-контент в качестве резерва для отсутствующего ресурса</td> + <td>не поддерживается (<code><noembed></code> является устаревшим)</td> + <td>содержится внутри <code><object></code>, после элементов <code><param></code> </td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Замечание</strong>: <code><object></code> -у необходим атрибут <code>data</code> , атрибут <code>type</code> , или оба сразу. Если вы используете их вместе, вы также можете использовать атрибут {{htmlattrxref('typemustmatch','object')}} (имеющийся в наличии только в Firefox, на момент написания данной статьи). Атрибут <code>typemustmatch</code> предотвращает запуск файла, только если в в атрибут type не записан соответствующий медиа-тип. Следовательно, атрибут <code>typemustmatch</code> может предоставлять значительные преимущества в безопасности в случае встраивания контента из других источников {{glossary("origin")}} (Таким образом, не давая возможности злоумышленникам запускать произвольные скрипты посредством плагинов).</p> +</div> + +<p>Ниже представлен пример использования элемента {{htmlelement("embed")}} для вставки Flash-фильма (загляните на <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/other-embedding-technologies/embed-flash.html">live on Github</a>, а также на <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/other-embedding-technologies/embed-flash.html">check the source code</a>):</p> + +<pre class="brush: html notranslate"><embed src="whoosh.swf" quality="medium" + bgcolor="#ffffff" width="550" height="400" + name="whoosh" align="middle" allowScriptAccess="sameDomain" + allowFullScreen="false" type="application/x-shockwave-flash" + pluginspage="http://www.macromedia.com/go/getflashplayer"></pre> + +<p>Достаточно ужасно, не так ли? Html-код, генерируемый Flash, имел склонность быть значительно хуже. Он использовал элемент <code><object></code> вместе со встроенным элементом <code><embed></code> для скрытия всего фундамента (взгляните на пример). Flash ранее использовался в качестве резерва для HTML5-видео (в случае его отсутствия), но со временем необходимость в этом отпала.</p> + +<p>Давайте взглянем на пример <code><object></code> , встраивающего PDF в страницу (взгляните <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/other-embedding-technologies/object-pdf.html">live example</a> и <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/other-embedding-technologies/object-pdf.html">source code</a>):</p> + +<pre class="brush: html notranslate"><object data="mypdf.pdf" type="application/pdf" + width="800" height="1200" typemustmatch> + <p>You don't have a PDF plugin, but you can <a href="mypdf.pdf">download the PDF file.</a></p> +</object></pre> + +<p>PDF-файлы были необходимым средством достижения цели в качестве преобразования бумажной информации в цифровую, но, в то же время, они имеют множество проблем доступности и плохо читаемы на мелких экранах. В некоторых кругах они всё ещё пользуются популярностью, так что заметим, что вместо встраивания в страницу следует использовать ссылки (для скачивания или чтения на отдельной вкладке).</p> + +<h3 id="Дело_против_плагинов"><span class="short_text" id="result_box" lang="ru"><span>Дело против плагинов</span></span></h3> + +<p>Когда-то плагины были незаменимы в Интернете. Помните дни, когда вам приходилось устанавливать Adobe Flash Player для просмотра онлайн-фильма? И потом постоянно возникали раздражающие предупреждения об обновлении Flash Player и Java Runtime Environment. С тех пор веб-технологии стали намного надежнее. Почти всем сервисам пришло время прекратить доставлять контент с помощью плагинов и вместо этого использовать веб-технологии.</p> + +<ul> + <li><strong>Расширьте свою досягаемость для всех</strong>. У каждого есть браузер, но плагины используются все реже, особенно среди мобильных пользователей. Поскольку Web в значительной степени можно использовать без плагинов, люди предпочли бы просто перейти на сайты ваших конкурентов, чем установить плагин.</li> + <li><strong>Немного передохните от лишних головных болей, связанных с общедоступностью Flash-плагинов и др.( <a href="http://webaim.org/techniques/flash/">extra accessibility headaches </a>).</strong></li> + <li><strong>Избегайте лишних проблем безопасности. </strong>Ни для кого не секрет,что Adobe Flash является небезопасным, даже после многочисленных патчей. В 2015, Алекс Стэймос (бывший главный сотрудник по вопросам информационной безопасности компании Facebook) даже делал запрос, чтобы Adobe прекратил поддержку Flash.</li> +</ul> + +<p>Итак, что нужно делать? Если вам нужна интерактивность, HTML и {{glossary ("JavaScript")}} могут легко выполнить задание для вас без необходимости использования апплетов Java или устаревшей технологии ActiveX / BHO. Вместо того, чтобы полагаться на Adobe Flash, вы можете использовать видео HTML5 для своих медиа-потребностей, SVG для векторной графики и Canvas для сложных изображений и анимаций. Питер Элст уже писал несколько лет назад, что Adobe Flash редко является подходящим инструментом для работы, за исключением специализированных игр и бизнес-приложений. Что касается ActiveX, браузер Microsoft {{glossary ("Microsoft Edge", "Edge")}} больше не поддерживает его.</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Тема встраивания другого контента в веб-документы поначалу может показаться очень сложной для понимания, поэтому в этой статье мы попытались представить ее простым, знакомым способом, который сразу же станет актуальным, но все же намекает на некоторые из более сложных функций вовлеченных технологий. Начнем с того, что вы вряд ли будете использовать большое количество встраиваний стороннего контента, помимо встроенных карт и видео на своих страницах.</p> + +<p>Существует много других технологий, которые включают в себя внедрение внешнего контента, помимо тех, которые мы обсуждали здесь. Мы видели некоторые из ранних статей, например {{htmlelement ("video")}}, {{htmlelement ("audio")}} и {{htmlelement ("img")}}, но есть и другие. Например, {{htmlelement ("canvas")}} для 2D-и 3D-графики, сгенерированной JavaScript, и {{SVGElement ("svg")}} для встраивания векторной графики. Мы рассмотрим SVG в следующей статье модуля.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video and audio content</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">From <object> to <iframe> — other embedding technologies</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the Web</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></li> +</ul> diff --git a/files/ru/learn/html/multimedia_and_embedding/responsive_images/index.html b/files/ru/learn/html/multimedia_and_embedding/responsive_images/index.html new file mode 100644 index 0000000000..b65ec750e1 --- /dev/null +++ b/files/ru/learn/html/multimedia_and_embedding/responsive_images/index.html @@ -0,0 +1,242 @@ +--- +title: Адаптивные изображения +slug: Learn/HTML/Multimedia_and_embedding/Responsive_images +translation_of: Learn/HTML/Multimedia_and_embedding/Responsive_images +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<div> +<p class="summary">В данной статье мы изучим концепцию гибких (responsive) изображений — таких, которые отображаются хорошо на устройствах с сильно отличающимися размерами экрана, разрешением, и другими характеристиками — и рассмотрим инструменты, которые имеются в HTML для их реализации. Responsive images - только одна часть (и хорошее начало) гибкого веб-дизайна, темы, которая будет рассмотрена подробнее в будущем модуле на тему <a href="/en-US/docs/Learn/CSS">CSS</a>.</p> +</div> + +<table class="learn-box nostripe standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Предполагается, что вы уже знакомы с <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">основами HTML</a> и умеете <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">добавлять статичные изображения на веб-страницу</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Узнать, как использовать такие элементы, как {{htmlattrxref("srcset", "img")}} и {{htmlelement("picture")}} чтобы обеспечить работу гибких изображения на веб-сайтах.</td> + </tr> + </tbody> +</table> + +<h2 id="Почему_адаптивные_изображения">Почему адаптивные изображения?</h2> + +<p>Какую проблему мы пытаемся решить адаптивными изображениями? Давайте рассмотрим типичный сценарий. Обычный веб-сайт может содержать изображение в заголовке, для улучшения визуального восприятия пользователем, а также несколько изображений в контенте под ним. Вы, вероятно, захотите, чтобы изображение в заголовке занимало всю ширину окна, а изображения в контенте размещались где-то внутри колонки с контентом. Давайте посмотрим на следующий простой пример:</p> + +<p><img alt="Our example site as viewed on a wide screen - here the first image works ok, as it is big enough to see the detail in the center." src="https://mdn.mozillademos.org/files/12940/picture-element-wide.png" style="display: block; height: 554px; margin: 0px auto; width: 700px;"></p> + +<p>Такая вёрстка хорошо выглядит на широкоформатных экранах ноутбуков и настольных ПК, (вы можете посмотреть <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/not-responsive.html">посмотреть демо-пример</a> и найти <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/responsive-images/not-responsive.html">исходный код</a> на Github.) Мы не будем подробно рассматривать CSS, скажем только следующее:</p> + +<ul> + <li>Содержимому тега <code>main</code> задана максимальная ширина 1200 пикселей. Если окно браузера выше этой ширины, то содержимое сайта остается на 1200 пикселей и центрирует себя в доступном пространстве. Если окно браузера ниже этой ширины, содержимое устанавливается в 100% от ширины экрана.</li> + <li>Изображение в шапке всегда будет оставаться в центре тега header вне зависимости от ширины браузера. Если сайт будет просматриваться на узких экранах, то важные детали в центре изображения (люди) все равно будут видны. Все, что выходит за пределы ширины экрана будет скрыто. Высота шапки 200 пикселей.</li> + <li>Изображения в содержимом заданы так, что если ширина body становится меньше чем ширина изображения, то изображения начинают сжиматься и остаются всегда внутри body и не выступают за его пределы.</li> +</ul> + +<p>Всё хорошо, однако проблемы начинаются, когда вы просматриваете сайт на устройстве с небольшим экраном – шапка внизу выглядит нормально, но теперь она занимает значительную высоту экрана; первое изображение в контенте напротив, выглядит ужасно – при таком размере едва можно рассмотреть людей!</p> + +<p><img alt="Our example site as viewed on a narrow screen; the first image has shrunk to the point where it is hard to make out the detail on it." src="https://mdn.mozillademos.org/files/12936/non-responsive-narrow.png" style="display: block; height: 793px; margin: 0px auto; width: 320px;"></p> + +<p>Было бы намного лучше показывать обрезанную версию изображения, на котором видны важные детали снимка, когда сайт отображается на узком экране, и, возможно, что-то среднее между обрезанным и оригинальным изображениями для экранов средней ширины, таких как планшеты – это известно как <strong>art direction problem</strong>.</p> + +<p>Кроме того, нет нужды встраивать такие большие изображения на страницу, если она просматривается на маленьком экране мобильного устройства; это называется <strong>resolution switching problem</strong> — растровое изображение представляет собой точно-заданное количество пикселей по ширине и высоте; как мы успели заметить, когда рассматривали <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">векторную графику</a>, растровое изображение становится зернистым и выглядит ужасно, если оно отображается в размере большем, чем оригинальный (тогда как векторное изображение нет). В то же время, если изображение отображается в гораздо меньшем размере, чем оригинальный, это приведёт к напрасной трате трафика — пользователи мобильных устройств будут грузить большое изображение для компьютера, вместо маленького для их устройства. Идеально было бы иметь несколько файлов в разных разрешениях, и отображать нужный размер в зависимости от устройства, обращающегося к веб-сайту.</p> + +<p>Сложность в том, что для некоторых устройств с большим разрешением экрана нужны изображения большего чем ожидается размера, чтобы четче отображалось. По сути это всё одна задача в разных условиях.</p> + +<p>Можно предположить, что векторные изображения могли бы решить эти проблемы. В какой-то степени это так. У них небольшой вес и размер, поэтому их можно использовать почти в любом случае. Они хороши для простой графики, узоров, элементов интерфейса и т. д. Сложнее создать векторное изображение с большим количеством деталей, как, например, на фото. Растровые изображения (JPEG) для нашего примера подходят больше. </p> + +<p>Такого рода проблемы не было в начале существования веба, в первой половине 90-х годов – тогда единственными устройствами для просмотра веб-страниц были настольные компьютеры и ноутбуки, так что создатели браузеров и авторы спецификаций даже не задумывались о создании решения. <em>Технологии отзывчивых изображений</em> были реализованы недавно для решения проблем, указанных выше. Они позволяют вам предоставить браузеру несколько изображений, каждое из которых отображает одно и то же, но содержит разное количество пикселей (<em>resolution switching</em>), или разные изображения с отдельными областями основного изображения (<em>art direction</em>).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Новые возможности обсуждаются в статье — {{htmlattrxref("srcset", "img")}}/{{htmlattrxref("sizes", "img")}}/{{htmlelement("picture")}} — все они поддерживаются последними версиями современных настольных и мобильных браузеров (включая Microsoft Edge, но не Internet Explorer).</p> +</div> + +<h2 id="Как_сделать_изображения_отзывчивыми">Как сделать изображения отзывчивыми?</h2> + +<p>В этом разделе рассмотрим две вышеописанные проблемы и покажем, как их решить с использованием инструментов HTML {{htmlelement("img")}}. Как показано на примере выше - изображение в заголовке используется только как украшение сайта и установлено как фоновое с помощью CSS. <a href="http://blog.cloudfour.com/responsive-images-101-part-8-css-images/">CSS больше подходит для адаптивного дизайна</a> чем HTML, об этом поговорим в следующем модуле о CSS.</p> + +<h3 id="Разные_разрешения_Разные_размеры">Разные разрешения: Разные размеры</h3> + +<p>Итак, какую проблему решают разные разрешения? В зависимости от устройства нужно отобразить одно и то же изображение, но разных размеров. Посмотрите на вторую картинку в примере. Стандартный элемент {{htmlelement("img")}} обычно позволяет указать только один путь к файлу:</p> + +<pre class="brush: html notranslate"><img src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy"></pre> + +<p>Однако есть два новых атрибута — {{htmlattrxref("srcset", "img")}} and {{htmlattrxref("sizes", "img")}} — позволяющих добавить дополнительные изображения с пометками, чтобы браузер выбрал подходящее. Пример на Github: <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/responsive.html">responsive.html</a> (также смотри <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/responsive-images/responsive.html">источник кода</a>).</p> + +<pre class="brush: html notranslate"><img srcset="elva-fairy-320w.jpg 320w, + elva-fairy-480w.jpg 480w, + elva-fairy-800w.jpg 800w" + sizes="(max-width: 320px) 280px, + (max-width: 480px) 440px, + 800px" + src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy"></pre> + +<p>Атрибуты <code>srcset</code> и <code>sizes</code> кажутся сложными, но они не так плохи, если вы отформатируете их как в примере выше: каждая часть значения атрибута с новой строки. Значение состоит из списка элементов через запятую, каждый из которых включает три части. Давайте рассмотрим эти значения:</p> + +<p><strong><code>srcset</code></strong> включает названия изображений, среди которых браузер выберет нужное и их размеры.<strong> </strong>Перед каждой запятой части значения в таком порядке:</p> + +<ol> + <li>Название изображения (<code>elva-fairy-480w.jpg</code>.)</li> + <li>Пробел.</li> + <li><strong>Актуальная ширина картинки</strong> <strong>в пикселах </strong>(<code>480w</code>) — заметьте, что здесь используется <code>w</code> вместо <code>px</code>, как вы могли ожидать. Эта настоящая ширина изображения, которая может быть просмотрена в свойствах картинки на вашем компьютере (например, на Mac нужно открыть картинку в Finder и нажать <kbd>Cmd</kbd> + <kbd>I</kbd> , чтобы вывести информацию на экран).</li> +</ol> + +<p><strong><code>sizes</code></strong> определяет перечень медиа-выражений (например, ширину экрана) и указывает предпочтительную ширину изображения, когда определённое медиа-выражение истинно — это то, о чём мы говорили выше. В нашем случае, перед каждой запятой мы пишем:</p> + +<ol> + <li><strong>Медиа-условие</strong> (<code>(max-width:480px)</code>) — вы можете больше узнать об этом в <a href="/en-US/docs/Learn/CSS">CSS topic</a>, но сейчас давайте скажем, что медиа-условие описывает возможное состояние экрана. В этом случае, мы говорим "когда viewport width меньше или равен 480 пикселям".</li> + <li>Пробел.</li> + <li><strong>Ширину слота</strong> (в оригинале "width of the slot"), занимаемую изображением, когда медиа-условие истинно. (<code>440px</code>)</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: Для ширины слота, вы можете указать абсолютные значения (<code>px</code>, <code>em</code>) или значение относительно окна просмотра (<code>vw</code>), но НЕ проценты. Вы могли заметить, что у последнего слота нет медиа-условия — это значение по умолчанию, которое станет актуальным, если ни одно из предыдущих медиа-условий не будет истинно. Браузер игнорирует все последующие проверки после первого совпадения, так что будьте внимательнее к порядку их объявления.</p> +</div> + +<p>Итак, с такими атрибутами, браузер сделает следующее:</p> + +<ol> + <li>Посмотрит на ширину экрана устройства.</li> + <li>Попытается определить подходящее медиа-условие из списка в атрибуте <code>sizes</code>.</li> + <li>Посмотрит на размер слота к этому медиа-запросу.</li> + <li>Загрузит изображение из списка из <code>srcset</code>, которое имеет тот же размер, что и выбранный слот, или, если такого нет, то первое изображение, которое больше размера выбранного слота. </li> +</ol> + +<p>И это всё! На текущий момент, если поддерживающий браузер с viewport width 480px загрузит страницу, медиа-условие <code>(max-width: 480px)</code> будет истинно, следовательно, будет выбран слот <code>440px</code>, тогда будет загружено изображение <code>elva-fairy-480w.jpg</code>, так как свойство ширины (<code>480w</code>) наиболее близко значение <code>440px</code>. Условно, изоображение 800px занимает на диске 128KB, в то время как версия в 480px только 63KB — экономия в 65KB. Теперь представьте, что у вас страница, на которой много изображений. Используя это технику, вы обеспечите мобильным пользователям большую пропускную способность.</p> + +<p>Старые брузеры, не поддерживающие эти возможности, просто проигнорируют их и возьмут изображение по адресу из атрибута {{htmlattrxref("src", "img")}}.</p> + +<div class="note"> +<p><strong>Note</strong>: В описании элемента {{htmlelement("head")}} вы найдёте строку <code><meta name="viewport" content="width=device-width"></code>: это заставляет мобильные браузеры адаптировать их реальный viewport width для загрузки web-страниц (некоторые мобильные браузеры нечестны насчёт своего viewport width, вместо этого они загружают страницу в большем viewport width, а затем ужимают её, что не очень хорошо сказывается на наших отзывчивых изображениях или дизайне. Мы расскажем вам об этом больше в будущем модуле.)</p> +</div> + +<h3 id="Полезные_инструменты_разработчика">Полезные инструменты разработчика</h3> + +<p>Есть несколько полезных браузерных <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">инструментов разработчика</a>, чтобы помочь с определением необходимой ширины слотов и т. д., которые вам нужно использовать. Когда я работал над ними, я сначала загружал фиксированную версию моего примера (<code>not-responsive.html</code>), затем открывал <a href="/en-US/docs/Tools/Responsive_Design_Mode">Responsive Design View</a> (<em>Tools > Web Developer > Responsive Design View</em>), который позволяем взглянуть на layout вашей веб-страницы как если бы они были просмотрены через устройства с различными размерами экрана.</p> + +<p>Я устанавливал viewport width на 320px, затем на 480px; для каждой я обращался к <a href="/en-US/docs/Tools/Page_Inspector">DOM Inspector,</a> кликал по элементу {{htmlelement("img")}} в котором мы заинтересованы, далее смотрел размер во вкладке Box Model с правой стороны дисплея. Это должно дать вам необходимую ширину изображения</p> + +<p><img alt="A screenshot of the firefox devtools with an image element highlighted in the dom, showing its dimensions as 440 by 293 pixels." src="https://mdn.mozillademos.org/files/12932/box-model-devtools.png" style="display: block; height: 845px; margin: 0px auto; width: 480px;"></p> + +<p>А дальше вы можете проверить работает ли <code>srcset</code> если установить значение viewport width таким каким вы хотите (например, установить узкую ширину), открыв Network Inspector (<em>Tools > Web Developer > Network</em>) и затем перезагрузить страницу. Это должно дать вам перечень ресурсов которые были загружены чтобы составить (собрать) web-страницу, и тут вы можете проверить какой файл изображения был выбран для загрузки.</p> + +<p><img alt="a screenshot of the network inspector in firefox devtools, showing that the HTML for the page has been downloaded, along with three images, which include the two 800 wide versions of the responsive images" src="https://mdn.mozillademos.org/files/12934/network-devtools.png" style="display: block; height: 630px; margin: 0px auto; width: 600px;"></p> + +<h3 id="Переключения_разрешений_Одинаковый_размер_разные_разрешения">Переключения разрешений: Одинаковый размер, разные разрешения</h3> + +<p>Если вы поддерживаете несколько разрешений экрана, но все видят ваше изображение в одном и том же размере на экране, вы можете позволить браузеру выбирать изображение с подходящим разрешением используя <code>srcset</code> с x-дисриптором и без <code>sizes</code> — более простой синтаксис! Найти пример как это выглядит можно здесь <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/srcset-resolutions.html">srcset-resolutions.html</a> (смотрите также <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/responsive-images/srcset-resolutions.html">the source code</a>):</p> + +<pre class="brush: html notranslate"><img srcset="elva-fairy-320w.jpg, + elva-fairy-480w.jpg 1.5x, + elva-fairy-640w.jpg 2x" + src="elva-fairy-640w.jpg" alt="Elva dressed as a fairy"> +</pre> + +<p><img alt="A picture of a little girl dressed up as a fairy, with an old camera film effect applied to the image" src="https://mdn.mozillademos.org/files/12942/resolution-example.png" style="display: block; height: 425px; margin: 0px auto; width: 480px;">В данном примере, к изображению применяется CSS таким образом, что оно имеет ширину в 320 пикселей на экране (также называмое CSS-пикселями):</p> + +<pre class="brush: css notranslate">img { + width: 320px; +}</pre> + +<p>В этом случае, нет необходимости в <code>sizes</code> — браузер просто определяет в каком разрешении отображает дисплей и выводит наиболее подходящее изображение в соответствии с <code>srcset</code>. Таким образом, если устройство, подключаемое к странице, имеет дисплей стандартного/низкого разрешения, когда один пиксель устройства представляет (соответсвтует) каждый CSS-пиксель, то будет загружено изображение <code>elva-fairy-320w.jpg</code> (применен x1, то есть вам не надо включать его). Если устройство имеет высокое разрешение, в два пикселя устройства на каждый CSS-пиксель или более, то будет загружено изображение <code>elva-fairy-640w.jpg</code>. 640px изображение имеет размер 93KB, тогда так 320px изображение - всего 39KB.</p> + +<h3 id="Художественное_оформление">Художественное оформление</h3> + +<p>Подводя итоги, <strong>проблема художественного оформления</strong> заключается в желании изменить отображаемое изображение чтобы оно соответствовало разным размерам отображения изображения. <span class="tlid-translation translation" lang="ru"><span title="">Например, если на веб-сайте отображается большой пейзажный снимок с человеком посередине при просмотре в браузере на настольном компьютере, то при просмотре веб-сайта в мобильном браузере он уменьшается;</span></span> он будет выглядеть плохо так как человек будет очень меленьким и его будет тяжело разглядеть. Вероятно будет лучше показать меньшую портретную картинку в мобильной версии на которой человек отображается в увеличении (в приближении). Элемент {{htmlelement("picture")}} позволяет нам применять именно такое решение.</p> + +<p>Возвращаясь к нашему оригинальному примеру <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/not-responsive.html">not-responsive.html</a>, мы имеем изображение которое очень нуждается в художественном оформлении:</p> + +<pre class="brush: html notranslate"><img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva"></pre> + +<p>Давайте исправим это при помощи элемента {{htmlelement("picture")}}! Так же как <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content"><code><video></code> и <code><audio></code></a>, элемент <code><picture></code> это обертка содержащая некоторое количество элементов {{htmlelement("source")}} которые предоставляют браузеру выбор нескольких разных источников, в сопровождаении крайне важного элемента {{htmlelement("img")}}. Код <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/responsive.html">responsive.html</a> выглядит так:</p> + +<pre class="brush: html notranslate"><picture> + <source media="(max-width: 799px)" srcset="elva-480w-close-portrait.jpg"> + <source media="(min-width: 800px)" srcset="elva-800w.jpg"> + <img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva"> +</picture> +</pre> + +<ul> + <li>Элемент <code><source></code> принимает атрибут <code>media</code>, который содержит медиа-условие; при помощи этих условий опредяется, какое изображение будет выведено. В данном случае, если ширина viewport'a составит 799px или меньше, будет выведено изображение первого элемента <code><source></code>. Если ширина составит 800px и более — второго.</li> + <li>Атрибут <code>srcset</code> содержит путь изображения, которое будет выведено. Обратите внимание, что, как и в примере с <code><img></code> выше, <code><source></code> может принимать атрибуты <code>srcset</code> и <code>sizes</code> с несколько предопределенными изображниями. Так вы можете не только поместить группу изображений внутри элемента <code><picture></code>, но и задать группу предписаний для каждого из них. В реальности вы вряд ли захотите заниматься этим очень часто.</li> + <li>Вы всегда должны использовать элемент <code><img></code>, с <code>src</code> и <code>alt</code>, прямо перед <code></picture></code>, иначе изображения не появятся. Это нужно на тот случай, когда ни одно из медиа-условий не удовлетворено (например, если бы вы убрали второй элемент <code><source>)</code> или браузер не поддерживает элемент <code><picture></code>.</li> +</ul> + +<p>Этот код позволяет нам выводить отзывчивое изображение и на широких, и на узких экранах, как показано ниже:</p> + +<p><img alt="Our example site as viewed on a wide screen - here the first image works ok, as it is big enough to see the detail in the center." src="https://mdn.mozillademos.org/files/12940/picture-element-wide.png" style="display: block; height: 554px; margin: 0px auto; width: 700px;"><img alt="Our example site as viewed on a narrow screen with the picture element used to switch the first image to a portrait close up of the detail, making it a lot more useful on a narrow screen" src="https://mdn.mozillademos.org/files/12938/picture-element-narrow.png" style="display: block; height: 710px; margin: 0px auto; width: 320px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Вам следует использовать атрибут <code>media</code> только при художественном оформлении; когда вы используюте <code>media</code>, не применяйте медиа-условия с атрибутом <code>sizes</code>.</p> +</div> + +<h3 id="Почему_это_нельзя_сделать_посредством_CSS_и_JavaScript">Почему это нельзя сделать посредством CSS и JavaScript?</h3> + +<p>Когда браузер начинает загружать страницу, он начинает загрузку изображений до того, как главный парсер начал загружать и интерпретировать CSS и JavaScript. В среднем, эта техника уменьшает время загрузки страницы на 20%. Но она не так полезна в случае с адаптивными изображениями, поэтому и необходимы такие решeния, как <code>srcset</code>. Например, вы не могли бы загрузить элемент <code><img></code>, потом определить ширину viewport'а при помощи JavaScript и динамически изменить источник изображения. Изначальное изображение было бы уже загружено к тому времени, как вы загрузили его меньшую версию, что плохо.</p> + +<ul> +</ul> + +<h3 id="Смело_используйте_современные_форматы_изображений">Смело используйте современные форматы изображений</h3> + +<p>Есть несколько новых форматов изображения (таких, как WebP и JPEG-2000), которым удается сохранять высокое качество при малом размере файла. Тем не менее, браузеры поддерживают их не полностью.</p> + +<p><code><picture></code> позволяет нам использовать их в старых браузерах. Вы можете прописать MIME-тип внутри атрибута <code>type</code>, браузер сразу определит файлы такого типа как неподдерживаемые:</p> + +<pre class="brush: html notranslate"><picture> + <source type="image/svg+xml" srcset="pyramid.svg"> + <source type="image/webp" srcset="pyramid.webp"> + <img src="pyramid.png" alt="regular pyramid built from four equilateral triangles"> +</picture> +</pre> + +<ul> + <li>Не используйте атрибут <code>media</code>, если вам не нужно художественное оформление.</li> + <li>В элементе <code><source></code> можно указывать путь к изображениям только того типа, который указан в <code>type</code>.</li> + <li>Как и в предыдущих примерах, при необходимости вы можете использовать <code>srcset</code> and <code>sizes</code>.</li> +</ul> + +<h2 id="Активное_обучение_реализация_собственных_адаптивных_изображений">Активное обучение: реализация собственных адаптивных изображений</h2> + +<p>Самостоятельно создайте отзывчивое, художественно оформленное изображение для широких и узких экранов, используя <code><picture></code> и <code>srcset</code>.</p> + +<ol> + <li>Напишите простую HTML-разметку.</li> + <li>Найдите широкоформатное пейзажное фото с какой-нибудь яркой деталью. Создайте веб-версию изображения посредством графического редактора, потом обрежьте его, чтобы крупнее выделить деталь, и создайте второе изображение (примерно 480px достаточно).</li> + <li>Используйте элемент <code><picture> </code>для работы с художественно оформленной картинкой.</li> + <li>Обозначьте несколько разных размеров для этой картикни.</li> + <li>Используйте <code>srcset</code>/<code>size</code> для описания переключения при смене размеров viewport'а</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Используйте инструменты разработчика, чтобы отследить смену размера, как было описано выше.</p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>Это все для отзывчивых изображений - мы надеемся, вам понравилось играть с этими новыми технологиями. <span class="tlid-translation translation" lang="ru"><span title="">Напомним, что мы здесь обсуждали две различные проблемы:</span></span></p> + +<ul> + <li><strong>Художественное оформление</strong>: Проблема, при которой вы хотите использовать обрезанные изображения для различных макетов - например, ландшафтное изображение для полных экранов на макете компьютера и портретное изображение, показывающее увеличенный основной объект, для мобильного макета. Всё это может быть решено с помощью {{htmlelement("picture")}} элемента.</li> + <li><strong>Переключение разрешений</strong>: Проблема, при которой вы хотите использовать <span class="tlid-translation translation" lang="ru"><span title="">файлы изображений меньшего размера на устройствах с узким экраном, поскольку им не нужны огромные изображения, как на настольных дисплеях</span></span>, а также дополнительно, что вы хотите использовать изображения разного разрешения для экранов с высокой/низкой плотностью. Эту проблему можно решить с помощью <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">векторной графики</a> (SVG изображений), и {{htmlattrxref("srcset", "img")}} и {{htmlattrxref("sizes", "img")}} атрибуты.</li> +</ul> + +<p>Это так же подводит нас к окончанию целого модуля <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding">"Мультимедия и встраивание"</a>! Единственное, что вам осталось сейчас сделать перед тем, как двигаться дальше <span class="tlid-translation translation" lang="ru"><span title="">- это попробовать наше мультимедийное задание и посмотреть, как вы усвоили материал. Веселитесь!</span></span></p> + +<h2 id="Посмотрите_так_же">Посмотрите так же</h2> + +<ul> + <li><a href="http://blog.cloudfour.com/responsive-images-101-definitions">Отличное введение в отзывчивые изображения от Джейсона Григсби</a></li> + <li><a href="https://css-tricks.com/responsive-images-youre-just-changing-resolutions-use-srcset/">Отзывчивые изображения: Если вы только меняете разрешения используйте srcset</a> — включает больше объяснений того,как браузер выбирает,какое изображение использовать</li> + <li>{{htmlelement("img")}}</li> + <li>{{htmlelement("picture")}}</li> + <li>{{htmlelement("source")}}</li> +</ul> + +<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page", "Learn/HTML/Multimedia_and_embedding")}}</div> diff --git a/files/ru/learn/html/multimedia_and_embedding/video_and_audio_content/index.html b/files/ru/learn/html/multimedia_and_embedding/video_and_audio_content/index.html new file mode 100644 index 0000000000..1b7cfb7af6 --- /dev/null +++ b/files/ru/learn/html/multimedia_and_embedding/video_and_audio_content/index.html @@ -0,0 +1,293 @@ +--- +title: Видео и аудио контент +slug: Learn/HTML/Multimedia_and_embedding/Video_and_audio_content +translation_of: Learn/HTML/Multimedia_and_embedding/Video_and_audio_content +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Images_in_HTML", "Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<p class="summary">Теперь, когда мы спокойно добавляем простые изображения на веб-страницу, сделаем следующий шаг — начнём добавлять видео и аудиоплееры в ваши HTML-документы! В этой статье вы увидите, как это делать с элементами {{htmlelement("video")}} и {{htmlelement("audio")}} ; а в завершение посмотрите, как добавить титры и субтитры к вашим видео.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Базовая компьютерная грамотность, <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">установка базового ПО</a>, базовые знания <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">работа с файлами</a>, знакомство с основами HTML (как описано в <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Начало работы с HTML</a>) и <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Изображения в HTML</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Узнать, как вставлять видео и аудиоконтент в веб-страницу, а также добавлять титры или субтитры к видео. </td> + </tr> + </tbody> +</table> + +<h2 id="Аудио_и_видео_в_Интернете">Аудио и видео в Интернете</h2> + +<p>Веб-разработчики хотели использовать видео и аудио в Интернете в течение длительного времени, начиная с начала 2000-х годов, когда пропускная способность сети стала достаточной, чтобы поддерживать любое видео (видеофайлы намного больше, чем текст, или даже изображения). На раннем этапе базовые веб-технологии, такие как HTML, не имели возможности вставлять видео и аудио в Интернет, поэтому запатентованные технологии (или плагины), такие как Flash (а затем и Silverlight), стали популярными для обработки такого контента. Такая технология работала нормально, но у нее было много недостатков, включавших плохую работу с функционалом HTML и CSS, проблемы безопасности и проблемы доступности.</p> + +<p>Самостоятельное решение решило бы большую часть этого, если сделано правильно. К счастью, несколько лет спустя в спецификации {{glossary ("HTML5")}} были добавлены такие функции, с элементами {{htmlelement("video")}} и{{htmlelement("audio")}}, и некоторые новые {{glossary("JavaScript")}} {{glossary("API", "API")}} для их управления. Мы не будем рассматривать JavaScript здесь - только необходимые основы, которые могут быть достигнуты с помощью HTML.</p> + +<p>Мы не будем учить вас, как создавать аудио- и видеофайлы - для этого требуется совершенно другой набор навыков. Мы предоставили вам образцы аудио- и видеофайлов и пример кода для вашего собственного эксперимента, на случай, если у вас нет под рукой собственных.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Прежде чем вы начнете здесь, вы также должны знать, что есть немало {{glossary("OVP","OVPs")}} (провайдеров онлайн-видео) вроде <a href="https://www.youtube.com/">YouTube</a>, <a href="http://www.dailymotion.com">Dailymotion</a> и <a href="https://vimeo.com/">Vimeo</a>, а также онлайн аудио-провайдеров вроде <a href="https://soundcloud.com/">Soundcloud</a>. Такие компании предлагают удобный и простой способ размещения и потребления видео, поэтому вам не нужно беспокоиться о огромном потреблении полосы пропускания. OVP даже обычно предлагают готовый код для встраивания видео и аудио в ваши веб-страницы. Если вы пойдёте по этому пути, то сможете избежать некоторых трудностей, которые мы обсуждаем в этой статье.</p> +</div> + +<h3 id="Элемент_<video>">Элемент <video></h3> + +<p>Элемент {{htmlelement("video")}} позволяет вам вставлять видео достаточно легко. Очень простой пример выглядит так:</p> + +<pre class="brush: html notranslate"><video src="rabbit320.webm" controls> + <p>Ваш браузер не поддерживает HTML5 видео. Используйте <a href="rabbit320.webm">ссылку на видео</a> для доступа.</p> +</video></pre> + +<p>Описание параметров:</p> + +<dl> + <dt>{{htmlattrxref("src","video")}}</dt> + <dd>Точно так же, как для элемента {{htmlelement("img")}} , атрибут <code>src</code> (source — источник) содержит путь к видео, которое вы хотите внедрить. Он работает точно так же.</dd> + <dt>{{htmlattrxref("controls","video")}}</dt> + <dd>Пользователи должны иметь возможность контролировать воспроизведение видео и аудио (особенно это важно для людей, которые больны <a href="https://ru.wikipedia.org/wiki/%D0%AD%D0%BF%D0%B8%D0%BB%D0%B5%D0%BF%D1%81%D0%B8%D1%8F">эпилепсией</a>). Вы должны либо использовать атрибут <code>controls</code>, чтобы использовать встроенный в браузер интерфейс управления или создать собственный интерфейс, используя соответствующие <a href="/en-US/docs/Web/API/HTMLMediaElement">JavaScript API</a>. Как минимум, интерфейс должен включать способ запуска и остановки медиа-носителя и регулировки громкости.</dd> + <dt>Параграф внутри тегов <code><video></code></dt> + <dd>Это называют <strong>резервный контент</strong> — он будет отображаться, если браузер, показывающий страницу, не поддерживает элемент <code><video></code>, позволяя нам обеспечить поддержку для старых версий браузеров. Это может быть все, что вы захотите; в нашем примере мы предоставили прямую ссылку на видеофайл, поэтому пользователь может хотя бы получить к нему доступ, независимо от того, какой браузер он используют.</dd> +</dl> + +<p>Встроенное видео будет выглядеть примерно так:</p> + +<p><img alt="A simple video player showing a video of a small white rabbit" src="https://mdn.mozillademos.org/files/12794/simple-video.png" style="display: block; height: 592px; margin: 0px auto; width: 589px;"></p> + +<p>Вы можете <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/simple-video.html">посмотреть живой пример</a> (взгляните также на <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/video-and-audio-content/simple-video.html">исходный код</a>).</p> + +<h3 id="Поддержка_нескольких_форматов">Поддержка нескольких форматов</h3> + +<p>Присутствует одна проблема с приведенным выше примером, которую вы, возможно, уже заметили, если пытались получить доступ к прямой ссылке выше с помощью браузера, такого как Safari или Internet Explorer. Видео не будет играть!</p> + +<p>Давайте кратко рассмотрим терминологию. Форматы, такие как MP3, MP4 и WebM, называются <strong>форматами контейнеров</strong>. Они содержат различные части, которые составляют всю песню или видео — например, звуковую дорожку, видеодорожку (в случае видео) и метаданные для описания представленного носителя.</p> + +<p>Аудио и видео треки также находятся в разных форматах, например:</p> + +<ul> + <li>Контейнер WebM обычно загружает звук Ogg Vorbis с видео VP8 / VP9. Поддерживается в основном в Firefox и Chrome.</li> + <li>Контейнер MP4 часто включает аудио AAC или MP3 с видео H.264. Поддерживается в основном в Internet Explorer и Safari.</li> + <li>Более старый контейнер Ogg имеет тенденцию идти с аудио Ogg Vorbis и видео Ogg Theora. Поддерживалось главным образом в Firefox и Chrome, но было вытеснено более качественным форматом WebM.</li> +</ul> + +<p>Звуковой проигрыватель обычно воспроизводит звуковую дорожку напрямую, например, файл MP3 или Ogg.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Всё не так просто, вы можете увидеть это в нашей <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats#Browser_compatibility">таблице совместимости видео и аудио кодеков</a>. Кроме того, многие браузеры мобильных платформ могут воспроизводить неподдерживаемый формат, передавая его системному медиа-проигрывателю. Так случается и в наше время.</p> +</div> + +<p>Вышеупомянутые форматы существуют для сжатия видео и аудио в управляемые файлы (необработанные видео и аудио очень большие). Браузеры содержат разные <strong>{{Glossary("Codec","Codecs")}}</strong>, вроде Vorbis или H.264, которые используются для преобразования сжатого звука и видео в двоичные цифры и обратно. Как указано выше, браузеры, к сожалению, не поддерживают одни и те же кодеки, поэтому вам придется предоставить несколько файлов для каждого медиа-продукта. Если вам не хватает правильного кодека для декодирования носителя, он просто не сможет играть.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Возможно, вам интересно, как сложилась такая ситуация. <strong>MP3 </strong> (для аудио) и <strong>MP4/H.264</strong> (для видео) широко поддерживаются и имеют высокое качество. В то же время, они защищены патентами — американские патенты охватывают MP3 по крайней мере до 2017 года, и H.264 самое меньшее до 2027 года, так что браузеры, которые не являются держетелями этих патентов, должны платить огромные суммы денег для поддержки этих форматов. Кроме того, многие люди избегают несвободного программного обеспечения в принципе, предпочитая открытые форматы. Вот почему мы должны предоставить несколько форматов для разных браузеров.</p> +</div> + +<p>Так как мы это сделаем? Взгляните на следующий <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/video-and-audio-content/multiple-video-formats.html">обновленный пример</a> ( а также <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/multiple-video-formats.html">живой пример</a>):</p> + +<pre class="brush: html notranslate"><video controls> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Ваш браузер не подддерживает HTML5 видео. Вот <a href="rabbit320.mp4">ссылка на видео</a> взамен.</p> +</video></pre> + +<p>Здесь мы изъяли атрибут <code>src</code> из нашего тега <code><video></code>, и вместо этого включали отдельные элементы {{htmlelement("source")}}, каждый из которых ссылается на собственный источник. В этом случае браузер пройдется по элементам <code><source></code> и начнёт воспроизводить первый из них, который имеет поддерживаемый кодек. Включение источников WebM и MP4 должно быть достаточно для воспроизведения вашего видео на большинстве платформ и браузеров в наши дни.</p> + +<p>Каждый элемент <code><source></code> также имеет атрибут <code>type</code>. Он не обязательный, но рекомендуется его включать — он содержит {{glossary("MIME type","MIME types")}} видеофайла, браузеры могут прочитать их и сразу же пропустить видео, которые они не понимают. Если <code>type</code> не включен, браузеры загружают и пытаются воспроизвести каждый файл до тех пор, пока не найдут тот, который будет работать, затрачивая больше времени и ресурсов.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Наша <a href="/ru/docs/Web/HTML/Поддерживаемые_медиа_форматы">статья о поддерживаемых медиаформатах</a> описывает некоторые распространенные {{glossary("MIME type","MIME types")}}.</p> +</div> + +<h3 id="Другие_параметры_<video>">Другие параметры <video></h3> + +<p>Есть ряд других параметры, которые вы можете включить в HTML5 элемент <code>video</code>. Взгляните на наш третий пример:</p> + +<pre class="brush: html notranslate"><video controls width="400" height="400" + autoplay loop muted + poster="poster.png"> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> +</video> +</pre> + +<p>На выходе получим нечто, подобное этому:</p> + +<p><img alt="A video player showing a poster image before it plays. The poster image says HTML5 video example, OMG hell yeah!" src="https://mdn.mozillademos.org/files/12796/extra-video-features.png" style="display: block; height: 731px; margin: 0px auto; width: 653px;">Новые параметры:</p> + +<dl> + <dt>{{htmlattrxref("width","video")}} and {{htmlattrxref("height","video")}}</dt> + <dd>Вы можете контролировать размер видео либо с помощью этих атрибутов, либо с помощью {{Glossary("CSS")}}. В обоих случаях видео поддерживают собственное соотношение ширины и высоты — известное как <strong>соотношение сторон</strong>. Если соотношение сторон не поддерживается установленными вами размерами, видео будет увеличиваться, чтобы заполнить пространство по горизонтали, а заполненному пространству по умолчанию будет задан сплошной цвет фона.</dd> + <dt>{{htmlattrxref("autoplay","video")}}</dt> + <dd>Этот атрибут позволяет сразу начать воспроизведение звука или видео, пока остальная часть страницы загружается. Вам не рекомендуется использовать автовоспроизведение видео (или аудио) на ваших сайтах, потому что пользователи могут найти это действительно раздражающим.</dd> + <dt>{{htmlattrxref("loop","video")}}</dt> + <dd>Этот атрибут позволяет воспроизводить видео (или аудио) снова, когда он заканчивается. Это также может раздражать, поэтому используйте тогда, когда это действительно необходимо.</dd> + <dt>{{htmlattrxref("muted","video")}}</dt> + <dd>Этот атрибут заставляет проигрыватель воспроизводить звук, отключенный по умолчанию.</dd> + <dt>{{htmlattrxref("poster","video")}}</dt> + <dd>Этот атрибут принимает в качестве значения URL-адрес изображения, который будет отображаться до воспроизведения видео. Он предназначен для заставки к видео или рекламы.</dd> + <dt>{{htmlattrxref("preload","video")}}</dt> + <dd> + <p>этот атрибут используется в элементе для буферизации больших файлов. Он может принимать одно из трех значений:</p> + + <ul> + <li><code>"none"</code> не буферизирует файл</li> + <li><code>"auto"</code> буферизирует медиафайл</li> + <li><code>"metadata"</code> буферирует только метаданные файла</li> + </ul> + </dd> +</dl> + +<p>Вы можете найти приведенный выше пример для воспроизведения <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/extra-video-features.html">на Github</a> (также <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/video-and-audio-content/extra-video-features.html">просмотрите исходный код</a>.) Обратите внимание, что мы не включили атрибут <code>autoplay</code> в live-версию - если видео начнет воспроизводиться, как только страница загрузится, вы не увидите заставку к видео!</p> + +<h3 id="Элемент_<audio>">Элемент <audio> </h3> + +<p>Элемент {{htmlelement ("audio")}} работает точно так же, как элемент {{htmlelement ("video")}}, с несколькими небольшими отличиями, которые описаны ниже. Типичный пример может выглядеть так:</p> + +<pre class="brush: html notranslate"><audio controls> + <source src="viper.mp3" type="audio/mp3"> + <source src="viper.ogg" type="audio/ogg"> + <p>Your browser doesn't support HTML5 audio. Here is a <a href="viper.mp3">link to the audio</a> instead.</p> +</audio></pre> + +<p>В браузере это вызывает следующее:</p> + +<p><img alt="A simple audio player with a play button, timer, volume control, and progress bar" src="https://mdn.mozillademos.org/files/12798/audio-player.png" style="display: block; height: 413px; margin: 0px auto; width: 626px;"></p> + +<div class="note"> +<p>Примечание: Вы можете запустить <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/multiple-audio-formats.html">аудио-демо</a> в Github (см. также <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/video-and-audio-content/multiple-audio-formats.html">исходный код аудиоплеера</a>.)</p> +</div> + +<p>Он занимает меньше места, чем видеоплеер, поскольку нет визуального компонента - вам просто нужно отображать элементы управления для воспроизведения звука. Другие отличия от видео HTML5 заключаются в следующем:</p> + +<ul> + <li>Элемент {{htmlelement ("audio")}} не поддерживает атрибуты width / height - опять же, нет визуального компонента, поэтому присваивать ширину или высоту не к чему.</li> + <li>Он также не поддерживает атрибут <code>poster</code>- опять же, из-за отсутствия визуального компонента. </li> +</ul> + +<p>Помимо этого, <code><audio></code> поддерживает все те же функции, что и <code><video></code> - просмотрите приведенные выше разделы для получения дополнительной информации о них.</p> + +<h2 id="Отображение_текстовых_дорожек_к_видео">Отображение текстовых дорожек к видео</h2> + +<p>Теперь мы обсудим немного более продвинутую концепцию, о которой очень полезно знать. Многие люди не могут или не хотят слышать аудио / видео контент, который они находят в Интернете, по крайней мере, в определенное время. Например:</p> + +<ul> + <li>У многих людей есть слуховые нарушения (более известные как слабослышащие или глухие).</li> + <li>Другие могут не слышать звук, потому что они находятся в шумной обстановке (например, в переполненном баре при показе спортивной игры) или, возможно, не хотят беспокоить других, если они находятся в тихом месте (например, в библиотеке).</li> + <li>Люди, которые не говорят на языке из видео, могут захотеть увидеть текстовую расшифровку или даже перевод, чтобы помочь им понять медиа-контент.</li> +</ul> + +<p>Разве было бы неплохо иметь возможность предоставить этим людям транскрипцию слов, произносимых в аудио / видео? Благодаря HTML5 видео, вы можете, с форматом <a href="/en-US/docs/Web/API/Web_Video_Text_Tracks_Format">WebVTT</a> и элементом {{htmlelement ("track")}}.</p> + +<div class="note"> +<p><strong>Замечание</strong>: "Транскрибировать" значит записывать устную речь в форме письменной.Получившийся в результате текст есть 'расшифровка'.</p> +</div> + +<p>WebVTT - это формат для записи текстовых файлов, содержащих несколько строк текста, а также метаданные, такие как время, в которое вы хотите отображать каждую текстовую строку, и даже ограниченную информацию о стиле / позиционировании. Эти текстовые строки называются <strong>репликами</strong>, и вы можете отображать разные типы для разных целей, наиболее распространенными являются:</p> + +<dl> + <dt>субтитры</dt> + <dd>Переводы иностранного материала, для людей, которые не понимают слов, произнесенных в аудио.</dd> + <dt>титры</dt> + <dd>Синхронизированные транскрипции диалога или описания значимых звуков, чтобы люди, которые не могут слышать звук, поняли что происходит.</dd> + <dt>рассчитанные описания</dt> + <dd>Текст для преобразования в аудио, чтобы обслуживать людей с нарушениями зрения.</dd> +</dl> + +<p>Типичный файл WebVTT будет выглядеть примерно так:</p> + +<pre class="eval line-numbers language-html notranslate"><code class="language-html">WEBVTT + +1 +00:00:22.230 --> 00:00:24.606 +Это первый субтитр. + +2 +00:00:30.739 --> 00:00:34.074 +Это второй. + + ...</code> +</pre> + +<p>Чтобы отобразить это вместе с воспроизведением мультимедиа HTML, вам необходимо:</p> + +<ol> + <li>Сохраните его как <code>.vtt</code>- файл, в разумном месте.</li> + <li>Ссылка на файл <code>.vtt</code> с элементом {{htmlelement ("track")}}. <code><track></code> должен быть помещен в <code><audio></code> или <code><video></code>, но после элементов <code><source></code>. Используйте атрибут {{htmlattrxref ("kind", "track")}}, чтобы указать, являются ли реплики <code>субтитрами</code>, <code>титрами</code> или <code>описаниями</code>. Кроме того, используйте {{htmlattrxref ("srclang", "track")}}, чтобы сообщить браузеру, на каком языке вы записывали субтитры.</li> +</ol> + +<p>Вот пример:</p> + +<pre class="brush: html notranslate"><video controls> + <source src="example.mp4" type="video/mp4"> + <source src="example.webm" type="video/webm"> + <track kind="subtitles" src="subtitles_en.vtt" srclang="en"> +</video> +</pre> + +<p dir="ltr" id="tw-target-text">Это приведет к просмотру видео с субтитрами, таким как:</p> + +<p><img alt='Video player with stand controls such as play, stop, volume, and captions on and off. The video playing shows a scene of a man holding a spear-like weapon, and a caption reads "Esta hoja tiene pasado oscuro."' src="https://mdn.mozillademos.org/files/7887/video-player-with-captions.png" style="display: block; height: 365px; margin: 0px auto; width: 593px;"></p> + +<p>Подробнее читайте в разделе <a href="/en-US/Apps/Build/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video">добавление титров и субтитров к видео HTML5</a>. Вы можете <a href="http://iandevlin.github.io/mdn/video-player-with-captions/">найти пример</a>, который соответствует этой статье в Github, написанной Ян Девлином (см. также <a href="https://github.com/iandevlin/iandevlin.github.io/tree/master/mdn/video-player-with-captions">исходный код</a>). В этом примере используется JavaScript, позволяющий пользователям выбирать между различными субтитрами. Обратите внимание, что для включения субтитров вам нужно нажать кнопку «CC» и выбрать вариант - английский, немецкий или испанский.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Текстовые треки также помогут вам с {{glossary ("SEO")}}, так как поисковые системы особенно преуспевают в работе с текстом. Текстовые треки даже позволяют поисковым системам напрямую связываться с местом, происходящим в видео.</p> +</div> + +<h3 id="Активное_обучение_Внедрение_собственного_аудио_и_видео">Активное обучение: Внедрение собственного аудио и видео</h3> + +<p>Для этого активного обучения мы (в идеале) хотели бы, чтобы вы вышли на улицу и записали некоторые из ваших собственных видео и аудио. Большинство телефонов в эти дни позволяют легко записывать аудио и видео, и если вы можете перенести их на на свой компьютер, вы можете его использовать. Возможно, вам придется сделать некоторое преобразование, чтобы в конечном итоге получить WebM и MP4 в случае видео, а также MP3 и Ogg в случае аудио, но есть достаточно программ, чтобы вы могли сделать это без особых проблем, таких как <a href="http://www.mirovideoconverter.com/">Miro Video Converter</a> и <a href="https://sourceforge.net/projects/audacity/">Audacity</a>. Мы хотели бы, чтобы вы попробовали сделать это!</p> + +<p>Если у вас нет какого-либо видео или аудио, вы можете свободно пользоваться нашими <a href="https://github.com/mdn/learning-area/tree/master/html/multimedia-and-embedding/video-and-audio-content">образцами аудио и видео файлов</a> для выполнения этого упражнения. Вы также можете использовать наш образец кода для справки.</p> + +<p>Мы хотим, чтобы вы сделали следующие действия:</p> + +<ol> + <li>Сохраните аудио и видео файлы в новом каталоге на вашем компьютере.</li> + <li>Создайте новый HTML файл в том же каталоге, и назвать его <code>index.html</code>.</li> + <li>Добавьте элементы <code><audio></code> и <code><video> </code>на страницу; чтобы они отображали элементы управления браузером по умолчанию.</li> + <li>Введите оба варианта элемента <code><source></code>, чтобы браузеры находили оптимальный формат звука, который он поддерживает и загружает. Они должны включать <code>type</code> атрибуты.</li> + <li>Дайте элементу <code><video></code> заставку, которая будет отображаться до начала воспроизведения видео. Получайте удовольствие, создавая свою собственную заставку к видео.</li> +</ol> + +<p>Для дополнительного бонуса вы можете попробовать исследовать текстовые треки и выяснить, как добавить некоторые титры к вашему видео.</p> + +<h2 id="Краткое_изложение">Краткое изложение</h2> + +<p>Мы надеемся, что вам понравилось играть с видео и аудио на веб-страницах! В следующей статье мы рассмотрим другие способы встраивания контента в Web, используя такие технологии, как {{htmlelement ("iframe")}} и {{htmlelement ("object")}}.</p> + +<h2 id="Смотри_также">Смотри также</h2> + +<ul> + <li>{{htmlelement("audio")}}</li> + <li>{{htmlelement("video")}}</li> + <li>{{htmlelement("source")}}</li> + <li>{{htmlelement("track")}}</li> + <li><a href="/en-US/Apps/Build/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video">Adding captions and subtitles to HTML5 video</a></li> + <li><a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery">Audio and Video delivery</a>: Множество деталей встраивания аудио и видео в страницу используя HTML и Javascript.</li> + <li><a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_manipulation">Audio and Video manipulation</a>: Множество способов управления аудио и видео с помощью Javascript(вроде добавления фильтров).</li> + <li>Автоматические опции по переводу(<a href="http://www.inwhatlanguage.com/blog/translate-video-audio/">translate multimedia</a>).</li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Images_in_HTML", "Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video and audio content</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">From <object> to <iframe> — other embedding technologies</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the Web</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></li> +</ul> + +<dl> +</dl> + +<ul> +</ul> diff --git a/files/ru/learn/html/multimedia_and_embedding/добавление_r_graphics_to_the_web/index.html b/files/ru/learn/html/multimedia_and_embedding/добавление_r_graphics_to_the_web/index.html new file mode 100644 index 0000000000..10ab133f74 --- /dev/null +++ b/files/ru/learn/html/multimedia_and_embedding/добавление_r_graphics_to_the_web/index.html @@ -0,0 +1,351 @@ +--- +title: Добавление векторной графики в веб-документ +slug: Learn/HTML/Multimedia_and_embedding/Добавление_r_graphics_to_the_Web +translation_of: Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding/Responsive_images", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<div class="summary"> +<p>Векторная графика очень полезна во многих случаях. Она имеет малые размеры файла и высокую масштабируемость – при увеличении масштаба пиксели не увеличиваются вместе с графикой. В данной статье мы покажем, как встраивать векторную графику на Вашу страницу.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Навыки:</th> + <td>Знание <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">основ HTML</a> и умение <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">добавлять изображение в веб-документ</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Изучить как встроить SVG (векторное) изображение на вебстраницу.</td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Примечание</strong>: Данная статья не научит Вас векторной графике, а даст понимание что это и как ее использовать в веб-документах.</p> +</div> + +<h2 id="Что_такое_векторная_графика">Что такое векторная графика?</h2> + +<p>В веб-разработке Вы будете сталкиваться с двумя типами изображений - растровым и векторным:</p> + +<ul> + <li>Растровое изображение задается сеткой пикселей — файл растрового изображения содержит информацию о расположении и цвете каждого пикселя. Среди популярных форматов изображений данного типа числятся Bitmap (.bmp), PNG (.png), JPEG (.jpg) и GIF (.gif)</li> + <li>Векторное изображение определяется алгоритмом — файл векторного изображения содержит фигуры и правила, по которым компьютер может вычислить как должно выглядеть изображение, когда выводится на экран.{{glossary("SVG")}} формат позволяет нам создавать векторную графику для использования в веб-документах.</li> +</ul> + +<p>Для демонстрации различий между типами изображений, давайте взглянем на пример. Вы можете найти данный пример на Github как <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/adding-vector-graphics-to-the-web/vector-versus-raster.html">vector-versus-raster.html</a> — в нем демонстрируются два, на первый взгляд, одинаковых изображения, расположенных рядом друг с другом. Каждое из изображений представляет собой красную звезду с тенью. Различие их в том, что левое изображение имеет формат PNG, а правое - SVG.</p> + +<p>Различия становятся заметны, когда Вы изменяете масштаб страницы — PNG изображение становится неровным (становятся видны пиксели), потому что оно содержит информацию о положении и цвете каждого пикселя. При увеличении каждый пиксель также увеличивается, охватывая несколько пикселей дисплея, поэтому становятся заметны "кирпичики". Векторное изображение продолжает выглядеть ровным и красивым, потому что фигуры, масштабируются совместно с ним. </p> + +<p><img alt="Two star images" src="https://mdn.mozillademos.org/files/12866/raster-vector-default-size.png" style="display: block; height: 112px; margin: 0px auto; width: 223px;"></p> + +<p><img alt="Two star images zoomed in, one crisp and the other blurry" src="https://mdn.mozillademos.org/files/12868/raster-vector-zoomed.png" style="display: block; height: 328px; margin: 0px auto; width: 677px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Оба изображения сверху имеют формат PNG — слева показано растровое изображение, справа условно показано векторное изображение. Напоминаем, что пример с реальными растровым и веркторным изображениями находится по ссылке: <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/adding-vector-graphics-to-the-web/vector-versus-raster.html">vector-versus-raster.html</a> !</p> +</div> + +<p>Более того, файлы векторных изображений намного меньше растровых, т.к. в них содержится алгоритмы построения вместо информации о каждом пикселе.</p> + +<h2 id="Что_такое_SVG">Что такое SVG?</h2> + +<p><a href="https://developer.mozilla.org/en-US/docs/Web/SVG">SVG</a> это язык на базе {{glossary("XML")}} для описания векторных изображений. По сути это язык разметки, как и HTML, только содержащий множество различных элементов для определения фигур вашего изображения, а также параметров их отображения. SVG предназначен для разметки графики, а не содержимого. В простейшем случае, Вы можете использовать элементы для создания простых фигур, таких как {{svgelement("circle")}}(круг) и {{svgelement("rect")}}(прямоугольник). Более сложные SVG элементы включают {{svgelement("feColorMatrix")}} (разложение цвета с использованием матрицы), {{svgelement("animate")}} (анимация частей Вашего векторного изображения) и {{svgelement("mask")}} (примение маски к изображению.)</p> + +<p>В качестве простого примера, следующий код создает круг и прямоугольник:</p> + +<pre class="brush: html"><svg version="1.1" + baseProfile="full" + width="300" height="200" + xmlns="http://www.w3.org/2000/svg"> + <rect width="100%" height="100%" fill="black" /> + <circle cx="150" cy="100" r="90" fill="blue" /> +</svg></pre> + +<p>В результате получается следующее:</p> + +<p>{{ EmbedLiveSample('What_is_SVG', 300, 200, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>Исходя из примера выше, может показаться, что SVG легко создавать вручную. Да, простые SVG можно создавать, используя текстовый редактор, но в случае сложного изображения это становится сложным. Для создания SVG изображений используются редакторы векторной графики, такие как <a href="https://inkscape.org/en/">Inkscape</a> или <a href="https://en.wikipedia.org/wiki/Adobe_Illustrator">Illustrator</a>. Данные приложения позволяют создавать различные изображения, используя множество графических инструментов, и создавать приближения фотографий (например опция Trace Bitmap feature приложения Inkscape.)</p> + +<p>Дополнительные преимущества SVG:</p> + +<ul> + <li>Текст в векторном изображении остается машинописным (то есть доступным для поисковика, что улучшает {{glossary("SEO")}}).</li> + <li>SVG легко поддаются стилизации/программированию (scripting), потому что каждый компонент изображения может быть стилизован с помощью CSS или запрограммирован с помощью JavaScript.</li> +</ul> + +<p>Так почему же тогда вообще используют растровые изображения, а не только SVG? Дело в том, что SVG имеет ряд недостатков:</p> + +<ul> + <li>SVG может очень быстро стать сложным в том смысле, что размер файла увеличивается; сложные SVG-изображения также создают большую вычислительную нагрузку на браузер.</li> + <li>SVG может быть сложнее создать, нежели растровое изображение, в зависимости от того, какое изображение необходимо создать.</li> + <li>не поддерживается старыми версиями браузеров, то есть не подойдёт для сайтов, поддерживающих Internet Explorer 8 или старее.</li> +</ul> + +<p>В целом, растровая графика лучше подходит для сложных изображений, например, фотографий.</p> + +<div class="note"> +<p><strong>Примечание</strong>: В приложении Inkscape сохраняйте файлы как Plain SVG, для экономии места. Также, пожалуйста перейдите на <a href="http://tavmjong.free.fr/INKSCAPE/MANUAL/html/Web-Inkscape.html">статью, описывающую как подготовить SVG изображение для веб-документа.</a></p> +</div> + +<h2 id="Добавление_SVG_на_страницы">Добавление SVG на страницы</h2> + +<p>В данном разделе мы рассмотрим различные варианты, с помощью которых можно добавить SVG векторную графику на веб-страницу.</p> + +<h3 id="Быстрый_путь_htmlelementimg">Быстрый путь: {{htmlelement("img")}}</h3> + +<p>Чтобы встроить SVG используя элемент {{htmlelement ("img")}}, вам просто нужно сослаться на него в атрибуте src, как и следовало ожидать. Вам понадобится атрибут <code>height</code> или <code>width</code> (или оба, если ваш SVG не имеет собственного соотношения сторон). Если вы еще этого не делали, пожалуйста, прочтите <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Изображения в HTML</a>.</p> + +<pre class="brush: html"><img + src="equilateral.svg" + alt="triangle with all three sides equal" + height="87px" + width="100px" /></pre> + +<h4 id="Плюсы">Плюсы</h4> + +<ul> + <li>Быстрый, знакомый синтаксис изображения со встроенным текстовым эквивалентом, доступным в атрибуте <code>alt</code></li> + <li>Вы можете легко превратить изображение в гиперссылку, поместив <code><image></code> в элемент {{htmlelement("a")}}.</li> +</ul> + +<h4 id="Минусы">Минусы</h4> + +<ul> + <li>Вы не можете изменять изображение с помощью JavaScript.</li> + <li>Если вы хотите управлять содержимым SVG с помощью CSS, вы должны использовать встроенные CSS стили в своем SVG коде. (Внешние таблицы стилей, вызываемые из файла SVG, не действуют.)</li> + <li>Вы не можете изменить стиль изображения с помощью псевдоклассов CSS (например <code>:focus</code>).</li> +</ul> + +<h3 id="Устранение_неполадок_и_кросс-браузерная_поддержка">Устранение неполадок и кросс-браузерная поддержка</h3> + +<p>Для браузеров которые не поддерживают SVG (IE 8 и ниже, Android 2.3 и ниже), вы можете ссылаться на PNG или JPG в <code>src</code> атрибуте и использовать {{htmlattrxref("srcset", "img")}} атрибут (который распознают только последние браузеры) чтобы сослаться на SVG. В этом случае <span class="tlid-translation translation" lang="ru"><span title="">SVG будут загружаться только поддерживающими браузерами - старые же браузеры будут загружать PNG:</span></span></p> + +<pre class="brush: html"><img src="equilateral.png" alt="triangle with equal sides" srcset="equilateral.svg"></pre> + +<p>Также вы можете использовать SVG в качестве фоновых изображение CSS, как показано ниже. В приведенном коде ниже старые браузеры будут придерживаться PNG, который они понимают, тогда как новые браузеры будут загружать SVG:</p> + +<pre class="brush: css"><code>background: url("fallback.png") no-repeat center;</code> +background<code>-image: url("image.svg"); +background-size: contain;</code></pre> + +<p>Подобно методу <code><img></code>, описанному выше, вставка SVG с использлованием фоновых изображений CSS означает, что SVG нельзя манипулировать при помощи JavaScript, и что SVG будет иметь те же ограничения, что и CSS.</p> + +<p>Если ваши SVG не отображаются вовсе, возможно, ваш сервер не настроен должным образом. Если проблема в этом, то <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Getting_Started#A_Word_on_Webservers">данная сатья укажет вам верное направление</a>.</p> + +<h3 id="Как_включить_SVG_в_ваш_HTML_код">Как включить SVG в ваш HTML код</h3> + +<p>Вы можете открыть файл SVG в текстовом редакторе, скопировать этот код и вставить его в ваш HTML документ — такой прием иногда называют встраиванием SVG (<strong>SVG inline</strong> или <strong>inlining SVG</strong>). Убедитесь, что фрагмент вашего SVG кода начинается и заканчивается с тегов <code><a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg"><svg></svg></a></code> (не включайте ничего, кроме них). Вот очень простой пример того, что вы можете вставить в ваш документ:</p> + +<pre class="brush: html"><svg width="300" height="200"> + <rect width="100%" height="100%" fill="green" /> +</svg> +</pre> + +<h4 id="Плюсы_2">Плюсы</h4> + +<ul> + <li>Вставка вашего SVG путем <strong>SVG inline </strong>позволяет сохранить HTTP запросы и, следовательно, может уменьшить время загрузки.</li> + <li>Вы можете присваивать <code>class</code>-ы и <code>id</code> элементам SVG и стилизовать их при помощи CSS, либо в пределах SVG, либо <span class="tlid-translation translation" lang="ru"><span title="">внутри SVG, либо там, где вы размещаете правила стиля CSS для вашего HTML документа. По факту вы можете использовать любой</span></span> <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute#Presentation_attributes">атрибут представления SVG </a>как свойство CSS.</li> + <li><strong>SVG inline </strong>единственный метод, который позволяет вам использовать CSS-взаимодействия (как <code>:focus</code>) и CSS-анимацию на вашем SVG изображении (даже в вашей обычной таблице стилей).</li> + <li>Вы можете разметить SVG как гиперссылку, обернув в элемент {{htmlelement("a")}}.</li> +</ul> + +<h4 id="Минусы_2">Минусы</h4> + +<ul> + <li>Этот метод подходит, только если вы используете SVG лишь в одном месте. Дублирование делает обслуживание ресурсоемким.</li> + <li>Дополнительный SVG код увеличивает размер вашего HTML файла.</li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Браузер не может кешировать встроенный SVG, так как он кеширует обычные изображения</span></span>.</li> + <li>Вы можете добавить альтернативный вариант в элементе {{svgelement("foreignObject")}}, но браузеры поддерживающие SVG будут продолжать загружать все альтернативные изображения. Вы должны взвесить действительно стоит ли поддержка устаревших браузеров дополнительных накладных расходов (ресурсов).</li> +</ul> + +<ul> +</ul> + +<h3 id="Как_встраивать_SVG_при_помощи_htmlelementiframe">Как встраивать SVG при помощи {{htmlelement("iframe")}}</h3> + +<p>Вы можете открывать ваши SVG изображения в браузере просто как веб-страницы. Таким образом встраивание SVG документа с помощью <code><iframe></code> выполняется как мы изучали ранее в главе <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">От <object> к <iframe> — другие технологии внедрения</a>.</p> + +<p>Вот краткий обзор:</p> + +<pre class="brush: html"><iframe src="triangle.svg" width="500" height="500" sandbox> + <img src="triangle.png" alt="Triangle with three unequal sides" /> +</iframe></pre> + +<p>Это - определенно не самый лучший метод для выбора:</p> + +<h4 id="Минусы_3">Минусы</h4> + +<ul> + <li>Как вы можете видеть, у <code>iframe</code>-ов есть резервный механизм, но браузеры отображают резервный вариант только если они вообще не поддерживают <code>iframe</code>-ы.</li> + <li>Более того, до тех пор пока SVG и ваша текущая веб-страница имеют одинаковый {{glossary('origin')}}, вы не можете использовать JavaScript на вашей основной веб-странице, чтобы манипулировать SVG.</li> +</ul> + +<h2 id="Активное_изучение_поиграйте_с_SVG">Активное изучение: поиграйте с SVG</h2> + +<p>В этом разделе ативного изучения мы бы хотели, чтобы вы просто попробовали поиграть с SVG. Ниже, в областе <em>Input,</em> вы увидите, что мы уже предоставили некий пример для того, чтобы вы начали. А еще вы можете посетить <a href="/en-US/docs/Web/SVG/Element">SVG Element Reference</a>, чтобы узнать больше деталей о других игрушках, которые могут быть использованы в SVG, и тоже попробовать их. Этот раздел полностью посвящен практике ваших исследовательских навыков и вашему развлечению.</p> + +<p>Если Вы где-то застряли и ваш код не работает, Вы всегда можете начать сначала, нажав кнопку <em>Reset</em>.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html"><h2>Live output</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="input" style="width: 95%;min-height: 200px;"> + <svg width="100%" height="100%"> + <rect width="100%" height="100%" fill="red" /> + <circle cx="100%" cy="100%" r="150" fill="blue" stroke="black" /> + <polygon points="120,0 240,225 0,225" fill="green"/> + <text x="50" y="100" font-family="Verdana" font-size="55" + fill="white" stroke="black" stroke-width="2"> + Hello! + </text> + </svg> +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution" disabled> +</div></pre> + +<pre class="brush: css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var htmlSolution = ''; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 500, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Эта статья предоставила вам краткий обзор по тому, что такое векторная графика и SVG, почему полезно знать о них и как внедрять SVG в вашу веб-страницу. Эта статья не является полным руколводством по изучению SVG, а всего лишь указатель, чтоб вы знали что такое SVG, на случай, если вы встретите его во время странствий по Сети. Так что не переживайте, если вы еще не чувствуете себя экспертом в SVG. Ниже мы включили несколько ссылок, которые могут вам помочь, если вы хотите узнать больше о том, как это работает.</p> + +<p>В последней статье этого модуля мы будем исследовать адаптивные изображения в деталях, рассматривая инструменты HTML, которые позволяют делать ваши изображения так, чтоб они могли лучше работать на разных устройствах.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Getting_Started">SVG tutorial</a> on MDN</li> + <li><a href="http://thenewcode.com/744/Making-SVG-Responsive">Quick tips for responsive SVGs</a></li> + <li><a href="http://tympanus.net/codrops/2014/08/19/making-svgs-responsive-with-css/">Sara Soueidan's tutorial on responsive SVG images</a></li> + <li><a href="http://www.w3.org/TR/SVG-access/">Accessibility benefits of SVG</a></li> + <li><a href="https://css-tricks.com/scale-svg/">How to scale SVGs </a>(it's not as simple as raster graphics!)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding/Responsive_images", "Learn/HTML/Multimedia_and_embedding")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video and audio content</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">From <object> to <iframe> — other embedding technologies</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the Web</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></li> +</ul> diff --git a/files/ru/learn/html/multimedia_and_embedding/заставка_mozilla/index.html b/files/ru/learn/html/multimedia_and_embedding/заставка_mozilla/index.html new file mode 100644 index 0000000000..4171780730 --- /dev/null +++ b/files/ru/learn/html/multimedia_and_embedding/заставка_mozilla/index.html @@ -0,0 +1,106 @@ +--- +title: Заставка Mozilla +slug: Learn/HTML/Multimedia_and_embedding/заставка_Mozilla +translation_of: Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/HTML/Multimedia_and_embedding/Responsive_images", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<p class="summary">В этом задании мы проверим ваши знания приёмов, рассмотренных в статьях этого модуля, через добавление изображений и видео на забавную страницу о Mozilla!</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Прежде чем приступить к этому заданию, вы должны проработать остальную часть <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding">модуля мультимедиа и встраивания.</a></td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Для проверки знаний о встраивании изображений и видео в веб-страницы, фреймы и методы визуального восприятия HTML.</td> + </tr> + </tbody> +</table> + +<h2 id="Отправная_точка">Отправная точка</h2> + +<p>Для начала этого задания скачайте все HTML файлы и изображения, доступные на github(<a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/mdn-splash-page-start/">mdn-splash-page-start</a>). Сохраните содержимое <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/mdn-splash-page-start/index.html">index.html</a> в файле с именем <code>index.html</code> на вашем диске в новой папке. Затем сохраните <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/mdn-splash-page-start/pattern.png">pattern.png</a> в той же папке (правый клик на изображении для выбора опции сохранения).</p> + +<p>Сохраните изображения из папки <a href="https://github.com/mdn/learning-area/tree/master/html/multimedia-and-embedding/mdn-splash-page-start/originals">originals</a> тем же способом; возможно вы захотите сохранить их в другой папке пока не обработаете (некоторые из них) с помощью графического редактора.</p> + +<div class="note"> +<p><strong>Note</strong>: Приведенный для примера HTML файл содержит довольно много CSS для стилизации страницы. Вам не нужно изменять CSS, только HTML внутри {{htmlelement("body")}} элемента — пока вы используете корректную разметку, CSS будет придавать правильный внешний вид.</p> +</div> + +<h2 id="Описание_проекта">Описание проекта</h2> + +<p>В этом задании мы представляем вам почти законченый сайт-визитку Mozilla, цель которого - рассказать что-нибудь интересное о принципах Mozilla и предоставить несколько ссылок для углубленного ознакомления. К сожалению, изображения или видео не добавлены - это ваша работа! Вам нужно добавить несколько медиа-файлов для того, чтобы страница смотрелась лучше и имела больше смысла. В следующих подразделах подробно объяснено, что вам требуется сделать:</p> + +<h3 id="Подготовка_изображений">Подготовка изображений</h3> + +<p>Используя ваш любимый редактор изображений, создайте версии шириной 400px и 120px, следующих изображений:</p> + +<ul> + <li><code>firefox_logo-only_RGB.png</code></li> + <li><code>firefox-addons.jpg</code></li> + <li><code>mozilla-dinosaur-head.png</code></li> +</ul> + +<p>Назовите их как-нибудь разумно, например <code>firefoxlogo400.png</code>и <code>firefoxlogo120.png</code>.</p> + +<p>Вместе с <code>mdn.svg</code>, эти изображения будут иконками для ссылок на другие ресурсы внутри секции <code>further-info</code>. Вы также дадите ссылку на логотип Firefox в шапке сайта. Сохраните все копии внутри той же папки, что и <code>index.html</code>.</p> + +<p>Затем создайте фоновую версию <code>red-panda.jpg </code>шириной 1200px и портретную версию шириной 600px, которая показывает панду более крупным планом. Снова назовите их разумно, чтобы легко распозновать их. Сохраните обе копии внутри той же папки, что и <code>index.html</code>.</p> + +<div class="note"> +<p><strong>Note</strong>: Следует обрабатывать JPG и PNG изображения, чтобы делать их как можно меньше по весу, при сохранении хорошего вида. <a href="https://tinypng.com/">tinypng.com</a> - отличный сервис для этого.</p> +</div> + +<h3 id="Добавление_логотипа_в_шапку">Добавление логотипа в шапку</h3> + +<p>Добавьте внутрь элемента {{htmlelement("header")}} элемент {{htmlelement("img")}}, который вставит уменьшенную версию логотипа Firefox в шапку.</p> + +<h3 id="Добавление_видео_к_основному_содержанию_статьи">Добавление видео к основному содержанию статьи</h3> + +<p>Внутри элемента {{htmlelement("article")}} (сразу после открывающего тэга), вставьте ролик с YouTube по ссылке <a href="https://www.youtube.com/watch?v=ojcNcvb1olg">https://www.youtube.com/watch?v=ojcNcvb1olg</a>, используя подходящие инструменты YouTube для генерации кода. Видео должно быть 400px в ширину.</p> + +<h3 id="Добавление_отзывчивых_изображений_к_ссылкам_с_доп._информацей">Добавление отзывчивых изображений к ссылкам с доп. информацей</h3> + +<p>Внутри {{htmlelement("div")}} с классом <code>further-info</code> вы найдёте четыре элемента {{htmlelement("a")}} — каждый из которых ссылается на интересную страницу, связанную с Mozilla. Для завершения этой секции вам необходимо поместить элемент {{htmlelement("img")}} внутрь каждого элемента {{htmlelement("a")}} дополнив подходящими атрибутами {{htmlattrxref("src", "img")}}, {{htmlattrxref("alt", "img")}}, {{htmlattrxref("srcset", "img")}} и {{htmlattrxref("sizes", "img")}}.</p> + +<p>В каждом случае (кроме одного - какой из них по сути отзывчивый?) мы хотим, чтобы браузер использовал изображение шириной 120px , когда экран меньше или равен 480px, либо шириной 400px в других случаях.</p> + +<p>Убедитесь, что вы использовали изображения, соответствующие ссылкам.</p> + +<div class="note"> +<p><strong>Note</strong>: Для проверки правильности работы <code>srcset</code>/<code>sizes</code> , вам нужно загрузить ваш сайт на сервер (используйте <a href="/en-US/docs/Learn/Common_questions/Using_Github_pages">Github pages</a> - простое и бесплатное решение). Затем вы сможете проверить правильность их работы используя инструменты разработчика в браузере, как описано в <a href="/en-US/Learn/HTML/Multimedia_and_embedding/Responsive_images#Useful_developer_tools">Responsive images: useful developer tools</a>.</p> +</div> + +<h3 id="Искусственно_измененная_красная_панда">Искусственно измененная красная панда</h3> + +<p>Внутри элемента {{htmlelement("div")}} с классом <code>red-panda</code>, мы хотим поместить элемент {{htmlelement("picture")}} , который использует маленькое портретное изображение панды, если экран меньше или равен 600px, либо большое фоновое изображение.</p> + +<h2 id="Пример">Пример</h2> + +<p>Следующие скриншоты демонстрируют, как сайт-визитка выглядит, при правильной разметке, на широких и узких экранах.</p> + +<p><img alt="A wide shot of our example splash page" src="https://mdn.mozillademos.org/files/12946/wide-shot.png" style="border-style: solid; border-width: 1px; display: block; height: 620px; margin: 0px auto; width: 700px;"></p> + +<p><img alt="A narrow shot of our example splash page" src="https://mdn.mozillademos.org/files/12944/narrow-shot.png" style="border-style: solid; border-width: 1px; display: block; height: 1069px; margin: 0px auto; width: 320px;"></p> + +<h2 id="Заключение">Заключение</h2> + +<p>Если вы выполняете это задание как часть организованного курса вам следует передать вашу работу учителю/наставнику для оценки. Если вы обучаетесь самостоятельно, то вы легко можете получить отметку <a href="https://discourse.mozilla.org/t/mozilla-splash-page-assessment/24679">в ветке форума этого упражнения</a>, либо в IRC канале <a href="irc://irc.mozilla.org/mdn">#mdn</a> на <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Сначала попробуйте выполнить упражнение - жульничеством ничего не добиться! </p> + +<p>{{PreviousMenu("Learn/HTML/Multimedia_and_embedding/Responsive_images", "Learn/HTML/Multimedia_and_embedding")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Изображения в HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Видео и аудио контент</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">От <object> до <iframe> — другие технологии встраивания</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Добавление векторной графики в Web</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Отзывчивые изображения</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Сайт-визитка Mozilla</a></li> +</ul> diff --git a/files/ru/learn/html/multimedia_and_embedding/изображения_в_html/index.html b/files/ru/learn/html/multimedia_and_embedding/изображения_в_html/index.html new file mode 100644 index 0000000000..930362d696 --- /dev/null +++ b/files/ru/learn/html/multimedia_and_embedding/изображения_в_html/index.html @@ -0,0 +1,356 @@ +--- +title: Изображения в HTML +slug: Learn/HTML/Multimedia_and_embedding/Изображения_в_HTML +translation_of: Learn/HTML/Multimedia_and_embedding/Images_in_HTML +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<p class="summary">В начале Web был просто текстом, что было довольно скучно. К счастью, это продолжалось не долго - до появления возможности вставлять изображения (и другие, более интересные, типы контента) в веб-страницы. Существуют и другие типы мультимедиа, однако логичнее начать со скромного {{htmlelement("img")}} элемента, используемого для вставки простого изображения в веб-страницу. В этой статье мы рассмотрим, как использовать элемент, начиная с основ, снабжать примечаниями, используя {{htmlelement("figure")}}, и разберём, как это относится к фоновым изображениям {{glossary("CSS")}}. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимы:</th> + <td>Базовые знания компьютера, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">установленное базовое ПО</a>, базовые знания по <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">работе с файлами</a>, (как описано в статье <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a>.)</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Научиться вставлять простые изображения в HTML, приписывать их комментариями, и какое отношение HTML изображения имеют к фоновым изображениям CSS.</td> + </tr> + </tbody> +</table> + +<h2 id="Как_разместить_картинку_на_странице">Как разместить картинку на странице?</h2> + +<p>Для того, что бы разместить изображение на странице, нужно использовать тег {{htmlelement("img")}}. Это пустой элемент (имеется ввиду что, не содержит текста и закрывающего тега) который требует минимум один атрибут для использования — <code>src</code> (произносится <em>эс-ар-си</em>, иногда говорят его полное название, <em>со-о-рс</em>). Атрибут <code>src</code> содержит путь к изображению которое вы хотите встроить в страницу, который может быть относительным или абсолютным URL, таким же образом, как для элемента {{htmlelement("a")}} значение атрибута <code>href</code>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Перед тем как продолжить, вы можете прочитать <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#A_quick_primer_on_URLs_and_paths">Быстрый пример про URL - адресс и путь</a> чтобы обновить свою память про относительный и абсолютный URL - адресс.</p> +</div> + +<p>Например, если ваше изображение называется <code>dinosaur.jpg</code>, и оно находится в той же директории что и ваша HTML страница, вы можете встроить это изображение как:</p> + +<pre class="brush: html notranslate"><img src="dinosaur.jpg"></pre> + +<p>Если изображение было в поддиректории <code>images</code> , находящаяся внутри директории, в которой HTML страница (что рекомендует Google для индексации SEO целей), тогда вы можете встроить ее как:</p> + +<pre class="brush: html notranslate"><img src="images/dinosaur.jpg"></pre> + +<p>И так далее.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Поисковые системы также читают имена изображений и считают их для оптимизации поискового запроса. Поэтому, давайте вашим изображениям смысловые имена; <code>dinosaur.jpg</code> лучше, чем <code>img835.png</code>.</p> +</div> + +<p>Вы можете встроить изображение используя абсолютный URL, например:</p> + +<pre class="brush: html notranslate"><img src="https://www.example.com/images/dinosaur.jpg"></pre> + +<p>Но это бесмыссленно, так как он просто заставляет браузер делать больше работы, используя IP-адрес от DNS-сервера все снова, и т.д. Вы почти всегда будете держать свои изображения для сайта на том же сервере, что и ваш HTML.</p> + +<div class="warning"> +<p><strong>Внимание:</strong> Большиство изображений защищены. Не отображайте изображения на вашем сайте пока:<br> + <br> + 1) вы не будете владеть изображением<br> + 2) у вас не будет письменного разрешения владельца изображения, или<br> + 3) пока у вас не будет достаточно доказательств что изображение находится в открытом доступе.<br> + <br> + Нарушение авторских прав является не законным. Кроме того, никогда не указывайте в своем атрибуте <code>src</code> ссылку на изображение, размещенную на чужом сайте. Это называется "хотлинкинг" (с англ. 'hotlinking' - 'горячая ссылка'). Запомните, кража чей-то пропускной способности не законно. Кроме того, это замедляет вашу страницу, оставляя вас без контроля над изображением; было ли оно удалено или случайно перемещено.</p> +</div> + +<p>Наш код выше даст нам следующий результат:</p> + +<p><img alt="A basic image of a dinosaur, embedded in a browser, with Images in HTML written above it" src="https://mdn.mozillademos.org/files/12700/basic-image.png" style="display: block; height: 700px; margin: 0px auto; width: 700px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Элементы как {{htmlelement("img")}} и {{htmlelement("video")}} иногда называются заменяемые элементы. Это потому что содержание элемента и размер, определяет внешний ресурс (как изображение или видео файл), а не содержание самого элемента. </p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти готовый пример здесь <a href="https://mdn.github.io/learning-area/html/multimedia-and-embedding/images-in-html/index.html">running on Github</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/images-in-html/index.html">source code</a> too.)</p> +</div> + +<h3 id="Альтернативный_текст">Альтернативный текст</h3> + +<p>Следующий атрибут, который мы рассмотрим, — <code>alt</code>. Предполагается, что значением атрибута является текстовое описание изображения; данный атрибут используется в ситуациях, когда изображение скрыто или его не удается отобразить. Чтобы продемонстрировать использование атрибута <code>alt</code> на практике, внесем изменения в код из предыдущего примера:</p> + +<p><img src="images/dinosaur.jpg"<br> + alt="The head and torso of a dinosaur skeleton;<br> + it has a large head with long sharp teeth"></p> + +<p class="syntaxbox">Самый простой способ увидеть атрибут <code>alt</code> в действии — это сделать намеренную ошибку в имени файла. Например, если бы мы написали имя изображения как <code>dinosooooor.jpg</code>, браузер не смог бы его отобразить, и на экране появился бы текст из атрибута <code>alt</code>:</p> + +<p><img alt="The Images in HTML title, but this time the dinosaur image is not displayed, and alt text is in its place." src="https://mdn.mozillademos.org/files/12702/alt-text.png" style="display: block; height: 700px; margin: 0px auto; width: 700px;">Итак, в каких случаях текст из атрибута <code>alt</code> может быть нам полезен? Приведем несколько примеров:</p> + +<ul> + <li>Пользователь с нарушением зрения использует <a href="https://en.wikipedia.org/wiki/Screen_reader">устройство чтения с экрана</a>, которое может читать вслух описание элементов веб-страницы. На самом деле, наличие текста в атрибуте <code>alt</code> для описания изображения может быть полезно для большинства пользователей.</li> + <li>В случае, если была допущена ошибка в имени файла или пути к нему (как было описано выше).</li> + <li>Браузер не поддерживает формат данного изображения. Некоторые люди до сих пор используют текстовые браузеры, такие как <a href="https://en.wikipedia.org/wiki/Lynx_%28web_browser%29">Lynx</a>, которые вместо изображений отображают текст из атрибута <code>alt</code>.</li> + <li>Если вы хотите добавить возможность найти ваше изображение с помощью поисковых систем. Например, поисковые системы могут искать совпадения поисковых запросов с текстом атрибута <code>alt</code>.</li> + <li>Если пользователи отключили отображение изображений на странице для уменьшения объема передаваемых данных и для сокрытия элементов, отвлекающих внимание. Это обычная практика для пользователей мобильных телефонов, а также в странах с маленькой пропускной способностью интернет-каналов и с высокой стоимостью интернет-трафика.</li> +</ul> + +<p>Что именно вы должны писать в атрибут <code>alt</code>? В первую очередь, это зависит от того, <em>зачем</em> изображение вообще находится на странице. Другими словами, что вы потеряете, если ваше изображение не появится:</p> + +<ul> + <li><strong>Декорация. </strong>Если изображение служит просто украшением и не является частью содержимого, добавьте пустой <code>alt=""</code>. Например, программа чтения с экрана не тратит время на чтение содержимого, которое не является важным для пользователя. На самом деле, декоративные изображения не принадлежат вашему HTML. {{anch("CSS background images")}} должны быть использованы для вставки декораций, но, если это неизбежно, то лучшее решение - использовать <code>alt=""</code>.</li> + <li><strong>Контент.</strong> Если ваше изображение содержит важную информацию, передайте ту же информацию через краткий<em> </em><code>alt</code>. Или даже лучше, в <em>главном</em> тексте, который все увидят. Не используйте <code>alt</code> , если можете обойтись без него. Насколько неудобно было бы для пользователя если бы <em>параграфы</em> были написаны дважды в <em>главном контенте</em>? Если изображение адекватно описано в основном тексте, можете просто использовать <code>alt=""</code>.</li> + <li><strong>Ссылка.</strong> Если вы помещаете изображение в {{htmlelement("a")}}, для того, чтобы сделать из него ссылку, вы всё ещё должны предоставить <a href="/en-US/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#Use_clear_link_wording">accessible link text</a>. В таком случае, вы сможете использовать элемент <code><a></code> или атрибут <code>alt</code> . Старайтесь выбрать лучший вариант.</li> + <li><strong>Текст.</strong> Не пишите текст в изображениях. Если вашему заголовку понадобиться тень, то лучше используйте для этого<a href="/en-US/docs/Web/CSS/text-shadow"> CSS</a> вместо добавления текста в изображение. Однако, если <em>действительно этого не избежать</em>, то вам следует дополнить текст в атрибуте <code>alt</code>.</li> +</ul> + +<p>По существу, главная идея здесь это предоставить нечто полезное, для случая когда изображения не видны. Это гарантирует что все пользователи не упустят ничего из содержимого страницы. Попробуйте отключить изображения в своём браузере и посмотрите как всё выглядит. Вы вскоре выясните насколько полезным является альтернативный текст если изображения не видны.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Более подробную информацию, смотрите здесь <a href="/en-US/docs/Learn/Accessibility/HTML#Text_alternatives">Text Alternatives</a>.</p> +</div> + +<h3 id="Ширина_и_высота">Ширина и высота</h3> + +<p>Вы можете использовать атрибуты <code>width</code> и <code>height</code>, чтобы указать ширину и высоту вашего изображения . Ширину и высоту вашего избражение можете найти различными способами. Например на Mac можно использовать <kbd>Cmd</kbd> + <kbd>I</kbd> что получить информацию по изображению. Повторяя наш пример, мы можем сделать так:</p> + +<pre class="brush: html notranslate"><img src="images/dinosaur.jpg" + alt="The head and torso of a dinosaur skeleton; + it has a large head with long sharp teeth" + width="400" + height="341"></pre> + +<p>Это не приводит к большой разнице в отображении при нормальных обстоятельствах. Но если изображение не будет показано, например, когда пользователь только что перешёл на страницу, а оно ещё не успело загрузится, вы укажите браузеру оставить место для отрисовки изображения:</p> + +<p><img alt="The Images in HTML title, with dinosaur alt text, displayed inside a large box that results from width and height settings" src="https://mdn.mozillademos.org/files/12706/alt-text-with-width-height.png" style="display: block; height: 700px; margin: 0px auto; width: 700px;"></p> + +<p>Это хорошая практика, в результате страница загрузится быстрей и более гладко.</p> + +<p>Однако, вы не должны изменять размеры ваших изображений используя HTML аттрибуты. Если вы установите размер изображения слишком большим, то в конечном итоге вы столкнётесь с изображениями, которые выглядят зернистыми, размытыми, или слишком маленькими, и потратите трафик для загрузки изображения, которое не будет соответствовать нуждам пользователя. Конечное изображение может также выглядеть искажённым, если вы не сохраните правильное <a href="https://en.wikipedia.org/wiki/Aspect_ratio_(image)">соотношение сторон</a>. Рекомендуется использовать графический редактор для подгонки изображения к нужному размеру, перед вставкой его на вашу вэб-страницу.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Если вам нужно задать размеры вашего изображения, взамен вы можете использовать <a href="/en-US/docs/Learn/CSS">CSS</a>.</p> +</div> + +<h3 id="Заголовок_изображения">Заголовок изображения</h3> + +<p>Как и для <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#Adding_supporting_information_with_%3Ctitle%3E">ссылок</a>, вы можете также добавить атрибут <code>title</code> для изображений, чтобы обеспечить дополнительную подтверждающую информацию если это необходимо. В нашем примере, мы можем это сделать так:</p> + +<pre class="brush: html notranslate"><img src="images/dinosaur.jpg" + alt="The head and torso of a dinosaur skeleton; + it has a large head with long sharp teeth" + width="400" + height="341" + title="A T-Rex on display in the Manchester University Museum"></pre> + +<p>Это даст нам подсказку, также как и в ссылках:</p> + +<p><img alt="The dinosaur image, with a tooltip title on top of it that reads A T-Rex on display at the Manchester University Museum " src="https://mdn.mozillademos.org/files/12708/image-with-title.png" style="display: block; height: 341px; margin: 0px auto; width: 400px;"></p> + +<p>Нет необходимости писать заголовки изображений. Зачастую лучше включить такого рода вспомогательную информацию в основной текст статьи, чем прикреплять её к изображению. Однако, они полезны в некоторых обстоятельствах; например, в галереях изображений когда у вас нет места для их заголовков.</p> + +<h3 id="Активное_обучение_встраивание_изображения">Активное обучение: встраивание изображения</h3> + +<p>Наступила очередь немного поиграть! Этот раздел активного обучения поможет вам выполнить простое упражнение по встраиванию. Вы будете обеспечены простым {{htmlelement("img")}} тэгом; мы хотели бы чтобы вы встроили изображение расположенное по следующей ссылке:</p> + +<p>https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg</p> + +<p>Ранее мы говорили никогда не используйте горячие ссылки на изображения с других серверов, данный случай только для целей обучения, итак мы позволим вам пренебречь этим один разок.</p> + +<p>Мы также хотели бы, чтобы вы:</p> + +<ul> + <li>Добавили любой альтернативный текст, и проверили как это работает внеся ошибку в ссылку на изображение.</li> + <li>Установите правильную <code>ширину</code> и <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">высоту</span></font> (подсказка; это 200px по ширине и 171px по высоте), после поэкспериментируйте с другими значениями, чтобы увидеть какой будет эффект.</li> + <li>Установите <code>заголовок</code> для изображения.</li> +</ul> + +<p>Если вы сделаете ошибку, вы всегда можете сбросить его используя кнопку <em>Reset</em>. Если вы реально не будете понимать что делать, нажмите кнопку <em>Show solution</em>, чтобы увидеть ответ:</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input"> +<img></textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +.input, .output { + width: 90%; + height: 10em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { +textarea.value = '<img src="https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg"\n alt="The head and torso of a dinosaur skeleton; it has a large head with long sharp teeth"\n width="200"\n height="171"\n title="A T-Rex on display in the Manchester University Museum">'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 500) }}</p> + +<h2 id="Придание_изображению_структуры_и_установка_заголовка">Придание изображению структуры и установка заголовка</h2> + +<p>Начиная разговор о заголовках, есть множество путей как вы можете добавить заголовок к своему изображению. Для примера, нет ничего, что может вас остановить сделать это таким образом:</p> + +<pre class="brush: html notranslate"><div class="figure"> + <img src="images/dinosaur.jpg" + alt="The head and torso of a dinosaur skeleton; + it has a large head with long sharp teeth" + width="400" + height="341"> + + <p>A T-Rex on display in the Manchester University Museum.</p> +</div></pre> + +<p>Это нормально. Это содержит всё что вам нужно, и красиво стилизуется с помощью CSS. Но есть проблема: здесь нет ничего, что семантически связывает изображение с его заголовком, и это может вызвать сложности для читателей. Например, когда у вас есть 50 изображений и заголовков, какой заголовок идёт вместе с каким изображением?</p> + +<p>Лучшим решением будет использование HTML5 {{htmlelement("figure")}} и {{htmlelement("figcaption")}} элементов. Они были созданы исключительно для этой цели: предоставление семантического контейнера для иллюстраций, и прозрачного связывания иллюстрации с её заголовком. Наш пример выше, мог быть переписан как то так:</p> + +<pre class="notranslate"><figure> + <img src="images/dinosaur.jpg" + alt="The head and torso of a dinosaur skeleton; + it has a large head with long sharp teeth" + width="400" + height="341"> + + <figcaption>A T-Rex on display in the Manchester University Museum.</figcaption> +</figure></pre> + +<p>{{htmlelement("figcaption")}} элемент говорит браузерам, и вспомогательной технологии, что заголовок описывает содержимое {{htmlelement("figure")}} элемента.</p> + +<div class="note"> +<p><strong>Замечание</strong>: С точки зрения доступности, заголовки и {{htmlattrxref('alt','img')}} имеют различные предназначения. Заголовки помогают даже тем,кто имеет возможность просматривать изображение, тогда как {{htmlattrxref('alt','img')}} предусматривает замену функционала отсутствующего изображения. Таким образом, заголовки и <code>alt</code> не подразумевают под собой одни и те же вещи, потому что оба используются браузером при отсутствии изображения. Попробуйте отключить изображения в своём браузере, чтобы увидеть как это выглядит.</p> +</div> + +<p> Тег <figure> не является изображением. Он представляет собой независимый структурный элемент, который: </p> + +<ul> + <li>Передает смысл компактным, интуитивно понятным способом.</li> + <li>Может использоваться в различных местах страницы.</li> + <li>Предоставляет ценную информацию, поддерживающую основной текст.</li> +</ul> + +<p>Тег <figure> может быть несколькими изображениями, куском кода, аудио, видео, уравнением, таблицей, либо чем-то другим.</p> + +<h3 id="Активное_изучение_создание_<figure>">Активное изучение: создание <figure></h3> + +<p>В этом разделе активного изучения, мы хотели бы, чтобы вы взяли текст из предыдущего раздела активного изучения, и преобразовали его в <figure>:</p> + +<ul> + <li>Оберните его в {{htmlelement("figure")}} элемент.</li> + <li>Скопируйте текст из атрибута <code>title</code>, удалите атрибут <code>title</code>, и вбейте текст в элемент {{htmlelement("figcaption")}}.</li> +</ul> + +<p>В случае допущения ошибки, вы всегда можете набрать код повторно нажав кнопку <em>Reset</em>. Если вы застряли, нажмите кнопку <em>Show solution</em> ,чтобы увидеть ответ:</p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input"> +</textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +.input, .output { + width: 90%; + height: 10em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { +textarea.value = '<figure>\n <img src="https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg"\n alt="The head and torso of a dinosaur skeleton; it has a large head with long sharp teeth"\n width="200"\n height="171">\n <figcaption>A T-Rex on display in the Manchester University Museum</figcaption>\n</figure>'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', 700, 500) }}</p> + +<h2 id="CSS_background-images">CSS background-images</h2> + +<p>Также альтернативой является использование css изображений (или JavaScript, но это совсем другая история). CSS-свойство {{cssxref("background-image")}} , и другие <code>background-*</code> свойства, применяются для контроля размещения фонового изображения. К примеру, чтобы залить фон каждого параграфа страницы, необходимо сделать следующее:</p> + +<pre class="brush: css notranslate">p { + background-image: url("images/dinosaur.jpg"); +}</pre> + +<p>Получившееся в конечном итоге изображение можно легко позиционировать и контролировать, в отличие от его HTML аналога. Так зачем же париться с HTML изображениями? Согласено вышесказанному, фоновые изображения CSS используются только в качестве украшения. Если вы хотите просто добавить что-нибудь красивое на вашу страницу, всё круто. Тем не менее, такого рода изображения не имеют семантического смысла вообще. Они не могут иметь каких-то текстовых эквивалентов, видимых посетителю, и тп. Это звёздное время для HTML!</p> + +<p>Итог: если изображение имеет важность, в контексте содержимого вашей страницы, вам следует использовать HTML изображения. Если же картинка является банальной декорацией, используйте фоновые изображения CSS.</p> + +<div class="note"> +<p><strong>Замечание</strong>: Вы можете узнать больше о <a href="/en-US/docs/Learn/CSS/Styling_boxes/Backgrounds">CSS background images</a> в нашей теме о <a href="/en-US/docs/Learn/CSS">CSS</a>.</p> +</div> + +<p>Вот и всё. Мы детально описали изображения и заголовки. В следующей статье мы перейдём на новый уровень, затронув тему встраивания видео и аудио в веб-страницу.</p> + +<p>{{NextMenu("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding")}}</p> diff --git a/files/ru/learn/html/tables/advanced/index.html b/files/ru/learn/html/tables/advanced/index.html new file mode 100644 index 0000000000..6314fedda1 --- /dev/null +++ b/files/ru/learn/html/tables/advanced/index.html @@ -0,0 +1,455 @@ +--- +title: HTML таблицы продвинутые возможности и доступность +slug: Learn/HTML/Tables/Advanced +translation_of: Learn/HTML/Tables/Advanced +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Tables/Basics", "Learn/HTML/Tables/Structuring_planet_data", "Learn/HTML/Tables")}}</div> + +<p class="summary">Во второй статье этого модуля мы рассматриваем еще несколько продвинутых возможностей в HTML таблицах — такие как заголовок/описание и группировка строк внутри head, body и footer секциях таблицы, а также доступность таблиц для пользователей с ограниченными возможностями.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовый HTML (<a href="/ru/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Изучить более продвинутые возможности HTML таблиц и их доступность.</td> + </tr> + </tbody> +</table> + +<h2 id="Добавление_заголовка_к_таблице_с_помощью_<caption>">Добавление заголовка к таблице с помощью <caption></h2> + +<p>Вы можете добавить заголовок для таблицы установив его в элементе {{htmlelement("caption")}} и этот элемент необходимо поместить внутрь элемента {{htmlelement("table")}}. Причем вам нужно поместить его сразу после открытия тега <code><table></code>.</p> + +<pre class="brush: html notranslate"><table> + <caption>Dinosaurs in the Jurassic period</caption> + + ... +</table></pre> + +<p>Как можно понять из короткого примера выше, заголовок отражает в себе описание контента таблицы. Это полезно для всех читателей просматривающих страницу и желающих получить краткое представление от том полезна ли для них таблица, что особенно важно для слепых пользователей. Вместо того чтобы читать содержимое множества ячеек чтобы понять о чем таблица, он или она могут полагаться на заголовок и принимать решение читать ли таблицу более подробно.</p> + +<p>Заголовок помещают сразу после тега <code><table></code>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Атрибут {{htmlattrxref("summary","table")}} также может быть использован в <code><table></code> элементе предоставляя описание — это также читается скринридерами. Однако мы рекомендуем вместо этого использовать <code><caption></code> элемент, так как <code>summary</code> {{glossary("deprecated")}} в HTML5 спецификации и не может быть прочитан зрячими пользователями (он не отображается на странице).</p> +</div> + +<h3 id="Упражнение_Добавление_заголовка">Упражнение: Добавление заголовка</h3> + +<p>Давайте попробуем это, вернемся к примеру который мы ранее встретили в прошлой статье.</p> + +<ol> + <li>Откройте расписание занятий школьного учителя по языку в конце статьи <a href="/ru/docs/Learn/HTML/Tables/Basics#Active_learning_colgroup_and_col">HTML таблицы основы</a>, или сделайте копию нашего <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/timetable-fixed.html">timetable-fixed.html</a> файла.</li> + <li>Добвьте подходящий заголовок к таблице.</li> + <li>Сохраните свой код и откройте его в браузере, чтобы посмотреть как это выглядит.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Этот пример можно найти на GitHub по ссылке <a href="https://github.com/mdn/learning-area/blob/master/html/tables/advanced/timetable-caption.html">timetable-caption.html</a> (<a href="http://mdn.github.io/learning-area/html/tables/advanced/spending-record-finished.html">живой пример</a>).</p> +</div> + +<h2 id="Добавление_структуры_с_помощью_<thead>_<tfoot>_и_<tbody>">Добавление структуры с помощью <thead>, <tfoot> и <tbody></h2> + +<p>Когда таблицы становятся более сложными по структуре полезно дать им более структурированное определение. Отличный способ сделать это используя {{htmlelement("thead")}}, {{htmlelement("tfoot")}} и {{htmlelement("tbody")}}, которые позволяют вам разметить header, footer и body секции таблицы.</p> + +<p>Эти элементы не создают дополнительной доступности для пользователей со скринридерами и не приводят к какому-то визуальному улучшению при их использовании. Зато они очень полезны при стилизации и разметке, как точки для добавления CSS к вашей таблице. Вот несколько интересных примеров, в случае длинной таблицы вы можете сделать header и footer таблицы повторяемый на каждой печатной странице, или вы можете сделать body таблицы отбражаемое на одной странице и иметь доступ ко всему содержимому контенту прокручивая вверх и вниз.</p> + +<p>Использование:</p> + +<ul> + <li>Элементом <code><thead></code> нужно обернуть часть таблицы которая относится к заголовку — обычно это первая строка содержащая заголовки колонок, но это не обязательно всегда такой случай. Если вы используете {{htmlelement("col")}}/{{htmlelement("colgroup")}} элемент, тогда заголовок должен находиться ниже его.</li> + <li>Элементом <code><tfoot></code> нужно обернуть ту часть, которая относится к footer таблицы — например, это может быть последняя строка в которой отбражаются суммы по столбцам таблицы. Вы можете включить сюда footer таблицы, как и следовало ожидать, или чуть ниже заголовка таблицы (браузер все равно отобразит его внизу таблицы).</li> + <li>Элементом <code><tbody></code> необходимо обернуть остальную часть содержимого таблицы которая не находится в header или footer таблицы. Этот блок располагают ниже заголовка таблицы или иногда footer таблицы, зависит от того какую структуру вы решите использовать (читать выше по тексту).</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: <code><tbody></code> всегда включен в каждой таблице, неявно если не укажете его в коде. Проверьте это, открыв один из предыдущих примеров в котором не используется <code><tbody></code> и посмотрите HTML код в <a href="/ru/docs/Learn/Common_questions/What_are_browser_developer_tools">browser developer tools</a> — вы увидите, что браузер добавил этот тег самостоятельно. Вы могли бы задаться вопросом почему мы должны волноваться о его включениии, но вы должны, потому что это дает больше контроля над структурой таблицы и стилем.</p> +</div> + +<h3 id="Упражнение_Добавление_структуры_таблицы">Упражнение: Добавление структуры таблицы</h3> + +<p>Давайте используем эти новые элементы.</p> + +<ol> + <li>В первую очередь, сделайте копию <a href="https://github.com/mdn/learning-area/blob/master/html/tables/advanced/spending-record.html">spending-record.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/html/tables/advanced/minimal-table.css">minimal-table.css</a> в новой папке.</li> + <li>Попробуйте открыть это в браузере — вы увидите, что все выглядит классно, но могло бы быть лучше. Строка "SUM" которая содержит потраченные суммы кажется находится не в том месте и некоторые детали отсутствуют в коде.</li> + <li>Поместите очевидную строку заголовка внутрь <code><thead></code> элемента, строку "SUM" внутрь <code><tfoot></code> элемента и оставшийся контент внутрь <code><tbody></code> элемента.</li> + <li>Сохраните, презагрузите и вы увидите, что добавление элемента <code><tfoot></code> привело к тому, что строка "SUM" опустилась к нижней части таблицы.</li> + <li>Далее, добавьте атрибут {{htmlattrxref("colspan","td")}}, чтобы ячейка "SUM" занимала первые четыре столбца, таким образом числовое значение "Cost" появится в последнем столбце.</li> + <li>Давайте добавим несколько простых дополнительных стилей к таблице, чтобы дать вам представление насколько эти элементы полезны при использовании CSS. Внутри в <code><head></code> вашего HTML документа вы увидите пустой элемент {{htmlelement("style")}}. Внутри этого элемента добавьте следующие строки CSS кода: + <pre class="brush: css notranslate">tbody { + font-size: 90%; + font-style: italic; +} + +tfoot { + font-weight: bold; +} +</pre> + </li> + <li>Сохраните, обновите и вы увидите результат. Если <code><tbody></code> и <code><tfoot></code> элементы не были установлены, то вам придется писать много сложных селекторов/правил для применения одного и того же стиля.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Мы не ожидаем что сейчас вы полностью поймете CSS. Вы узнаете больше когда пройдете наши CSS курсы (например, <a href="/ru/docs/Learn/CSS/Introduction_to_CSS">Вступление в CSS</a> это хорошее место для начала; у нас также есть статья конкретно о <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Styling_tables">стилизации таблиц</a>).</p> +</div> + +<p>Ваша готовая таблица должна выглядеть примерно так:</p> + +<div class="hidden"> +<h6 id="Hidden_example">Hidden example</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>My spending record</title> + <style> + + html { + font-family: sans-serif; + } + + table { + border-collapse: collapse; + border: 2px solid rgb(200,200,200); + letter-spacing: 1px; + font-size: 0.8rem; + } + + td, th { + border: 1px solid rgb(190,190,190); + padding: 10px 20px; + } + + th { + background-color: rgb(235,235,235); + } + + td { + text-align: center; + } + + tr:nth-child(even) td { + background-color: rgb(250,250,250); + } + + tr:nth-child(odd) td { + background-color: rgb(245,245,245); + } + + caption { + padding: 10px; + } + + tbody { + font-size: 90%; + font-style: italic; + } + + tfoot { + font-weight: bold; + } + </style> + </head> + <body> + <table> + <caption>How I chose to spend my money</caption> + <thead> + <tr> + <th>Purchase</th> + <th>Location</th> + <th>Date</th> + <th>Evaluation</th> + <th>Cost (€)</th> + </tr> + </thead> + <tfoot> + <tr> + <td colspan="4">SUM</td> + <td>118</td> + </tr> + </tfoot> + <tbody> + <tr> + <td>Haircut</td> + <td>Hairdresser</td> + <td>12/09</td> + <td>Great idea</td> + <td>30</td> + </tr> + <tr> + <td>Lasagna</td> + <td>Restaurant</td> + <td>12/09</td> + <td>Regrets</td> + <td>18</td> + </tr> + <tr> + <td>Shoes</td> + <td>Shoeshop</td> + <td>13/09</td> + <td>Big regrets</td> + <td>65</td> + </tr> + <tr> + <td>Toothpaste</td> + <td>Supermarket</td> + <td>13/09</td> + <td>Good</td> + <td>5</td> + </tr> + </tbody> + </table> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_example', '100%', 300) }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: Этот пример можно также найти на GitHub по ссылке <a href="https://github.com/mdn/learning-area/blob/master/html/tables/advanced/spending-record-finished.html">spending-record-finished.html</a> (<a href="http://mdn.github.io/learning-area/html/tables/advanced/spending-record-finished.html">живой пример</a>).</p> +</div> + +<h2 id="Вложенные_таблицы">Вложенные таблицы</h2> + +<p>В одну таблицу вкладывать другую таблицу возможно, если вы используете полную структуру включая элемент <code><table></code>. Это как правило не рекомендуется, так как делает разметку более запутанной и менее доступной для пользователей скринридеров, так в большинстве случаев вы можете просто вставить дополнительные ячейки/строки/столбцы в существующую таблицу. Однако, иногда это необходимо, например, если вы хотите легко импортировать контент из других источников.</p> + +<p>Разметка простой вложенной таблицы:</p> + +<pre class="brush: html notranslate"><table id="table1"> + <tr> + <th>title1</th> + <th>title2</th> + <th>title3</th> + </tr> + <tr> + <td id="nested"> + <table id="table2"> + <tr> + <td>cell1</td> + <td>cell2</td> + <td>cell3</td> + </tr> + </table> + </td> + <td>cell2</td> + <td>cell3</td> + </tr> + <tr> + <td>cell4</td> + <td>cell5</td> + <td>cell6</td> + </tr> +</table></pre> + +<p>Результат которого выглядит примерно так:</p> + +<table id="table1"> + <tbody> + <tr> + <th>title1</th> + <th>title2</th> + <th>title3</th> + </tr> + <tr> + <td id="nested"> + <table id="table2"> + <tbody> + <tr> + <td>cell1</td> + <td>cell2</td> + <td>cell3</td> + </tr> + </tbody> + </table> + </td> + <td>cell2</td> + <td>cell3</td> + </tr> + <tr> + <td>cell4</td> + <td>cell5</td> + <td>cell6</td> + </tr> + </tbody> +</table> + +<h2 id="Таблицы_для_пользователей_с_ограниченными_возможностями">Таблицы для пользователей с ограниченными возможностями</h2> + +<p>Давайте кратко опишем как мы используем данные таблицы. Таблицы могут быть удобным инструментом, который дает нам быстрый доступ к данным и позволяет искать разные значения. Например, быстрого взгляда на таблицу ниже достаточно, чтобы найти сколько колец было продано в Амстердаме в августе 2016. Чтобы понять эту информацию, мы проводим визуальные ассоциации между данными в этой таблице и ее заголовками колонок и/или строк.</p> + +<table> + <caption>Items Sold August 2016</caption> + <tbody> + <tr> + <td></td> + <td></td> + <th colspan="3" scope="colgroup">Clothes</th> + <th colspan="2" scope="colgroup">Accessories</th> + </tr> + <tr> + <td></td> + <td></td> + <th scope="col">Trousers</th> + <th scope="col">Skirts</th> + <th scope="col">Dresses</th> + <th scope="col">Bracelets</th> + <th scope="col">Rings</th> + </tr> + <tr> + <th rowspan="3" scope="rowgroup">Belgium</th> + <th scope="row">Antwerp</th> + <td>56</td> + <td>22</td> + <td>43</td> + <td>72</td> + <td>23</td> + </tr> + <tr> + <th scope="row">Gent</th> + <td>46</td> + <td>18</td> + <td>50</td> + <td>61</td> + <td>15</td> + </tr> + <tr> + <th scope="row">Brussels</th> + <td>51</td> + <td>27</td> + <td>38</td> + <td>69</td> + <td>28</td> + </tr> + <tr> + <th rowspan="2" scope="rowgroup">The Netherlands</th> + <th scope="row">Amsterdam</th> + <td>89</td> + <td>34</td> + <td>69</td> + <td>85</td> + <td>38</td> + </tr> + <tr> + <th scope="row">Utrecht</th> + <td>80</td> + <td>12</td> + <td>43</td> + <td>36</td> + <td>19</td> + </tr> + </tbody> +</table> + +<p>Но что если вы не можете провести эти визуальные ассоциации? Как тогда вы сможете прочитать таблицу выше? Люди с ослабленным зрением часто используют скринридер, который читает им информацию с веб-страницы. Это не проблема когда вы читаете простой текст, но интерпретация таблицы может быть сложной проблемой для слепых людей. Тем не менее, вместе с правильной разметкой мы можем заменить визуальные ассоциации програмными.</p> + +<p>В этой части статьи приводятся дополнительные способы которые делают таблицы более доступными.</p> + +<h3 class="attTitle" id="Использование_заголовков_столбцов_и_строк">Использование заголовков столбцов и строк</h3> + +<p>Скринридеры будут определять все заголовки и использовать их создавая програмные ассоциации между этими заголовками и ячейками к которым они относятся. Сочетание заголовков столбцов и строк будет определять и интерпретировать данные в каждой ячейке так, что пользователи скринридеров могут интерпретировать таблицу также как это делают зрячие пользователи.</p> + +<p>Мы уже разобрали заголовки в предыдущей статье, смотри по ссылке <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Tables/Basics#Adding_headers_with_%3Cth%3E_elements">Добавление заголовков с помощью элемента <th></a>.</p> + +<h3 class="attTitle" id="Атрибут_scope">Атрибут scope</h3> + +<p>Новая тема в этой статье это атрибут {{htmlattrxref("scope","th")}}, который может быть добавлен к элементу <code><th></code> он сообщает скринридеру какие ячейки точно являются заголовками — например, заголовок строки в которой он находится или столбца. Возвращаясь назад к нашему примеру с записями расходов, вы могли однозначно определить заголовки столбцов как здесь:</p> + +<pre class="brush: html notranslate"><thead> + <tr> + <th scope="col">Purchase</th> + <th scope="col">Location</th> + <th scope="col">Date</th> + <th scope="col">Evaluation</th> + <th scope="col">Cost (€)</th> + </tr> +</thead></pre> + +<p>И у каждой строки может быть определен заголовок, как здесь (если мы добавили заголовки строк и заголовки столбцов):</p> + +<pre class="brush: html notranslate"><tr> + <th scope="row">Haircut</th> + <td>Hairdresser</td> + <td>12/09</td> + <td>Great idea</td> + <td>30</td> +</tr></pre> + +<p>Скринридер распознает разметку структурированную таким образом, что позволяют пользователям прочитать весь столбец или строку целиком.</p> + +<p>Атрибут <code>scope</code> имеет еще два возможных значения — <code>colgroup</code> и <code>rowgroup</code>. Они используются для заголовков, которые располагаются вверху ваших столбцов или строк. Если вы посмотрите на таблицу "Items sold..." в начале этого раздела статьи, вы увидите что ячейка с "Clothes" находится над ячейками "Trousers", "Skirts" и "Dresses". Все эти ячейки должны быть помечены как заголовки (<code><th></code>), но "Clothes" заголовок который находится сверху и определяет остальные три подзаголовка. Поэтому "Clothes" должна получить атрибут <code>scope="colgroup"</code>, тогда как другие получат атрибут <code>scope="col"</code>.</p> + +<h3 class="attTitle" id="Атрибуты_id_и_headers">Атрибуты id и headers</h3> + +<p>Альтернатива атрибута <code>scope</code> это использование атрибутов {{htmlattrxref("id")}} и {{htmlattrxref("headers", "td")}} задавая ассоциации между заголовками и ячейками. Этот способ выглядит следующим образом:</p> + +<ol> + <li>Вы устанавливаете уникальный <code>id</code> для каждого<code><th></code> элемента.</li> + <li>Вы устанавливаете атрибут <code>headers</code> для каждого <code><td></code> элемента. Каждый <code>headers</code> атрибут должен содержать список всех <code>id</code> , разделенный пробелами, ко всем <code><th></code> элементам которые действуют как заголовок для этой ячейки.</li> +</ol> + +<p>Это обеспечивает явное определение позиции для каждой ячейки вашей HTML таблицы, определяет заголовки столбцов и строк таблицы. Для того чтобы это работало реально хорошо таблице нужно определить и заголовки столбцов, и заголовки строк.</p> + +<p>Вернемся к нашему примеру с расчетом затрат, его можно переписать следующим образом:</p> + +<pre class="brush: html notranslate"><thead> + <tr> + <th id="purchase">Purchase</th> + <th id="location">Location</th> + <th id="date">Date</th> + <th id="evaluation">Evaluation</th> + <th id="cost">Cost (€)</th> + </tr> +</thead> +<tbody> +<tr> + <th id="haircut">Haircut</th> + <td headers="location haircut">Hairdresser</td> + <td headers="date haircut">12/09</td> + <td headers="evaluation haircut">Great idea</td> + <td headers="cost haircut">30</td> +</tr> + + ... + +</tbody></pre> + +<div class="note"> +<p><strong>Примечание</strong>: Этот метод создания очень точного определения ассоциаций между заголовками и данными в ячейках, но использует <strong>гораздо</strong> больше разметки и оставляет обширное пространство для ошибок. Атрибута <code>scope</code> обычно достаточно для большинства таблиц.</p> +</div> + +<h3 id="Упражнение_играем_со_scope_и_headers">Упражнение: играем со scope и headers</h3> + +<ol> + <li>Для заключительного упражнения мы, вначале создадим копию <a href="https://github.com/mdn/learning-area/blob/master/html/tables/advanced/items-sold.html">items-sold.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/html/tables/advanced/minimal-table.css">minimal-table.css</a> в новой папке.</li> + <li>Теперь попробуем добавить соответствующий атрибут <code>scope</code>, который наиболее соответствует этой таблице.</li> + <li>И наконец попробуем сделать другую копию изначальных файлов, на этот раз делая таблицу более доступной используя атрибуты <code>id</code> и <code>headers</code>.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете проверить как работает последние примеры здесь <a href="https://github.com/mdn/learning-area/blob/master/html/tables/advanced/items-sold-scope.html">items-sold-scope.html</a> (<a href="http://mdn.github.io/learning-area/html/tables/advanced/items-sold-scope.html">also see this live</a>) и <a href="https://github.com/mdn/learning-area/blob/master/html/tables/advanced/items-sold-headers.html">items-sold-headers.html</a> (<a href="http://mdn.github.io/learning-area/html/tables/advanced/items-sold-headers.html">see this live too</a>).</p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>Есть еще некоторые вещи которые можно узнать о HTML таблицах, но мы действительно дали все что нужно на настоящий момент. Дальше вы возможно захотите больше узнать о стилизации HTML таблиц, посмотрите <a href="/en-US/docs/Learn/CSS/Styling_boxes/Styling_tables">Styling Tables</a>.</p> + +<div>{{PreviousMenuNext("Learn/HTML/Tables/Basics", "Learn/HTML/Tables/Structuring_planet_data", "Learn/HTML/Tables")}}</div> + +<div> +<h2 id="В_этом_блоке">В этом блоке</h2> + +<ul> + <li><a href="/ru/docs/Learn/HTML/Tables/Basics">HTML таблицы основы</a></li> + <li><a href="/ru/docs/Learn/HTML/Tables/Advanced">HTML таблицы продвинутые возможности и доступность</a></li> + <li><a href="/en-US/docs/Learn/HTML/Tables/Structuring_planet_data">Structuring planet data</a></li> +</ul> +</div> diff --git a/files/ru/learn/html/tables/basics/index.html b/files/ru/learn/html/tables/basics/index.html new file mode 100644 index 0000000000..a393a80a84 --- /dev/null +++ b/files/ru/learn/html/tables/basics/index.html @@ -0,0 +1,530 @@ +--- +title: HTML таблицы основы +slug: Learn/HTML/Tables/Basics +translation_of: Learn/HTML/Tables/Basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/HTML/Tables/Advanced", "Learn/HTML/Tables")}}</div> + +<p class="summary">Этот раздел познакомит вас с таблицами HTML, представив самые базовые понятия - строки и ячейки, заголовки, слияние строк и столбцов, а также объединение всех ячеек в столбце в целях стилизации.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Начальные условия:</th> + <td>Знание основ HTML (читайте <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML - Introduction to HTML</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Общее знакомство с таблицами HTML.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_таблица">Что такое таблица ?</h2> + +<p>Таблица - это структурированный набор данных, состоящий из строк и столбцов (<strong>табличных данных</strong>). Таблицы позволяют быстро и легко посмотреть значения, показывающие некоторую взаимосвязь между различными типами данных, например - человек и его возраст, или расписание в плавательном бассейне.</p> + +<p><img alt="A sample table showing names and ages of some people - Chris 38, Dennis 45, Sarah 29, Karen 47." src="https://mdn.mozillademos.org/files/14583/numbers-table.png" style="display: block; height: 156px; margin: 0px auto; width: 350px;"></p> + +<p><img alt="A swimming timetable showing a sample data table" src="https://mdn.mozillademos.org/files/14587/swimming-timetable.png" style="display: block; height: 301px; margin: 0px auto; width: 794px;"></p> + +<p>Люди постоянно используют таблицы, причем уже давно, как показывает документ по переписи в США, относящийся к 1800 году:</p> + +<p><img alt="A very old parchment document; the data is not easily readable, but it clearly shows a data table being used." src="https://mdn.mozillademos.org/files/14585/1800-census.jpg" style="display: block; height: 505px; margin: 0px auto; width: 800px;"></p> + +<p>Так что не удивительно, что создатели HTML включили в него средства для структурирования и представления табличных данных в сети.</p> + +<h3 id="Как_работает_таблица">Как работает таблица?</h3> + +<p>Смысл таблицы в том, что она жесткая. Информацию легко интерпретировать, визуально сопоставляя заголовки строк и столбцов. Например, посмотрите на приведенную ниже таблицу и найдите единственное личное местоимение, используемое в третьем лице , с полом ♀, выступающее в качестве объекта в предложении. Ответ можно найти, сопоставив соответствующие заголовки столбцов и строк.</p> + +<table> + <caption>Personal pronouns</caption> + <tbody> + <tr> + <th colspan="3"></th> + <th scope="col">Субъект</th> + <th scope="col">Объект</th> + </tr> + <tr> + <th rowspan="5" scope="rowgroup">Единствен. числ.</th> + <th colspan="2" scope="row">1 Лицо</th> + <td>Я</td> + <td>меня</td> + </tr> + <tr> + <th colspan="2" scope="row">2 Лицо</th> + <td>ты</td> + <td>тебя</td> + </tr> + <tr> + <th rowspan="3" scope="rowgroup">3 Лицо</th> + <th class="symbol" scope="row">♂</th> + <td>он</td> + <td>его</td> + </tr> + <tr> + <th class="symbol" scope="row">♀</th> + <td>она</td> + <td>ее</td> + </tr> + <tr> + <th class="symbol" scope="row">o</th> + <td>оно</td> + <td>его</td> + </tr> + <tr> + <th rowspan="3" scope="rowgroup">Множ.числ.</th> + <th colspan="2" scope="row">1 Лицо</th> + <td>мы</td> + <td>нас</td> + </tr> + <tr> + <th colspan="2" scope="row">2 Лицо</th> + <td>вы</td> + <td>вас</td> + </tr> + <tr> + <th colspan="2" scope="row">2 Лицо</th> + <td>они</td> + <td>их</td> + </tr> + </tbody> +</table> + +<p>Если правильно представить таблицу HTML, интерпретировать ее данные смогут даже люди, имеющие проблемы со зрением.</p> + +<h3 id="Оформление_таблиц">Оформление таблиц</h3> + +<p><a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/personal-pronouns.html">Исходный код HTML (HTML source code)</a> вышеприведенной таблице есть в GitHub; посмотрите его и <a href="http://mdn.github.io/learning-area/html/tables/basic/personal-pronouns.html">живой пример (look at the live example)</a>! Вы заметите, что таблица там выглядит иначе — это потому, что на сайте MDN к этим данным была применена таблица стилей, а приведенный в GitHub пример информации о стиле не имеет.</p> + +<p>Не питайте ложных иллюзий - чтобы эффективно представлять таблицы в веб, необходимо придать им хорошую структуру в HTML и применить к ним таблицы стилей (<a href="/en-US/docs/Learn/CSS">CSS</a>). В данном разделе мы сфокусируемся на HTML, чтобы узнать о том, что касается CSS, вам надо обратиться к статье <a href="/en-US/docs/Learn/CSS/Styling_boxes/Styling_tables">Стилизация таблиц</a>.</p> + +<p>В этом разделе мы не фокусируемся на CSS, но все же дали простейшую таблицу стилей CSS, чтобы сделать таблицы более читабельными. Эту таблицу стилей можно найти <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/minimal-table.css">здесь</a>, можно также использовать <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/blank-template.html">шаблон HTML</a>, применяющий эту стаблицу стилей — вместе они дадут вам хорошую основу для экспериментов с таблицами HTML.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Посмотрите также <a href="http://mdn.github.io/learning-area/html/tables/basic/personal-pronouns-styled.html">таблицу personal_pronouns с примененным к ней стилем</a>, чтобы получить представление о том, как она выглядит.</p> +</div> + +<h3 id="Когда_не_надо_использовать_таблицы_HTML">Когда не надо использовать таблицы HTML?</h3> + +<p>HTML-таблицы следует использовать для табличных данных — это то, для чего они предназначены. К сожалению, многие используют таблицы HTML для оформления веб-страниц, например, одна строка для заголовка, одна для содержимого, одна для сносок, и тому подобное. Подробнее об этом можно узнать в разделе <a href="/ru/docs/Learn/Доступность/HTML#Вёрстка">Вёрстка</a> на <a href="/ru/docs/Learn/Доступность">Начальном обучающем модуле доступности</a>. Это происходило из-за плохой поддержки CSS в разных браузерах; в наше время такое встречается гораздо реже, но иногда все же попадается.</p> + +<p>Короче говоря, использование таблиц в целях оформления вместо <a href="/en-US/docs/Learn/CSS/CSS_layout">методов CSS</a> является плохой идеей по следующим причинам :</p> + +<ol> + <li><strong>Таблицы, используемые для оформления, уменьшают доступность страниц для людей, имеющих проблемы со зрением</strong>: <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">Скринридеры (Screenreaders</a>), используемые ими, интерпретируют HTML-теги и читают содержимое пользователю. Поскольку таблицы не являются средством для представления структуры таблицы, и разметка получается сложнее, чем при использовании методов CSS, скринридеры вводят пользователей в заблуждение.</li> + <li><strong>Таблицы создают путаницу тегов</strong>: Как уже упоминалось, оформление страниц с помощью таблиц дает более сложную структуру разметки, чем специально предназначенные для этого методы. Соответственно, такой код труднее писать, поддерживать и отлаживать.</li> + <li><strong>Таблицы не реагируют автоматически на тип устройства</strong>: У надлежащих контейнеров (например, {{htmlelement("header")}}, {{htmlelement("section")}}, {{htmlelement("article")}}, или {{htmlelement("div")}}) ширина по умолчанию равна 100% от их родительского элемента. У таблиц же размер по умолчанию подстраивается под их содержимое, так что чтобы они одинаково хорошо работали на разных типах устройств необходими принимать дополнительные меры.</li> +</ol> + +<h2 id="Упражение_Ваша_первая_таблица">Упражение: Ваша первая таблица</h2> + +<p>Итак, мы уже достаточно говорили о теории, теперь возьмем конкретный пример и построим таблицу.</p> + +<ol> + <li>Прежде всего, создайте локальную копию <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/blank-template.html">blank-template.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/minimal-table.css">minimal-table.css</a> в новой папке на вашем компьютере.</li> + <li>Содержимое любой таблицы заключается между двумя тегами : <strong><code><a href="/en-US/docs/Web/HTML/Element/table"><table></table></a></code></strong>. Добавьте их в тело HTML.</li> + <li>Самым маленьким контейнером в таблице является ячейка, она создается элементом <strong><code><a href="/en-US/docs/Web/HTML/Element/td"><td></a></code></strong> ('td' - сокращение от 'table data'). Введите внутри тегов table следующее: + <pre class="brush: html notranslate"><td>Hi, I'm your first cell.</td></pre> + </li> + <li>Чтобы получить строку из четырех ячеек, необходимо скопировать эти теги три раза. Обновите содержимое таблицы так, чтобы она выглядела следующим образом: + <pre class="brush: html notranslate"><td>Hi, I'm your first cell.</td> +<td>I'm your second cell.</td> +<td>I'm your third cell.</td> +<td>I'm your fourth cell.</td></pre> + </li> +</ol> + +<p>Как видите, ячейки не располагаются одна под другой, на самом деле они автоматически выравниваются по отношению к другим ячейкам той же строки. Каждый элемент <code><td> </code>создает отдельную ячейку, а все вместе они создают первую строку. Каждая добавленная ячейка удлиняет эту строку.</p> + +<p>Чтобы эта строка перестала расти, а новые ячейки перешли на вторую строку, необходимо использовать элемент <strong><code><a href="/en-US/docs/Web/HTML/Element/tr"><tr></a></code></strong> ('tr' - сокращение от 'table row'). Попробуем, как это получится.</p> + +<ol> + <li>Поместите четыре уже созданных ячейки между тегами <code><tr></code> как здесь показано: + + <pre class="brush: html notranslate"><tr> + <td>Hi, I'm your first cell.</td> + <td>I'm your second cell.</td> + <td>I'm your third cell.</td> + <td>I'm your fourth cell.</td> +</tr></pre> + </li> + <li>Теперь, когда одна строка уже есть, добавим еще — каждую строку надо вложить в дополнительный элемент <code><tr></code>, а каждая ячейка должна быть внутри <code>элемента <td></code>.</li> +</ol> + +<p>В результате получится таблица, которая будет выглядеть примерно так:</p> + +<table> + <tbody> + <tr> + <td>Hi, I'm your first cell.</td> + <td>I'm your second cell.</td> + <td>I'm your third cell.</td> + <td>I'm your fourth cell.</td> + </tr> + <tr> + <td>Second row, first cell.</td> + <td>Cell 2.</td> + <td>Cell 3.</td> + <td>Cell 4.</td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Примечание</strong>: Этот пример можно также найти на GitHub под названием <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/simple-table.html">simple-table.html</a> (<a href="http://mdn.github.io/learning-area/html/tables/basic/simple-table.html">see it live also</a>).</p> +</div> + +<h2 id="Добавление_заголовков_с_помощью_элементов_<th>">Добавление заголовков с помощью элементов <th></h2> + +<p>Теперь обратимся к табличным заголовкам — особым ячейкам, которые идут вначале строки или столбца и определяют тип данных, которые содержит данная строка или столбец (как "Person" и "Age" в первом примере данной статьи). Чтобы показать, для чего они нужны, возьмем следующий пример. Сначала исходный код:</p> + +<pre class="brush: html notranslate"><table> + <tr> + <td>&nbsp;</td> + <td>Knocky</td> + <td>Flor</td> + <td>Ella</td> + <td>Juan</td> + </tr> + <tr> + <td>Breed</td> + <td>Jack Russell</td> + <td>Poodle</td> + <td>Streetdog</td> + <td>Cocker Spaniel</td> + </tr> + <tr> + <td>Age</td> + <td>16</td> + <td>9</td> + <td>10</td> + <td>5</td> + </tr> + <tr> + <td>Owner</td> + <td>Mother-in-law</td> + <td>Me</td> + <td>Me</td> + <td>Sister-in-law</td> + </tr> + <tr> + <td>Eating Habits</td> + <td>Eats everyone's leftovers</td> + <td>Nibbles at food</td> + <td>Hearty eater</td> + <td>Will eat till he explodes</td> + </tr> +</table></pre> + +<p>Теперь как выглядит таблица:</p> + +<table> + <tbody> + <tr> + <td></td> + <td>Knocky</td> + <td>Flor</td> + <td>Ella</td> + <td>Juan</td> + </tr> + <tr> + <td>Breed</td> + <td>Jack Russell</td> + <td>Poodle</td> + <td>Streetdog</td> + <td>Cocker Spaniel</td> + </tr> + <tr> + <td>Age</td> + <td>16</td> + <td>9</td> + <td>10</td> + <td>5</td> + </tr> + <tr> + <td>Owner</td> + <td>Mother-in-law</td> + <td>Me</td> + <td>Me</td> + <td>Sister-in-law</td> + </tr> + <tr> + <td>Eating Habits</td> + <td>Eats everyone's leftovers</td> + <td>Nibbles at food</td> + <td>Hearty eater</td> + <td>Will eat till he explodes</td> + </tr> + </tbody> +</table> + +<p>Проблема в том, что, хотя вы и можете представить, о чем идет речь, ссылаться на эти данные не так легко, как хотелось бы. Лучше, чтобы строка и столбец с заголовками как-то выделялись.</p> + +<h3 id="Упражнение_заголовки">Упражнение: заголовки</h3> + +<p>Попробуем улучшить эту таблицу.</p> + +<ol> + <li>Сначала создайте локальную копию <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/dogs-table.html">dogs-table.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/minimal-table.css">minimal-table.css</a> в новой папке на вашем компьютере. HTML содержит пример Dogs, который вы уже видели выше.</li> + <li>Чтобы опознавать заголовки таблицы в качестве заголовков, визуально и семантически, можно использовать элемент <strong><code><a href="/en-US/docs/Web/HTML/Element/th"><th></a></code></strong> ('th' сокращение от 'table header'). Он работает в точности как <code><td></code>, за исключением того, что обозначает заголовок, а не обычную ячейку. Замените в своем HTML все элементы <code><td></code>, содержащие заголовки, на элементы <code><th></code>.</li> + <li>Сохраните HTML и загрузите его в браузер, и вы увидите, что заголовки теперь выглядят как заголовки.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Законченный пример можно найти на <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/dogs-table-fixed.html">dogs-table-fixed.html</a> в GitHub (<a href="http://mdn.github.io/learning-area/html/tables/basic/dogs-table-fixed.html">посмотрите живой пример</a>).</p> +</div> + +<h3 id="Для_чего_нужны_заголовки">Для чего нужны заголовки?</h3> + +<p>Мы уже частично ответили на этот вопрос — когда заголовки выделяются, легче искать данные и таблица выглядит лучше.</p> + +<div class="note"> +<p><strong>Примечание</strong>: По умолчанию к заголовкам таблицы применяется определенный стиль — они выделены жирным шрифтом и выровнены по центру, даже если вы не задавали для них стиль специально.</p> +</div> + +<p>Заголовки дают дополнительное преимущество — вместе с атрибутом <code>scope</code> (который мы будем изучать в следующей статье) они помогают улучшить связь каждого заголовка со всеми данными строки или столбца одновременно, что довольно полезно</p> + +<h2 id="Слияние_нескольких_строк_или_столбцов">Слияние нескольких строк или столбцов</h2> + +<p>Иногда нам нужно, чтобы ячейки распротранялись на несколько строк или столбцов. Возьмем простой пример, в котором приведены имена животных. Иногда бывает нужно вывести имена людей рядом с именами животных. А иногда это не требуется, и тогда мы хотим, чтобы имя животного занимало всю ширину.</p> + +<p>Исходная разметка выглядит так:</p> + +<pre class="brush: html notranslate"><table> + <tr> + <th>Animals</th> + </tr> + <tr> + <th>Hippopotamus</th> + </tr> + <tr> + <th>Horse</th> + <td>Mare</td> + </tr> + <tr> + <td>Stallion</td> + </tr> + <tr> + <th>Crocodile</th> + </tr> + <tr> + <th>Chicken</th> + <td>Cock</td> + </tr> + <tr> + <td>Rooster</td> + </tr> +</table></pre> + +<p>Но результат не такой, как хотелось бы:</p> + +<table> + <tbody> + <tr> + <th>Animals</th> + </tr> + <tr> + <th>Hippopotamus</th> + </tr> + <tr> + <th>Horse</th> + <td>Mare</td> + </tr> + <tr> + <td>Stallion</td> + </tr> + <tr> + <th>Crocodile</th> + </tr> + <tr> + <th>Chicken</th> + <td>Cock</td> + </tr> + <tr> + <td>Rooster</td> + </tr> + </tbody> +</table> + +<p>Нужно, чтобы "Animals", "Hippopotamus" и "Crocodile" распространялись на два столбца, а "Horse" и "Chicken" - на две строки. К счастью, табличные заголовки и ячейки имеют атрибуты <code>colspan</code> <code>и rowspan</code>, которые позволяют это сделать. Оба принимают безразмерное числовое значение, которое равно количеству строк или столбцов, на которые должны распространяться ячейки. Например, <code>colspan="2"</code> распространяет ячейку на два столбца.</p> + +<p>Воспользуемся <code>colspan</code> и <code>rowspan</code> чтобы улучшить таблицу.</p> + +<ol> + <li>Сначала создайте локальную копию <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/animals-table.html">animals-table.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/minimal-table.css">minimal-table.css</a> в новой папке на вашем компьютере. Код HTML содержит пример с животными, который вы уже видели выше.</li> + <li>Затем используйте атрибут <code>colspan</code> чтобы распространить "Animals", "Hippopotamus" и "Crocodile" на два столбца.</li> + <li>Наконец, используйте атрибут <code>rowspan</code> чтобы распространить "Horse" и "Chicken" на две строки.</li> + <li>Сохраните код и откройте его в браузере, чтобы увидеть улучшения.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Законченный пример можно посмотреть в <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/animals-table-fixed.html">animals-table-fixed.html</a> на GitHub (<a href="http://mdn.github.io/learning-area/html/tables/basic/animals-table-fixed.html">живой пример</a>).</p> +</div> + +<table id="tabular" style="background-color: white;"> +</table> + +<h2 id="Стилизация_столбцов">Стилизация столбцов</h2> + +<p>И последняя возможность, о которой рассказывается в данной статье. HTML позволяет указать, какой стиль нужно применять к целому столбцу данных сразу — для этого применяют элементы <strong><code><a href="/en-US/docs/Web/HTML/Element/col"><col></a></code></strong> и <strong><code><a href="/en-US/docs/Web/HTML/Element/colgroup"><colgroup></a></code></strong>. Их ввели, поскольку задавать стиль для каждой ячейки в отдельности или использовать сложный селектор вроде {{cssxref(":nth-child()")}} было бы слишком утомительно.</p> + +<p>Возьмем простой пример:</p> + +<pre class="brush: html notranslate"><table> + <tr> + <th>Data 1</th> + <th style="background-color: yellow">Data 2</th> + </tr> + <tr> + <td>Calcutta</td> + <td style="background-color: yellow">Orange</td> + </tr> + <tr> + <td>Robots</td> + <td style="background-color: yellow">Jazz</td> + </tr> +</table></pre> + +<p>Что дает нам:</p> + +<table> + <tbody> + <tr> + <th>Data 1</th> + <th style="background-color: yellow;">Data 2</th> + </tr> + <tr> + <td>Calcutta</td> + <td style="background-color: yellow;">Orange</td> + </tr> + <tr> + <td>Robots</td> + <td style="background-color: yellow;">Jazz</td> + </tr> + </tbody> +</table> + +<p>Он не идеален, поскольку нам пришлось повторить информацию о стиле для всех трех ячеек в столбце (в реальном проекте, возможно, придется вводить <code>class</code> на всех трех и вводит правило в таблице стилей). Вместо этого, мы можем задать информацию один раз, в элементе <code><col></code>. <code>Элемент <col></code> задается в контейнере <code><colgroup></code> сразу же за открывающим тегом <code><table></code>. Эффект, который мы видели выше, можно задать так:</p> + +<pre class="brush: html notranslate"><table> + <colgroup> + <col> + <col style="background-color: yellow"> + </colgroup> + <tr> + <th>Data 1</th> + <th>Data 2</th> + </tr> + <tr> + <td>Calcutta</td> + <td>Orange</td> + </tr> + <tr> + <td>Robots</td> + <td>Jazz</td> + </tr> +</table></pre> + +<p>Мы определяем два "стилизующих столбца". Мы не применяем стиль к первому столбцу, но пустой элемент <code><col></code> ввести необходимо — иначе к первому столбцу не будет применен стиль.</p> + +<p>Если бы мы хотели применить информацию о стиле к обоим столбцам, мы могли бы просто ввести один элемент <code><col></code> с атрибутом span, таким образом:</p> + +<pre class="brush: html notranslate"><colgroup> + <col style="background-color: yellow" span="2"> +</colgroup></pre> + +<p>Подобно <code>colspan</code> и <code>rowspan</code>, <code>span</code> принимает безразмерное числовое значение, указывающее, к какому количеству столбцов нужно применить данный стиль.</p> + +<h3 id="Упражнение_colgroup_и_col">Упражнение: colgroup и col</h3> + +<p>Теперь попробуйте сами.</p> + +<p>Ниже приведена таблица уроков по языкам. В пятницу (Friday) новый класс целый день изучает голландский (Dutch), кроме того, во вторник (Tuesday) и четверг (Thursdays) есть занятия по немецкому (German). Учительница хочет выделить столбцы, соответствующие дням, когда она преподает.</p> + +<table> + <colgroup> + <col> + <col style="background-color: #97DB9A;"> + <col style="width: 42px;"> + <col style="background-color: #97DB9A;"> + <col style="background-color: #DCC48E; border: 4px solid #C1437A;"> + <col style="width: 42px;"> + </colgroup> + <tbody> + <tr> + <td></td> + <th>Mon</th> + <th>Tues</th> + <th>Wed</th> + <th>Thurs</th> + <th>Fri</th> + <th>Sat</th> + <th>Sun</th> + </tr> + <tr> + <th>1st period</th> + <td>English</td> + <td></td> + <td></td> + <td>German</td> + <td>Dutch</td> + <td></td> + <td></td> + </tr> + <tr> + <th>2nd period</th> + <td>English</td> + <td>English</td> + <td></td> + <td>German</td> + <td>Dutch</td> + <td></td> + <td></td> + </tr> + <tr> + <th>3rd period</th> + <td></td> + <td>German</td> + <td></td> + <td>German</td> + <td>Dutch</td> + <td></td> + <td></td> + </tr> + <tr> + <th>4th period</th> + <td></td> + <td>English</td> + <td></td> + <td>English</td> + <td>Dutch</td> + <td></td> + <td></td> + </tr> + </tbody> +</table> + +<p>Заново создайте таблицу, проделав указанные ниже действия.</p> + +<ol> + <li>Сначала создайте локальную копию файла <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/timetable.html">timetable.html</a> в новой папке на вашем копьютере. Код HTML содержит таблицу, которую вы уже видели выше, но без информации о стиле.</li> + <li>Добавьте элемент <code><colgroup></code> вверху таблицы, сразу же под тегом <code><table></code>, куда вы сможете вставлять элементы <code><col></code>.</li> + <li>Первые два столбца надо оставить без стиля..</li> + <li>Добавьте цвет фона для третьего столбца. Значением атрибута <code>style</code> будет <code>background-color:#97DB9A;</code></li> + <li>Задайте ширину для четвертого столбца. <code>Значением атрибута style</code> будет <code>width: 42px;</code></li> + <li>Добавьте цвет фона для пятого столбца. Значением атрибута <code>style</code> будет <code>background-color: #97DB9A;</code></li> + <li>Добавьте другой цвет фона и границу для шестого столбца, чтобы показать, что это особый день и она ведет новый класс. Значениями атрибута <code>style</code> будут: <code>background-color:#DCC48E; border:4px solid #C1437A;</code></li> + <li>Последние два дня выходные; значением атрибута style <code>будет width: 42px;</code></li> +</ol> + +<p>Посмотрите, что у вас получилось. Если застрянете, или захотите себя проверить, можете посмотреть нашу версию в <a href="https://github.com/mdn/learning-area/blob/master/html/tables/basic/timetable-fixed.html">timetable-fixed.html</a> (<a href="http://mdn.github.io/learning-area/html/tables/basic/timetable-fixed.html">посмотрите живой пример</a>).</p> + +<h2 id="Итог">Итог</h2> + +<p>Здесь приведены практически все базовые сведения о таблицах HTML. В следующей статье вы получите более продвинутые сведения на эту тему.</p> + +<div>{{NextMenu("Learn/HTML/Tables/Advanced", "Learn/HTML/Tables")}}</div> diff --git a/files/ru/learn/html/tables/index.html b/files/ru/learn/html/tables/index.html new file mode 100644 index 0000000000..609f1b36fe --- /dev/null +++ b/files/ru/learn/html/tables/index.html @@ -0,0 +1,34 @@ +--- +title: HTML таблицы +slug: Learn/HTML/Tables +translation_of: Learn/HTML/Tables +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Структурирование табличных данных является в HTML самой обычной задачей, для этой цели есть множество элементов и атрибутов. С добавлением таблиц стилей (<a href="/ru-RU/docs/Learn/CSS">CSS</a>) HTML с легкостью позволяет выводить в веб различные таблицы, например, расписание школьных уроков, график посещения бассейна, или статистические данные о ваших любимых динозаврах или футбольных командах. В данном разделе вы узнаете все, что вам потребуется для структурирования табличных данных с помощью HTML.</p> + +<h2 id="Необходимые_условия">Необходимые условия</h2> + +<p>Прежде чем приступить к данному разделу, вы должны ознакомиться с основами HTML — смотрите <a href="/ru-RU/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML (Introduction to HTML</a>).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Если компьютер/планшет/другое устройство, на котором вы работаете, не позволяет вам самостоятельно создавать файлы, то приводимые здесь примеры кода можно посмотреть в онлайновых программах для кодирования, например <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<p>Данный раздел содержит следующие статьи:</p> + +<dl> + <dt><a href="/ru-RU/docs/Learn/HTML/Tables/Basics">Основы работы с таблицами HTML</a></dt> + <dd>Эта статья поможет вам начать работу с таблицами HTML, познакомив с самыми базовыми понятиями - строками и ячейками, заголовками, слиянием строк или столбцов, а также с тем, как объединять все ячейки столбца для оформительских целей.</dd> + <dt><a href="/ru/docs/Learn/HTML/Tables/Advanced">Продвинутые возможности таблиц HTML и доступность</a></dt> + <dd>Во второй статье данного раздела мы рассмотрим более продвинутые возможности таблиц HTML — заголовки/подписи, а также разбиение строк таблицы на три части: "голову" (head), "тело" (body) и нижний колонтитул (footer) — а также исследуем, как можно представлять таблицы для людей, имеющих проблемы со зрением.</dd> +</dl> + +<h2 id="Проверка_знаний">Проверка знаний</h2> + +<dl> + <dt><a href="/ru-RU/docs/Learn/HTML/Tables/Structuring_planet_data">Структурирование данных о планетах</a></dt> + <dd>Для проверки усвоенных знаний мы дадим вам ряд данных, касающихся планет солнечной системы, чтобы представить их в виде таблицы HTML.</dd> +</dl> diff --git a/files/ru/learn/html/tables/structuring_planet_data/index.html b/files/ru/learn/html/tables/structuring_planet_data/index.html new file mode 100644 index 0000000000..ef5ff547c0 --- /dev/null +++ b/files/ru/learn/html/tables/structuring_planet_data/index.html @@ -0,0 +1,96 @@ +--- +title: 'Аттестация: Структурирование данных о планетах' +slug: Learn/HTML/Tables/Structuring_planet_data +tags: + - HTML + - Начинающим + - таблицы +translation_of: Learn/HTML/Tables/Structuring_planet_data +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/HTML/Tables/Advanced", "Learn/HTML/Tables")}}</div> + +<p class="summary">В нашей аттестации, мы предоставим вам некоторые данные о планетах солнечной системы, и убедим вас <span class="tlid-translation translation" lang="ru"><span title="">структурировать их в </span></span>HTML таблицу.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td>Перед тем, как попытаться пройти эту аттестацию, вы должны были уже разобрать все статьи в этом модуле.</td> + </tr> + <tr> + <th scope="row">Цели:</th> + <td>Проверить знания о HTML таблицах и связанными с ними возможностями.</td> + </tr> + </tbody> +</table> + +<h2 id="Отправная_точка">Отправная точка</h2> + +<p>Для того, чтобы начать аттестацию, скопируйте <a href="https://github.com/mdn/learning-area/blob/master/html/tables/assessment-start/blank-template.html">blank-template.html</a>, <a href="https://github.com/mdn/learning-area/blob/master/html/tables/assessment-start/minimal-table.css">minimal-table.css</a>, и <a href="https://github.com/mdn/learning-area/blob/master/html/tables/assessment-start/planets-data.txt">planets-data.txt</a> в новую директорию на вашем компьютере.</p> + +<div class="note"> +<p><strong>Примечание</strong>: В качестве альтарнативы, вы можете использовать такие сайты, как <a class="external external-icon" href="https://jsbin.com/">JSBin</a> или <a href="https://glitch.com/">Glitch</a>, чтобы пройти аттестацию. Вы можете вставлять HTML, CSS и JavaScript в один из этих онлайн редакторов. Если используемый вами онлайн редактор не имеет отдельных JavaScript/CSS панелей, не стесняйтесь вставлять <code><script></code>/<code><style></code> элементы в HTML страницу.</p> +</div> + +<h2 id="Краткое_описание_проекта">Краткое описание проекта</h2> + +<p>Вы работаете в школе. В настоящее время ваши ученики изучают планеты солнечной системы, и вы хотите обеспечить их наглядным пособием для поиска фактов и данных о планетах. Таблица HTML была бы идеальным вариантом — вам необходимо взять необработанные данные, которые у вас есть, и превратить их в таблицу, следуя нижеприведенным инструкциям.</p> + +<p>Готовая таблица должна выглядить так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14609/assessment-table.png" style="display: block; margin: 0 auto;"></p> + +<p>Вы можете также<a href="https://mdn.github.io/learning-area/html/tables/assessment-finished/planets-data.html"> посмотреть на готовый вариант здесь</a> (не смотрите на исходный код — не жульничайте!).</p> + +<ul> +</ul> + +<h2 id="Шаги_для_завершения">Шаги для завершения</h2> + +<p>Следующие шаги опистывают что вам нужно сделать, чтобы завершить пример таблицы. Все данные, что вам нужны находятся в файле <code>planets-data.txt</code>. Если у вас возникли проблемы с визуализацией данных, посмотрите приведенный выше пример или попробуйте нарисовать диаграмму.</p> + +<ol> + <li>Откройте вашу копию <code>blank-template.html</code> , и запустите таблицу, предоставив ей внешний контейнер, заголовок и тело таблицы. Вам не нужен нижний колонтинул (footer) для этого примера.</li> + <li>Добавьте предоставленную подпись к вашей таблице ("Сaption" в конце <code>planets-data.txt</code>).</li> + <li>Добавьте строку в заголовок таблицы, содержащуюю все заголовки столбцов.</li> + <li>Создайте все строки содержимого внутри тела таблицы, помня, что все заголовки строк должны быть <em>семантически</em>.</li> + <li>Убедитесь, что весь контент помещен в нужные ячейки - в исходных данных каждая строка данных о планете отображается рядом со связанной с ней планетой.</li> + <li>Добавьте атрибуты, чтобы заголовки строк и столбцов были однозначно связаны со строками, столбцами или группами строк, для которых они выступают в качестве заголовков.</li> + <li>Добавьте черную рамку вокруг столбца, который содержит все заголовки строк с именами планет.</li> +</ol> + +<h2 id="Подсказки_и_советы">Подсказки и советы</h2> + +<ul> + <li>Первая ячейка строки заголовка должна быть пустой, и занимать два столбца.</li> + <li>Заголовки групповых строк (например, <em>Jovian planets</em>), которые расположены слева от заголовков строк с именами планет (например, <em>Saturn</em>), немного сложно разобрать - необходимо убедиться, что каждый из них охватывает правильное количество строк и столбцов.</li> + <li>Один из способов связать заголовки с их строками / столбцами намного проще, чем другой.</li> +</ul> + +<h2 id="Аттестация_или_дальнейшая_помощь">Аттестация или дальнейшая помощь</h2> + +<p>Если вы хотите, чтобы ваша работа была оценена, или вы застряли и хотите обратиться за помощью:</p> + +<ol> + <li>Разместите свою работу в онлайн-редакторе, таком как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle </a>или <a href="https://glitch.com/">Glitch</a>.</li> + <li>Напишите сообщение с просьбой об оценке и/или помощи в <a href="https://discourse.mozilla.org/c/mdn/learn">разделе обучения на форуме MDN Discourse</a>. Ваш пост должен включать: + <ul> + <li>Описательный заголовок, такой как «Требуется оценка для структурирования данных планеты».</li> + <li>Детали того, что вы уже пробовали, и что вы хотели бы, чтобы мы сделали, например, если вы застряли и нуждаетесь в помощи, или хотите оценить свою работу.</li> + <li>Ссылка на пример, который вы хотите оценить или в котором вам нужна помощь, в онлайн-редакторе (как упомянуто в шаге 1 выше). Это хорошая практика в решении проблем - очень сложно помочь кому-то с проблемой кода, если вы не видите его код.</li> + <li>Ссылка на актуальную задачу или страницу оценки, чтобы мы могли найти вопрос, с которым вам нужно помочь.</li> + </ul> + </li> +</ol> + +<p>{{PreviousMenu("Learn/HTML/Tables/Advanced", "Learn/HTML/Tables")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Tables/Basics">HTML table basics</a></li> + <li><a href="/en-US/docs/Learn/HTML/Tables/Advanced">HTML table advanced features and accessibility</a></li> + <li><a href="/en-US/docs/Learn/HTML/Tables/Structuring_planet_data">Structuring planet data</a></li> +</ul> diff --git a/files/ru/learn/html/введение_в_html/advanced_text_formatting/index.html b/files/ru/learn/html/введение_в_html/advanced_text_formatting/index.html new file mode 100644 index 0000000000..fdebae6e91 --- /dev/null +++ b/files/ru/learn/html/введение_в_html/advanced_text_formatting/index.html @@ -0,0 +1,679 @@ +--- +title: Углубленное форматирование текста +slug: Learn/HTML/Введение_в_HTML/Advanced_text_formatting +tags: + - Beginner + - Guide + - HTML + - Начинающий + - Руководство +translation_of: Learn/HTML/Introduction_to_HTML/Advanced_text_formatting +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">В HTML для форматирования текста есть много других элементов, не рассмотренных в статье <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a>. Элементы, описанные в этой статье, не так часто используются, но все же полезны для понимания (и это всё ещё будет не полный список элементов). Здесь вы узнаете о цитатах, списках описания, компьютерном коде и другом виде текстовых элементов, подстрочном и надстрочном тексте, контактной информации и других типах текста.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные требования:</th> + <td> + <p>Базовое знакомство с HTML, раскрытое в <br> + <a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a>. Форматирование текста с помощью HTML, описанное в статье <a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a>.</p> + </td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Научиться использовать менее известные HTML-элементы для продвинутой семантической разметки текста.</td> + </tr> + </tbody> +</table> + +<h2 id="Списки_описания">Списки описания</h2> + +<p>В основах HTML-текста мы рассмотрели, как <a href="HTML_text_fundamentals#Lists">пометить привычные типы списков</a> в HTML, но мы не упоминали о третьем типе списка, с которым вы иногда сталкиваетесь, — списке описания. Цель этих списков состоит в том, чтобы пометить набор элементов и их связанных описаний, таких как термины и определения или вопросы и ответы.</p> + +<p>Давайте рассмотрим пример набора терминов и определений:</p> + +<pre class="notranslate">Солилоквий +Драматическая речь, в которой персонаж разговаривает сам с собой, передавая свои ощущения и мысли публике (но не другим персонажам). +Монолог +Драматическая речь, в которой персонаж передаёт свои мысли публике и некоторым персонажам. +Ремарка +В драме: речь персонажа, при которой делается замечание с юмористическим или драматическим эффектом; чаще всего это чувства, мысли или предпосылки к чему-либо.</pre> + +<p>В списках описания используется иная оболочка, чем в других типах списков — {{htmlelement ("dl")}} (от <em>description list</em>); кроме того, каждый термин завёрнут в элемент {{htmlelement ("dt")}} (<em>description term</em> — термин для описания) и каждое определение завёрнуто в элемент {{htmlelement ("dd")}} (<em>description definition</em> — описание определения).</p> + +<p>Закончим разметку нашего примера:</p> + +<pre class="brush: html notranslate"><dl> + <dt>Солилоквий</dt> + <dd>Драматическая речь, в которой персонаж разговаривает сам с собой, передавая свои ощущения и мысли публике (но не другим персонажам).</dd> + <dt>Монолог</dt> + <dd>Драматическая речь, в которой персонаж передаёт свои мысли публике и некоторым персонажам.</dd> + <dt>Ремарка</dt> + <dd>В драме: речь персонажа, при которой делается замечание с юмористическим или драматическим эффектом; чаще всего это чувства, мысли или предпосылки к чему-либо.</dd> +</dl></pre> + +<p>В стилях браузера по умолчанию будут отображаться списки описания с некоторыми отступами от терминов. Стили, определённые на MDN, довольно близки к этому соглашению, но также вносят некоторые изменения:</p> + +<dl> + <dt>Солилоквий</dt> + <dd>Драматическая речь, в которой персонаж разговаривает сам с собой, передавая свои ощущения и мысли публике (но не другим персонажам).</dd> + <dt>Монолог</dt> + <dd>Драматическая речь, в которой персонаж передаёт свои мысли публике и некоторым персонажам.</dd> + <dt>Ремарка</dt> + <dd>В драме: речь персонажа, при которой делается замечание с юмористическим или драматическим эффектом; чаще всего это чувства, мысли или предпосылки к чему-либо.</dd> +</dl> + +<p>Заметьте, что разрешено давать одному элементу несколько описаний:</p> + +<dl> + <dt>Ремарка</dt> + <dd>В драме: речь персонажа, при которой делается замечание с юмористическим или драматическим эффектом; чаще всего это чувства, мысли или предпосылки к чему-либо.</dd> + <dd>В письменности: отметка, примечание (<em>устар.</em>).</dd> +</dl> + +<h3 id="Активное_обучение_разметка_набора_определений">Активное обучение: разметка набора определений</h3> + +<p>Пришло время попробовать свои силы в списках описания: добавьте элементы в исходный текст в поле Ввод, чтобы он отображался как список описания в поле <em>Вывод</em>. Вы можете попробовать использовать свои собственные термины и описания, если хотите.</p> + +<p>Если Вы ошиблись, то всегда можете начать снова, воспользовавшись кнопкой <em>Сбросить</em>. Если упражнение вызывает у Вас затруднения, то нажмите кнопку <em>Показать решение</em>, чтобы увидеть правильный ответ.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Результат</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label">Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).</p> + +<textarea id="code" class="input" style="min-height: 100px; width: 95%"> +Бекон +Скрепляет мир вокруг. +Яйца +Скрепляют пироги вокруг. +Кофе +Рычаг, движущий планетами. +Светло-коричневого цвета.</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<dl>\n <dt>Бекон</dt>\n <dd>Скрепляет мир вокруг.</dd>\n <dt>Яйца</dt>\n <dd>Скрепляют пироги вокруг.</dd>\n <dt>Кофе</dt>\n <dd>Рычаг, движущий планетами.</dd>\n <dd>Светло-коричневого цвета.</dd>\n</dl>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 350, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Цитаты">Цитаты</h2> + +<p>HTML также имеет функции, доступные для маркировки цитат; какой элемент вы используете, зависит от того, маркируете ли вы блочную или строчную цитату.</p> + +<h3 id="Блочные_цитаты">Блочные цитаты</h3> + +<p>Если часть содержимого уровня блока (будь то абзац, несколько абзацев, список и т. д.) цитируется из другого источника, вы должны обернуть ее внутри элемента {{htmlelement ("blockquote")}}, чтобы обозначить это, и указать URL-адрес, указывающий на источник цитаты, внутри атрибута {{htmlattrxref ("cite", "blockquote")}}.</p> + +<p class="syntaxbox">Например, следующая разметка берется из страницы элемента MDN <code><strong><blockquote></strong></code>:</p> + +<pre class="brush: html notranslate"><p><strong>HTML-элемент<code>&lt;blockquote&gt;</code></strong> (от англ. <em>HTML Block +Quotation Element</em>) указывает на то, что заключённый в нём текст является развёрнутой цитатой.</p></pre> + +<p>Чтобы превратить её в блочную цитату, мы просто делаем следующее:</p> + +<pre class="brush: html notranslate"><blockquote cite="https://developer.mozilla.org/ru/docs/Web/HTML/Element/blockquote"> + <p><strong>HTML-элемент<code>&lt;blockquote&gt;</code></strong> (от англ. <em>HTML Block Quotation Element</em>) указывает на то, что заключённый в нём текст является развёрнутой цитатой.</p> +</blockquote></pre> + +<p>Стиль браузера по умолчанию будет отображать это как абзац с отступом, как индикатор того, что это цитата; абзац над цитатой призван продемонстрировать это. MDN делает это, но также добавляет некоторый дополнительный стиль:</p> + +<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"> +<p><strong>HTML-элемент <blockquote> </strong>(от англ. <em>Block Quotation</em>) указывает на то, что заключённый в нём текст является развёрнутой цитатой.</p> +</blockquote> + +<h3 id="Строчные_цитаты">Строчные цитаты</h3> + +<p>Строчные цитаты работают точно так же, за исключением того, что они используют элемент {{htmlelement ("q")}}. Например, следующий кусочек разметки содержит цитату из страницы <code><q></code> MDN:</p> + +<pre class="brush: html notranslate"><p>Элемент цитирования — <code>&lt;q&gt;</code> — <q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">предназначен +для коротких цитат, не требующих прерывания абзаца</q>.</p></pre> + +<p>Стиль браузера по умолчанию будет отображать это как обычный текст, заключенный в кавычки для обозначения цитаты, например:</p> + +<p>Элемент цитирования — <code><q></code> — <q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">предназначен для коротких цитат, не требующих прерывания абзаца</q>.</p> + +<h3 id="Цитирование">Цитирование</h3> + +<p>Содержание атрибута {{htmlattrxref ("cite", "blockquote")}} выглядит полезным, но, к сожалению, браузерам, программам чтения с экрана и т. д. оно на самом деле мало чем помогает. Невозможно заставить браузер отображать содержимое атрибута <code><cite></code> без написания собственного решения с использованием JavaScript или CSS. Если вы хотите, чтобы источник цитирования был доступен на странице, лучший способ его разметки - поместить элемент {{htmlelement ("cite")}} рядом с элементом цитаты (или внутри него). Это действительно будет означать то, что имя источника цитаты — то есть имя книги или имя человека, которое произвело цитату, — будет включено в текст. Нет причин, по которым вы не могли бы связать текст внутри <code><cite></code> с источником цитаты:</p> + +<pre class="brush: html notranslate"><p>Как указано в статье о <a href="https://developer.mozilla.org/ru/docs/Web/HTML/Element/blockquote"> +<cite>блочных цитатах</cite></a>: +</p> + +<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"> + <p><strong>HTML-элемент<code>&lt;blockquote&gt;</code></strong> (от англ. <em>HTML Block + Quotation Element</em>) указывает на то, что заключённый в нем текст является развёрнутой цитатой.</p> +</blockquote> + +<p>Элемент цитирования — <code>&lt;q&gt;</code> — <q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">предназначен +для коротких цитат, не требующих прерывания абзаца</q>. -- <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q"> +<cite>Строчные цитаты</cite></a>.</p></pre> + +<p>По умолчанию цитаты стилизованы курсивом. Этот код можно увидеть в нашем примере <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/advanced-text-formatting/quotations.html">quotations.html</a></p> + +<h3 id="Активное_обучение_кто_это_сказал">Активное обучение: кто это сказал?</h3> + +<p>Время для другого примера активного обучения! В этом примере мы хотели бы, чтобы вы совершили следующие действия:</p> + +<ol> + <li>Преобразуйте средний абзац в блочную цитату (<code><blockquote></code>), который включает атрибут <code>cite</code>.</li> + <li>Заверните часть третьего абзаца в строчную цитату, которая включает атрибут <code>cite</code>.</li> + <li>Включите элемент <code><cite></code> для каждой ссылки.</li> +</ol> + +<p>Источники цитирования, которые вам потребуются:</p> + +<ul> + <li><a href="http://www.brainyquote.com/quotes/authors/c/confucius">http://www.brainyquote.com/quotes/authors/c/confucius</a> — HTML-страница с цитатами Конфуция</li> + <li><a href="https://www.affirmationsforpositivethinking">https://www.affirmationsforpositivethinking</a> — HTML-страница <em>The Need To Eliminate Negative Self Talk</em>.</li> +</ul> + +<p>Если Вы ошиблись, то всегда можете начать снова, воспользовавшись кнопкой <em>Сбросить</em>. Если упражнение вызывает у Вас затруднения, то нажмите кнопку <em>Показать решение</em>, чтобы увидеть правильный ответ.</p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Результат</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label">Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).</p> + +<textarea id="code" class="input" style="min-height: 150px; width: 95%"> +<p>Здравствуйте и добро пожаловать на мою страницу мотивации! Конфуций как-то сказал:</p> +<p>Не важно, с какой скоростью ты движешься к своей цели, — главное не останавливаться.</p> +<p>Мне также нравится концепция позитивного мышления, и я считаю, каждый ощущает Необходимость избавления от негативного внутреннего разговора (как сказано в зарубежной статье Affirmations for Positive Thinking.)</p> +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<p>Здравствуйте и добро пожаловать на мою страницу мотивации! <a href="http://www.brainyquote.com/quotes/authors/c/confucius.html"><cite>Конфуций</cite></a> как-то сказал:</p>\n\n<blockquote cite="http://www.brainyquote.com/quotes/authors/c/confucius.html">\n <p>Не важно, с какой скоростью ты движешься к своей цели, — главное не останавливаться.</p>\n</blockquote>\n\n<p>Мне также нравится концепция позитивного мышления, и я считаю, каждый ощущает <q cite="http://www.affirmationsforpositivethinking.com/index.htm">Необходимость избавления от негативного внутреннего разговора</q> (как сказано в зарубежной статье <a href="http://www.affirmationsforpositivethinking.com/index.htm"><cite>Affirmations for Positive Thinking</cite></a>.)</p>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', 700, 450, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Аббревиатуры">Аббревиатуры</h2> + +<p>Другой довольно часто встречающийся элемент, который вы будете часто встречать в Интернете, — это {{htmlelement ("abbr")}}, используемый для обёртывания аббревиатур или акронимов и обеспечивающий полную расшифровку сокращения (с помощью атрибута {{htmlattrxref("title")}}.)</p> + +<p>Давайте рассмотрим несколько примеров:</p> + +<pre class="notranslate"><p>Мы используем <abbr title="Hypertext Markup Language">HTML</abbr> для структурирования наших веб-документов.</p> + +<p>Я думаю, <abbr title="Почтенный">Почт.</abbr> Грин сделал это на кухне с бензопилой.</p> +</pre> + +<p>Они будут выглядеть примерно так (расшифровка появится в подсказке при наведении курсора мыши на сокращение):</p> + +<p>Мы используем <abbr title="Hypertext Markup Language">HTML</abbr> для структурирования наших веб-документов.</p> + +<p>Я думаю, <abbr title="Почтенный">Почт.</abbr> Грин сделал это на кухне с бензопилой.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Существует еще один элемент {{htmlelement ("acronym")}}, который в основном делает то же самое, что и <code><abbr></code>, но предназначен специально для акронимов (тип аббревитатур). Это, однако, было излишним, — он не поддерживается в браузерах на том же уровне, что <code><abbr></code>, и имеет такую же функциональность, поэтому считается бессмысленным иметь оба. Просто используйте <code><abbr></code>.</p> +</div> + +<h3 id="Активное_обучение_выделение_аббревиатуры">Активное обучение: выделение аббревиатуры</h3> + +<p>В рамках этого простого упражнения мы хотели бы, чтобы вы просто указали аббревиатуру. Вы можете использовать наш образец ниже или заменить его на свой собственный.</p> + +<div class="hidden"> +<h6 id="Playable_code_3">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Результат</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label">Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).</p> + +<textarea id="code" class="input" style="min-height: 50px; width: 95%"> +<p>Безусловно, NASA занимается классными вещами.</p> +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<p>Безусловно, <abbr title="National Aeronautics and Space Administration">NASA</abbr> занимается классными вещами.</p>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_3', 700, 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Разметка_контактных_данных">Разметка контактных данных</h2> + +<p>HTML имеет элемент для разметки контактных данных — {{htmlelement ("address")}}. Он просто обёртывает ваши контактные данные, например:</p> + +<pre class="brush: html notranslate"><address> + <p>Крис Миллс, Манчестер, Жестокий Север, РФ</p> +</address></pre> + +<p>Однако следует помнить, что элемент {{htmlelement ("address")}} предназначен для разметки контактных данных человека, который написал HTML-документ, а не <em>любого </em>адреса. Таким образом, написанное выше было бы корректным только в том случае, если бы Крис написал документ, на котором появляется разметка. Обратите внимание, что следующее также подойдет:</p> + +<pre class="brush: html notranslate"><address> + <p>Автор страницы — <a href="../authors/chris-mills/">Крис Миллс</a>.</p> +</address></pre> + +<h2 id="Верхний_и_нижний_индекс">Верхний и нижний индекс</h2> + +<p>Иногда вам понадобится использовать надстрочный или подстрочный индекс при разметке таких вещей, как даты, химические формулы и математические уравнения, чтобы они имели правильное представление. Элементы {{htmlelement ("sup")}} и {{htmlelement ("sub")}} созданы для таких ситуаций.</p> + +<p>Приведем пример:</p> + +<pre class="brush: html notranslate"><p>Я просыпаюсь в 6<sup>35</sup> часов утра.</p> +<p>Химическая формула кофеина: C<sub>8</sub>H<sub>10</sub>N<sub>4</sub>O<sub>2</sub>.</p> +<p>Если x<sup>2</sup> равно 9, x должен равняться 3 или -3.</p></pre> + +<p>Результат этого кода выглядит следующим образом:</p> + +<p>Я просыпаюсь в 6<sup>35</sup> часов утра.</p> + +<p>Химическая формула кофеина: C<sub>8</sub>H<sub>10</sub>N<sub>4</sub>O<sub>2</sub>.</p> + +<p>Если x<sup>2</sup> равно 9, x должен равняться 3 или -3.</p> + +<h2 id="Представление_компьютерного_кода">Представление компьютерного кода</h2> + +<p>Существует несколько элементов для маркировки компьютерного кода с использованием HTML:</p> + +<ul> + <li>{{htmlelement("code")}}: Для разметки общих частей компьютерного кода.</li> + <li>{{htmlelement("pre")}}: Для сохранения пробелов (как правило, кодовых блоков) — если вы используете отступы или лишние пробелы внутри вашего текста, браузеры будут игнорировать его, и вы не увидите его на вашей отображаемой странице; если вы поместите текст в теги <code><pre></pre></code>, то ваши пробелы будут отображаться идентично тому, как вы видите текст в редакторе.</li> + <li>{{htmlelement("var")}}: Для конкретной маркировки имен переменных.</li> + <li>{{htmlelement("kbd")}}: Для маркировки вывода компьютерной программы. Для маркировки ввода клавиатуры (и других типов), введенного в компьютер.</li> + <li>{{htmlelement("samp")}}: Для маркировки вывода компьютерной программы.</li> +</ul> + +<p>Давайте рассмотрим несколько примеров. Вы должны попробовать поиграть с ними (захватите копию нашего файла <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/advanced-text-formatting/other-semantics.html">other-semantics.html</a>):</p> + +<pre class="notranslate"><pre><code>var para = document.querySelector('p'); + +para.onclick = function() { + alert('Owww, stop poking me!'); +}</code></pre> + +<p>You shouldn't use presentational elements like <code>&lt;font&gt;</code> and <code>&lt;center&gt;</code>.</p> + +<p>In the above JavaScript example, <var>para</var> represents a paragraph element.</p> + + +<p>Select all the text with <kbd>Ctrl</kbd>/<kbd>Cmd</kbd> + <kbd>A</kbd>.</p> + +<pre>$ <kbd>ping mozilla.org</kbd> +<samp>PING mozilla.org (63.245.215.20): 56 data bytes +64 bytes from 63.245.215.20: icmp_seq=0 ttl=40 time=158.233 ms</samp></pre></pre> + +<p>Вышеприведенный код будет выглядеть так:</p> + +<p>{{ EmbedLiveSample('Representing_computer_code','100%',300, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Разметка_времени_и_даты">Разметка времени и даты</h2> + +<p>HTML также содержит элемент {{htmlelement ("time")}} для отметки времени и дат в машиночитаемом формате. Например:</p> + +<pre class="brush: html notranslate"><<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2020-01-20<span class="pl-pds">"</span></span>>20 Января 2020</<span class="pl-ent">time</span>></pre> + +<p>Почему это полезно? Ну, есть много разных способов, которыми люди записывают даты. Вышеуказанная дата может быть записана как:</p> + +<ul> + <li>20 Января 2020</li> + <li>20-ое Января 2020</li> + <li>Янв 20 2020</li> + <li>20/01/20</li> + <li>01/20/20</li> + <li><span lang="fr">20e Janvier 2020</span></li> + <li><span lang="ja">2020年1月20日</span></li> + <li>и другое...</li> +</ul> + +<p>Но эти разные формы не могут быть легко распознаны компьютерами — что, если вы хотите автоматически захватить даты всех событий на странице и вставить их в календарь? Элемент {{htmlelement ("time")}} позволяет прикрепить к этой цели однозначное машиночитаемое время / дату.</p> + +<p>В приведенном выше базовом примере приведена простая машиносчитываемая дата, но есть много других возможных вариантов, например:</p> + +<pre class="brush: html notranslate"><!-- Стандартная дата --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2020-01-20<span class="pl-pds">"</span></span>>20 Января 2020</<span class="pl-ent">time</span>> +<!-- Только год и месяц --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2020-01<span class="pl-pds">"</span></span>>Январь 2020</<span class="pl-ent">time</span>> +<!-- Только месяц и день --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>01-20<span class="pl-pds">"</span></span>>20 Января</<span class="pl-ent">time</span>> +<!-- Только время, часы и минуты --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>19:30<span class="pl-pds">"</span></span>>19:30</<span class="pl-ent">time</span>> +<!-- Также вы можете отобразить секунды и миллисекунды! --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span></span>19:30:01.856<span class="pl-s"><span class="pl-pds">"</span></span>>19:30:01.856</<span class="pl-ent">time</span>> +<!-- Дата и время --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2020-01-20T19:30<span class="pl-pds">"</span></span>>7.30pm, 20 Января 2020</<span class="pl-ent">time</span>> +<!-- Дата и время со смещением по часовому поясу --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2020-01-20T19:30<span class="pl-pds">+01:00"</span></span>>7.30pm, 20 Января 2020, — это 8.30pm во Франции.</<span class="pl-ent">time</span>> +<!-- Вызов номера недели --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2020-W04<span class="pl-pds">"</span></span>>Четвертая неделя 2020</<span class="pl-ent">time</span>></pre> + +<h2 id="Заключение">Заключение</h2> + +<p>На этом мы подошли к концу нашего изучения семантики текста HTML. Имейте в виду, что то, что вы видели во время этого курса, не является исчерпывающим списком текстовых элементов HTML. Мы попытались охватить основные из них, с которыми вы, скорее всего, столкнетесь в практической деятельности или, по крайней мере, сочтёте их интересными. Чтобы найти больше элементов HTML, вы можете взглянуть на нашу ссылку на <a href="https://developer.mozilla.org/ru/docs/Web/HTML/Element">Элемент</a>. В следующей статье мы рассмотрим элементы HTML, которые вы будете использовать для структурирования различных частей HTML-документа.</p> + +<p>{{PreviousMenuNext ("Learn/HTML/Introduction_to_HTML/Create_hyperlinks", "Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></li> +</ul> diff --git a/files/ru/learn/html/введение_в_html/debugging_html/index.html b/files/ru/learn/html/введение_в_html/debugging_html/index.html new file mode 100644 index 0000000000..1f3e03e508 --- /dev/null +++ b/files/ru/learn/html/введение_в_html/debugging_html/index.html @@ -0,0 +1,181 @@ +--- +title: Отладка HTML +slug: Learn/HTML/Введение_в_HTML/Debugging_HTML +tags: + - Debugging + - Guide + - HTML + - Валидация + - Отладка +translation_of: Learn/HTML/Introduction_to_HTML/Debugging_HTML +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML/Marking_up_a_letter", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">Написать HTML — здорово, но как понять, где ошибка, когда что-то не работает? В этой статье описаны несколько инструментов, которые помогают искать и исправлять ошибки в HTML.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Что нужно знать:</th> + <td>Базовые знания HTML на уровне <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a>, <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a>, и <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a>.</td> + </tr> + <tr> + <th scope="row">Чему вы научитесь:</th> + <td>Искать проблемы в HTML с помощю инструментов отладки.</td> + </tr> + </tbody> +</table> + +<h2 id="Отладка_—_это_не_страшно">Отладка — это не страшно</h2> + +<p>Во время написания какого-нибудь кода, обычно все идет хорошо, пока не появляется тот момент, когда вы совершаете ошибку. Итак, ваш код не работает, или работает не так, как вы задумывали. Если вы попытаетесь скомпилировать неработающую программу на языке <a href="https://www.rust-lang.org/">Rust</a>, компилятор укажет на ошибку:</p> + +<p><img alt="A console window showing the result of trying to compile a rust program with a missing quote around a string in a print statement. The error message reported is error: unterminated double quote string." src="https://mdn.mozillademos.org/files/12435/error-message.png" style="display: block; height: 520px; margin: 0px auto; width: 711px;">В данном случае, сообщение об ошибке понять относительно просто — "unterminated double quote string". Если вы внимательно посмотрите на <code>println!(Hello, world!");</code> , то заметите, что здесь отсутсвует двойная кавычка. Разумеется, сообщения об ошибках могут становиться куда более сложными для понимания по мере роста вашего кода, и даже самые простые случаи могут показаться пугающими для тех, кто ничего не знает о Rust.</p> + +<p>Но не бойтесь отладки! Чтобы комфортно писать и отлаживать любой код, нужно понимать язык и его инструменты.</p> + +<h2 id="HTML_и_отладка">HTML и отладка</h2> + +<p>HTML не так сложен к пониманию, как Rust. HTML не компилируется в какую-либо другую форму перед тем, как браузер проанализирует это и покажет результат (он является <em>интерпретируемым</em>, а не <em>компилируемым</em>). Синтаксис HTML элементов намного понятнее, чем у "настоящих языков программирования", таких как Rust, {{glossary("JavaScript")}}, или {{glossary("Python")}}. Способ, которым браузеры читают HTML более <strong>толерантен</strong>, чем у языков программирования, интерпретирующих свой код строже. Это одновременно и плохо, и хорошо.</p> + +<h3 id="Толерантный_код">Толерантный код</h3> + +<p>Так что же означает толерантный? В общих чертах, когда вы напортачили в коде, есть два типа ошибок, с которыми вы столкнетесь:</p> + +<ul> + <li><strong>Синтаксические ошибки (Syntax errors)</strong>: Это ошибки в правильности написания, как это было выше, в примере с Rust. Такие обычно легко исправлять, в той мере, в какой вы знакомы с синтаксисом языка и знаете, что означают сообщения об ошибках.</li> + <li><strong>Логические ошибки (Logic errors)</strong>: Это ошибки, появляющиеся в том случае, если синтаксис корректен, но код не выполняет своего предназначения, то есть программа выполняется неверно. Такие исправлять сложнее, чем синтаксические, поскольку не выводится сообщений, указывающих место, где вы ошиблись.</li> +</ul> + +<p>HTML не страдает от синтаксических ошибок, потому что браузер читает код толерантно, в том смысле, что страницы могут отображаться даже если синтаксические ошибки присутсвуют. Браузеры имеют встроенные правила по интерпретации неверно написанной разметки, и вы можете запустить что-либо, даже если вы имели в виду другое. Это может стать настоящей проблемой!</p> + +<div class="note"> +<p><strong>На заметку</strong>: HTML читается толерантно, потому что когда веб только появился, было решено позволить людям публиковать контент даже при условии некорректностей в коде, так как это куда более важно, чем уверенность в абсолютно верном синтаксисе. Веб не был бы сейчас так популярен, если бы относился к новичкам строго.</p> +</div> + +<h3 id="Активное_обучение_Знакомство_с_толерантным_кодом">Активное обучение: Знакомство с толерантным кодом</h3> + +<p>Время изучить природу толерантного кода в HTML.</p> + +<ol> + <li>Для начала, скачайте наш <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/debugging-html/debug-example.html">пример отладки</a> и сохраните локально. Эта демонстрация намеренно написана с ошибками, которые нам предстоит обнаружить.</li> + <li>Далее, откройте её в браузере. Вы увидите нечто вроде этого :<img alt="A simple HTML document with a title of HTML debugging examples, and some information about common HTML errors, such as unclosed elements, badly nested elements, and unclosed attributes. " src="https://mdn.mozillademos.org/files/12437/badly-formed-html.png" style="display: block; margin: 0 auto;"></li> + <li>Сейчас документ выглядит не особо хорошо; Давайте посмотрим в код и выясним почему (Показано только тело документа): + <pre class="brush: html"><h1>HTML debugging examples</h1> + +<p>What causes errors in HTML? + +<ul> + <li>Unclosed elements: If an element is <strong>not closed properly, + then its effect can spread to areas you didn't intend + + <li>Badly nested elements: Nesting elements properly is also very important + for code behaving correctly. <strong>strong <em>strong emphasised?</strong> + what is this?</em> + + <li>Unclosed attributes: Another common source of HTML problems. Let's + look at an example: <a href="https://www.mozilla.org/>link to Mozilla + homepage</a> +</ul></pre> + </li> + <li>Рассмотрим проблемы: + <ul> + <li>У {{htmlelement("p","параграфа")}} и {{htmlelement("li","элемента списка")}} не закрыты теги. На изображении выше видно, что разметка не пострадала, так как браузеру легко сделать вывод о том, где заканчивается один элемент и начинается другой.</li> + <li>Первый {{htmlelement("strong")}} элемент также не имеет закрывающего тега. Это уже более проблематично, так как сложно сказать, где элемент должен заканчиваться. На деле, весь оставшийся текст был выделен жирным.</li> + <li>Следующая часть нарушает правила вложенности: <code><strong>strong <em>strong emphasised?</strong> what is this?</em></code>. В этом случае код тоже сложно проинтерпретировать по причине, описанной выше.</li> + <li>В атрибуте {{htmlattrxref("href","a")}} отсутсвует закрывающая двойная кавычка. Это послужило причиной крупной проблемы — ссылка не воспроизвелась вовсе.</li> + </ul> + </li> + <li>Сейчас же посмотрим, как браузер сгенерировал собственную разметку, в противовес исходной разметке документа. Чтобы сделать это, воспользуемся инструментами разработчика. Если вы не знакомы с инструментами разработчика, потратьте несколько минут на <a href="/en-US/docs/Learn/Discover_browser_developer_tools">Обзор инструментов разработки в браузерах</a>.</li> + <li>В DOM инспекторе вы можете увидеть как сгенерировалась новая разметка: <img alt="The HTML inspector in Firefox, with our example's paragraph highlighted, showing the text "What causes errors in HTML?" Here you can see that the paragraph element has been closed by the browser." src="https://mdn.mozillademos.org/files/12439/html-inspector.png" style="display: block; margin: 0 auto;"></li> + <li>Используя DOM инспектор, давайте рассмотрим детали нашего кода, чтобы увидеть, как браузер пытается исправить наши ошибки в HTML (мы обозреваем в Firefox; другой современный браузер должен выдать те же результаты): + <ul> + <li>Параграфы и элементы списка получены с закрывающими тегами.</li> + <li>Было неочевидно, где элемент <code><strong></code> должен был закрыться, так что браузер обернул каждый отдельный блок текста своими собственными тегами strong, причем до самого низа документа!</li> + <li>Некорректная вложенность была исправлена браузером следующим образом: + <pre class="brush: html"><strong>strong + <em>strong emphasised?</em> +</strong> +<em> what is this?</em></pre> + </li> + <li>Ссылка с отсутсвующими двойными кавычками была удалена насовсем. Последний элемент списка будет выглядеть так: + <pre class="brush: html"><li> + <strong>Unclosed attributes: Another common source of HTML problems. + Let's look at an example: </strong> +</li></pre> + </li> + </ul> + </li> +</ol> + +<h3 id="Валидация_HTML">Валидация HTML</h3> + +<p>Из примера выше ясно, что стоит проверять валидность HTML. В простом примере сверху можно просто просмотреть весь код и найти ошибки, но как быть с огромными, сложными страницами?</p> + +<p>Лучше всего проверить страницу в <a href="https://validator.w3.org/">сервисе валидации разметки</a>. Его создал и поддерживает W3C — организация, которая занимается спецификациями HTML, CSS и других веб-технологий. Сервис проверит ваш HTML и составит отчет по ошибкам в нем.</p> + +<p><img alt="The HTML validator homepage" src="https://mdn.mozillademos.org/files/12441/validator.png" style="display: block; margin: 0 auto;"></p> + +<p>HTML можно проверить по адресу, загрузив файл или напрямую ввести код HTML.</p> + +<h3 id="Активное_обучение_Валидируем_HTML-документ">Активное обучение: Валидируем HTML-документ</h3> + +<p>Попробуем проверить <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/debugging-html/debug-example.html">документ-пример</a>.</p> + +<ol> + <li>Откройте <a href="https://validator.w3.org/">сервис валидации разметки</a> в браузере.</li> + <li>Перейдите в режим <a href="https://validator.w3.org/#validate_by_input">Validate by Direct Input</a>.</li> + <li>Скопируйте весь код документа (не только body) и вставьте в место для ввода.</li> + <li>Нажмите на <em>Check (проверить)</em>.</li> +</ol> + +<p>Вы увидите список ошибок и другую информацию.</p> + +<p><img alt="A list of of HTML validation results from the W3C markup validation service" src="https://mdn.mozillademos.org/files/12443/validation-results.png" style="display: block; margin: 0 auto;"></p> + +<h4 id="Работа_с_сообщениями_об_ошибках">Работа с сообщениями об ошибках</h4> + +<p>Обычно сразу ясно, что значат сообщения, но иногда приходится постараться, чтобы понять, в чем дело. Сейчас мы пройдемся по всем ошибкам и разберем, что они значат. Обратите внимание, что в сообщениях указаны строка и столбец кода, чтобы ошибки было проще искать.</p> + +<ul> + <li>"End tag <code>li</code> implied, but there were open elements" (2 instances): Нет явного закрывающего тега, хотя браузер догадывается, где он должен быть. Сообщение указывает на строку после той, на которой ожидался закрывающий тег, но вы найдете нужное место.</li> + <li>"Unclosed element <code>strong</code>": Это очень простая ошибка — элемент {{htmlelement("strong")}} не закрыт, и сообщение указывает прямо на открывающий тег.</li> + <li>"End tag <code>strong</code> violates nesting rules": Элемент неправильно вложен — на этом уровне нет парного открывающего тега.</li> + <li>"End of file reached when inside an attribute value. Ignoring tag": Загадочное сообщение. Дело в том, что где-то (скорее всего, в конце документа) неправильно прописано свойство элемента, и конец файла оказался внутри этого свойства. В браузере не видно ссылки — скорее всего, проблема рядом с ней.</li> + <li>"End of file seen and there were open elements": Файл закончился, но некоторые элементы не закрыты. Сообщение указывает на конец файла, в данном случае не закрыт элемент + <pre>example: <a href="https://www.mozilla.org/>link to Mozilla homepage</a> ↩ </ul>↩ </body>↩</html></pre> + + <div class="note"> + <p><strong>Примечание</strong>: Свойство без закрывающей кавычки может проглотить закрывающий тег — браузер считает его частью значения этого свойства.</p> + </div> + </li> + <li>"Unclosed element <code>ul</code>": Странно, ведь элемент {{htmlelement("ul")}} закрыт. Настоящая проблема всё там же — элемент {{htmlelement("a")}} не закрыт из-за недостающей кавычки в свойстве.</li> +</ul> + +<p>Если некоторые ошибки кажутся вам странными, начните исправление с остальных и проверьте документ еще раз. Иногда одна ошибка ломает большую часть документа.</p> + +<p><span>Когда вы увидите эту надпись, в вашем документе больше нет ошибок:</span></p> + +<p><img alt='Banner that reads "The document validates according to the specified schema(s) and to additional constraints checked by the validator."' src="https://mdn.mozillademos.org/files/12445/valid-html-banner.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="Заключение">Заключение</h2> + +<p>Теперь вы умеете отлаживать HTML. С новыми знаниями вам будет проще разобраться и в отладке более сложных языков — например, CSS и JavaScript. На этом мы заканчиваем вводный модуль курса HTML — время попробовать свои силы в упражнениях.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML/Marking_up_a_letter", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></li> +</ul> diff --git a/files/ru/learn/html/введение_в_html/html_text_fundamentals/index.html b/files/ru/learn/html/введение_в_html/html_text_fundamentals/index.html new file mode 100644 index 0000000000..711c0bfdf3 --- /dev/null +++ b/files/ru/learn/html/введение_в_html/html_text_fundamentals/index.html @@ -0,0 +1,994 @@ +--- +title: Основы редактирования текста в HTML +slug: Learn/HTML/Введение_в_HTML/HTML_text_fundamentals +tags: + - Guide + - HTML + - Абзацы + - Введение в HTML + - Изучение + - Начинающий + - Параграфы + - Руководство + - Семантика + - Текст +translation_of: Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals +--- +<div> +<div> {{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML")}}</div> +</div> + +<p class="summary">Одна из основных задач HTML — придавать тексту структуру и смысл, {{glossary("семантику")}}, так, чтобы браузер смог отобразить текст корректно. Эта статья покажет, как можно использовать {{glossary("HTML")}}, чтобы упорядочить текст на странице путём добавления заголовков и абзацев, выделения слов, создания списков и многое другое.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные требования:</th> + <td>Базовое знакомство с HTML , описанное в <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Изучить базовые способы разметки текста путем добавлением на страницу структуры и значения — создать абзацы, заголовки, списки, акценты и цитаты..</td> + </tr> + </tbody> +</table> + +<h2 id="Основы_Заголовки_и_абзацы_параграфы">Основы: Заголовки и абзацы / параграфы</h2> + +<p>Большинство структурированных текстов состоят из параграфов и заголовков, независимо от того, читаете ли вы рассказ, или газету, или учебник, журнал и т.д.</p> + +<p><img alt="An example of a newspaper front cover, showing use of a top level heading, subheadings and paragraphs." src="https://mdn.mozillademos.org/files/12371/newspaper_small.jpg" style="display: block; margin: 0 auto;"></p> + +<p>Упорядоченный контент делает чтение более легким и приятным.</p> + +<p>В HTML каждый абзац заключен в элемент {{htmlelement("p")}}, подобно:</p> + +<pre class="brush: html notranslate"><p>Я параграф, да, это я.</p></pre> + +<p>Каждый заголовок заключен в элемент заголовка {{htmlelement("h1")}}:</p> + +<pre class="brush: html notranslate"><h1>Я заголовок истории.</h1></pre> + +<p>Имеется шесть элементов заголовка: {{htmlelement("h1")}}, {{htmlelement("h2")}}, {{htmlelement("h3")}}, {{htmlelement("h4")}}, {{htmlelement("h5")}} и {{htmlelement("h6")}}. Каждый элемент представляет разный уровень контента в документе; <code><h1></code> представляет главный заголовок, <code><h2></code> представляет подзаголовки, <code><h3></code> представляет под-подзаголовки и так далее.</p> + +<h3 id="Создание_иерархической_структуры">Создание иерархической структуры</h3> + +<p>Например, в рассказе <code><h1></code> будет представлять заглавие рассказа, <code><h2></code> обозначит название каждой главы, <code><h3></code> будет обозначать подзаголовки в каждой главе и так далее.</p> + +<pre class="brush: html notranslate"><h1> Сокрушительная скука </ h1> + +<p> Крис Миллс </ p> + +<h2> Глава 1: Темная ночь </ h2> + +<p> Это была темная ночь. Где-то кричала сова. Дождь обрушился на ... </ p> + +<h2> Глава 2: Вечное молчание </ h2> + +<p> Наш главный герой ничего не мог, когда шёпот из тёмной фигуры ... </ p> + +<h3> Призрак говорит </ h3> + +<p> Прошло ещё несколько часов, когда внезапно призрак выпрямился и воскликнул: «Пожалуйста, помилуй мою душу!» </ p> +</pre> + +<p>Всё это действительно зависит от вас — что именно будут представлять собой элементы, пока существует иерархия. Вам просто нужно иметь в виду несколько хороших правил при создании таких структур.</p> + +<ul> + <li>Предпочтительнее использовать <code><h1></code> только один раз на странице — это заголовок самого верхнего уровня, и все остальные заголовки распологаются ниже его в иерархии.</li> + <li>Убедитесь, что вы используете заголовки в правильном порядке в иерархии. Не используйте <code><h3></code> для создания подзаголовков при одновременном использовании <code><h2></code> для представления под-подзаголовков — это не имеет смысла и приведет к странным результатам.</li> + <li><span id="result_box" lang="ru"><span>Из шести доступных уровней заголовка вы должны стремиться использовать не более трех на странице, если только вы не чувствуете, что это необходимо.</span></span> <span id="result_box" lang="ru"><span>Документы с большим количеством уровней (то есть с глубокой иерархией) становятся громоздкими и трудными для навигации.</span></span> <span id="result_box" lang="ru"><span>В таких случаях рекомендуется распределять контент по нескольким страницам, если это возможно.</span></span></li> +</ul> + +<h3 id="Зачем_нам_необходима_структура">Зачем нам необходима структура?</h3> + +<p><span id="result_box" lang="ru"><span>Чтобы ответить на этот вопрос, давайте посмотрим на </span></span> <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/html-text-formatting/text-start.html">text-start.html</a> —<span lang="ru"><span> отправную точку нашего примера для этой статьи (хороший рецепт хумуса).</span></span> <span id="result_box" lang="ru"><span>Вы должны сохранить копию этого файла на своем локальном компьютере, так как вам понадобится это для упражнений позже.</span></span> <span id="result_box" lang="ru"><span>Сейчас тело этого документа содержит несколько фрагментов контента — они не отмечены каким-либо образом, но они разделены разрывами строк (был нажат Enter / Return для перехода на следующую строку).</span></span></p> + +<p><span id="result_box" lang="ru"><span>Однако, когда вы откроете документ в своем браузере, вы увидите, что текст выглядит как один большой кусок!</span></span></p> + +<p><img alt="A webpage that shows a wall of unformatted text, because there are no elements on the page to structure it." src="https://mdn.mozillademos.org/files/14827/Screen%20Shot%202017-03-29%20at%2009.20.35.png" style="display: block; height: 377px; margin: 0px auto; width: 600px;"></p> + +<p><span id="result_box" lang="ru"><span>Это связано с тем, что нет элементов для создания структуры контента, поэтому браузер не знает, где здесь заголовок и где абзац.</span> <span>Более того:</span></span></p> + +<ul> + <li><span id="result_box" lang="ru"><span>Пользователи, просматривающие веб-страницу, быстро сканируют её в поиске подходящего контента, часто просто просматривая только заголовки (мы обычно </span></span><a class="external external-icon" href="http://www.nngroup.com/articles/how-long-do-users-stay-on-web-pages/">тратим очень мало времени на веб-странице</a><span lang="ru"><span>).</span> <span>Если они не смогут увидеть ничего полезного в течение нескольких секунд, они, скорее всего, расстроятся и отправятся куда-нибудь ещё.</span></span></li> + <li><span id="result_box" lang="ru"><span>Поисковые системы, индексирующие вашу страницу, считают содержание заголовков важными ключевыми словами для влияния на ранжирование поиска страницы.</span> <span>Без заголовков ваша страница будет плохо работать с точки зрения</span></span> {{glossary("SEO")}} (Search Engine Optimization — поисковая оптимизация).</li> + <li>Сильно <span id="result_box" lang="ru"><span>слабовидящие люди часто не читают веб-страницы —</span> <span>они слушают их вместо этого.</span> <span>Это делается с помощью программного обеспечения, называемого </span></span><a class="external external-icon" href="http://en.wikipedia.org/wiki/Screen_reader" title="screen readers">программой чтения с экрана</a><span lang="ru"><span>.</span> <span>Это программное обеспечение предоставляет способы быстрого доступа к данному текстовому контенту.</span> <span>Среди различных используемых методов они предоставляют схему документа, считывая заголовки, позволяя своим пользователям быстро находить нужную им информацию.</span> <span>Если заголовки недоступны, они будут вынуждены слушать весь документ вслух.</span></span></li> + <li><span id="result_box" lang="ru"><span>Чтобы стилизовать контент с помощью {{glossary ("CSS")}} или сделать его интересным с помощью {{glossary ("JavaScript")}}, вам нужно, чтобы элементы обёртывали соответствующий контент, чтобы CSS и JavaScript смогли эффективно работать</span><span>.</span></span></li> +</ul> + +<p><span id="result_box" lang="ru"><span>Поэтому нужно дать структурную разметку нашему контенту.</span></span></p> + +<h3 id="Активное_изучение_создание_структуры_для_нашего_контента">Активное изучение: создание структуры для нашего контента</h3> + +<p><span id="result_box" lang="ru"><span>Давайте рассмотрим это на живом примере.</span> <span>В приведённом ниже примере добавьте элементы в исходный текст в поле «</span></span>Редактируемый код<span lang="ru"><span>», чтобы он отображался как заголовок и два абзаца в поле «</span></span>Результат<span lang="ru"><span>».</span></span></p> + +<p><span id="result_box" lang="ru"><span>Если вы допустили ошибку, вы всегда можете сбросить её с помощью кнопки <em>Сбросить</em>.</span> <span>Если вы застряли, нажмите кнопку <em>Показать решение</em>, чтобы увидеть ответ.</span></span></p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Результат</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label">Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).</p> + +<textarea id="code" class="input" style="min-height: 100px; width: 95%">Моя мини-история +Я полицейский, и моё имя Триш. +Мои ноги сделаны из картона, и мой муж — рыба.</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +body { + margin: 10px; + background: #f5f9fa; +} + +.input, .output { + width: 90%; + height: 6em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<h1>Моя мини-история</h1>\n<p>Я полицейский, и моё имя Триш.</p>\n<p>Мои ноги сделаны из картона, и мой муж — рыба.</p>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +textarea.onkeyup = function(){ + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 500) }}</p> + +<h3 id="Почему_мы_нуждаемся_в_семантике">Почему мы нуждаемся в семантике?</h3> + +<p><span id="result_box" lang="ru"><span>Семантика проявляется всюду вокруг нас — мы полагаемся на опыт, который рассказывает нам, какова функция бытовых предметoв;</span> <span>когда мы что-то видим, мы знаем, какова его функция.</span> <span>Так, например, мы ожидаем, что красный свет на светофоре означает «стоп», а зеленый свет означает «идти».</span> <span>Жизнь станет очень сложной, если применяется неправильная семантика (какие-либо страны используют красный цвет для обозначения «идти»? Надеюсь, что нет.)</span></span></p> + +<p><span id="result_box" lang="ru"><span>В подобном ключе нам нужно убедиться, что мы используем правильные элементы, придавая нашему контенту правильное значение, функцию или внешний вид.</span> <span>В этом контексте элемент {{htmlelement ("h1")}} также является семантическим элементом, который даёт тексту, который он обёртывает, роль (или значение) «заголовка верхнего уровня на вашей странице».</span></span></p> + +<pre class="brush: html notranslate"><h1>Это заголовок верхнего уровня</h1></pre> + +<p><span id="result_box" lang="ru"><span>По умолчанию браузер придаст ему большой размер шрифта, чтобы он выглядел как заголовок (хотя вы можете стилизовать его как угодно, используя CSS).</span> <span>Что ещё более важно, его семантическое значение будет использоваться несколькими способами, например, поисковыми системами и программами чтения с экрана (как упоминалось выше).</span></span></p> + +<p><span id="result_box" lang="ru"><span>С другой стороны, вы можете сделать любой элемент похожим на заголовок верхнего уровня.</span> <span>Рассмотрим следующее:</span></span></p> + +<pre class="brush: html notranslate"><span style="font-size: 32px; margin: 21px 0;">Это заголовок верхнего уровня?</span></pre> + +<p><span id="result_box" lang="ru"><span>Это элемент {{htmlelement ("span")}}.</span> <span>У него нет семантики.</span> <span>Вы используете его, когда хотите применить к контенту CSS (или сделать что-то с ним с помощью JavaScript), не придавая ему никакого дополнительного значения (об этом вы узнаете позже). Мы применили CSS,</span> <span>чтобы он выглядел как заголовок верхнего уровня, но поскольку он не имеет семантического значения, он не получит никаких дополнительных преимуществ, описанных выше.</span> <span>Рекомендуется использовать соответствующий элемент HTML на практике.</span></span></p> + +<h2 id="Списки">Списки</h2> + +<p><span id="result_box" lang="ru"><span>Теперь обратим наше внимание на списки.</span> <span>Списки есть везде вокруг нас — от вашего списка покупок до списка направлений, которым вы подсознательно следуете, чтобы каждый день добраться домой, и списка инструкций, которые вы выполняете в этом руководстве!</span> <span>Списки используются всюду в Интернете, и мы рассмотрим три разных типа списков.</span></span></p> + +<h3 id="Неупорядоченные">Неупорядоченные</h3> + +<p><span id="result_box" lang="ru"><span>Неупорядоченные списки используются для элементов, для которых порядок не имеет значения, — возьмем, к примеру, список покупок:</span></span></p> + +<pre class="notranslate">молоко +яйца +хлеб +хумус</pre> + +<p><span id="result_box" lang="ru"><span>Каждый неупорядоченный список начинается с элемента {{htmlelement ("ul")}} (<em>unordered list</em>) — он обёртывает все элементы списка:</span></span> молоко, яйца, хлеб, хумус.</p> + +<p><span id="result_box" lang="ru"><span>Последний шаг состоит в том, чтобы обернуть каждый элемент списка в элемент {{htmlelement ("li")}} (элемент списка):</span></span></p> + +<pre class="brush: html notranslate"><ul> + <li>молоко</li> + <li>яйца</li> + <li>хлеб</li> + <li>хумус</li> +</ul></pre> + +<h3 id="Активное_изучение_разметка_неупорядоченного_списка">Активное изучение: разметка неупорядоченного списка</h3> + +<p><span id="result_box" lang="ru"><span>Попробуйте отредактировать образец ниже, чтобы создать свой собственный неупорядоченный список HTML.</span></span></p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code</h6> + +<pre class="brush: html notranslate"><code><h2>Результат</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label"></code>Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).<code></p> + +<textarea id="code" class="input" style="min-height: 100px; width: 95%">молоко +яйца +хлеб +хумус</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></code></pre> + +<pre class="brush: css notranslate">html { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +body { + margin: 10px; + background: #f5f9fa; +} + +.input, .output { + width: 90%; + height: 6em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<ul>\n<li>молоко</li>\n<li>яйца</li>\n<li>хлеб</li>\n<li>хумус</li>\n</ul>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +textarea.onkeyup = function(){ + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', 700, 400) }}</p> + +<h3 id="Упорядоченные">Упорядоченные</h3> + +<p><span id="result_box" lang="ru"><span>Упорядоченные списки — это списки, в которых порядок элементов имеет значение, — возьмем в качестве примера маршрут следования:</span></span></p> + +<pre class="notranslate">Доедьте до конца дороги +Поверните направо +Едьте прямо через первые два перекрестка с круговым движением +Поверните налево на третьем перекрестке +Школа справа от вас, 300 метров вверх по дороге</pre> + +<p><span id="result_box" lang="ru"><span>Структура разметки такая же, как для неупорядоченных списков, за исключением того, что вы должны обернуть элементы списка в элемент {{htmlelement ("ol")}} (ordered list), а не <ul>:</span></span></p> + +<pre class="brush: html notranslate"><ol> + <li>Доедьте до конца дороги</li> + <li>Поверните направо</li> + <li>Едьте прямо через первые два перекрестка с круговым движением</li> + <li>Поверните налево на третьем перекрестке</li> + <li>Школа справа от вас, в 300 метрах вверх по дороге</li> +</ol></pre> + +<h3 id="Активное_изучение_разметка_упорядоченного_списка">Активное изучение: разметка упорядоченного списка</h3> + +<p><span id="result_box" lang="ru"><span>Попробуйте отредактировать образец ниже, чтобы создать свой собственный упорядоченный список HTML.</span></span></p> + +<div class="hidden"> +<h6 id="Playable_code_3">Playable code</h6> + +<pre class="brush: html notranslate"><code><h2>Результат</h2> +<div class="output" style="min-height: 50px;"> +</div> +<h2>Редактируемый код</h2> +<p class="a11y-label"></code>Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).<code></p> + +<textarea id="code" class="input" style="min-height: 200px; width: 95%"></code>Доедьте до конца дороги +Поверните направо +Едьте прямо через первые два перекрестка с круговым движением +Поверните налево на третьем перекрестке +Школа справа от вас, 300 метров вверх по дороге<code></textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></code></pre> + +<pre class="brush: css notranslate">html { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +body { + margin: 10px; + background: #f5f9fa; +} + +.input, .output { + width: 90%; + height: 6em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<ol>\n<li>Доедьте до конца дороги</li>\n<li>Поверните направо</li>\n<li>Едьте прямо через первые два перекрестка с круговым движением</li>\n<li>Поверните налево на третьем перекрестке</li>\n<li>Школа справа от вас, 300 метров вверх по дороге</li>\n</ol>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +textarea.onkeyup = function(){ + if(solution.value === 'Показать решение>') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_3', 700, 500) }}</p> + +<h3 id="Активное_изучение_разметка_собственной_страницы_рецептов">Активное изучение: разметка собственной страницы рецептов</h3> + +<p><span id="result_box" lang="ru"><span>Итак, в этот момент в статье у вас есть вся необходимая информация, чтобы разметить наш пример страницы рецепта.</span> <span>Вы можете либо сохранить локальную копию исходного файла </span></span><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/html-text-formatting/text-start.html">text-start.html</a><span lang="ru"><span> и выполнить в нём работу, либо сделать это в приведённом ниже примере.</span> <span>Делать это локально, вероятно, будет лучше, так как тогда вы сможете сохранить работу, которую вы делаете, тогда как если вы её добавите в редактируемый пример, она будет потеряна при следующем открытии страницы.</span> <span>У обоих способов есть плюсы и минусы.</span></span></p> + +<div class="hidden"> +<h6 id="Playable_code_4">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Результат</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2><code>Редактируемый код</code></h2> +<p class="a11y-label">Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).</p> + +<textarea id="code" class="input" style="min-height: 200px; width: 95%">Рецепт быстрого приготовления хумуса. + + Хумус — быстро, вкусно, — и ничего лишнего. Этот рецепт был составлен из других рецептов, которые мне попадались в течение многих лет. + + Хумус — это вкусная густая паста, широко используемая в Греческих и Ближневосточных блюдах. Очень вкусно есть его с салатами, мясом на гриле и питой. + + Ингредиенты + + 1 банка (400г) турецкого гороха (или бараньего гороха) + 175г тахини + 6 вяленых томатов + Половинка красного перца + Щепотка кайенского перца + 1 зубчик чеснока + Чуть-чуть оливкового масла + + Рецепт + + Очистите чеснок от кожуры и крупно нарежьте. + Удалите стебель и семена у перца; крупно нарежьте перец. + Добавьте все ингредиенты в пищевой комбайн. + Измельчите все ингридиенты до состояния пасты. + Если вы хотите "грубый" хумус, измельчайте пару минут. + Если вам нужен гладкий хумус, измельчайте дольше. + + По вкусу можете добавить в небольших количествах лимон и кориандский перец, лайм и чипотле, хариссу и мяту или шпинат и брынзу. Попробуйте и решите, что подоходит вам. + + Хранение + + Храните хумус в запечатанном контейнере в холодильнике. Хумус хранится примерно неделю после приготовления. Если он начнёт пениться, выкидывайте его. + + Хумус можно хранить в морозильном отделении 2–3 месяца.</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +body { + margin: 10px; + background: #f5f9fa; +} + +.input, .output { + width: 90%; + height: 6em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<h1>Рецепт быстрого приготовления хумуса.</h1>\n\n<p>Хумус — быстро, вкусно, — и ничего лишнего. Этот рецепт был составлен из других рецептов, которые мне попадались в течение многих лет.</p>\n\n<p>Хумус — это вкусная густая паста, широко используемая в Греческих и Ближневосточных блюдах. Очень вкусно есть его с салатами, мясом на гриле и питой.</p>\n\n<h2>Ингредиенты</h2>\n\n<ul>\n<li>1 банка (400г) турецкого гороха (или бараньего гороха)</li>\n<li>175г тахани</li>\n<li>6 вяленых томатов</li>\n<li>Половинка красного перца</li>\n<li>Щепотка кайенского перца</li>\n<li>1 зубчик чеснока</li>\n<li>Чуть-чуть оливкового масла</li>\n</ul>\n\n<h2>Рецепт</h2>\n\n<ol>\n<li>Очистите чеснок от кожуры и крупно нарежьте.</li>\n<li>Удалите стебель и семена у перца; крупно нарежьте.</li>\n<li>Добавьте все ингредиенты в пищевой комбайн.</li>\n<li>Измельчите все ингридиенты до состояния пасты.</li>\n<li>Если вы хотите "грубый" хумус, измельчайте пару минут.</li>\n<li>Если вам нужен гладкий хумус, измельчайте дольше.</li>\n</ol>\n\n<p>По вкусу можете добавить в небольших количествах лимон и кориандский перец, лайм и чипотле, хариссу и мяту или шпинат и брынзу. Попробуйте и решите, что подоходит вам.</p>\n\n<h2>Хранение</h2>\n\n<p>Храните хумус в запечатанном контейнере в холодильнике. Хумус хранится примерно неделю после приготовления. Если он начнёт пениться, выкидывайте его.</p>\n\n<p>Хумус можно хранить в морозильном отделении 2–3 месяца.</p>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +textarea.onkeyup = function(){ + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_4', 700, 500) }}</p> + +<p><span id="result_box" lang="ru"><span>Если вы застряли, вы всегда можете нажать кнопку <em>Показать решение</em> или проверить наш пример </span></span><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/html-text-formatting/text-complete.html">text-complete.html</a><span lang="ru"><span> в нашем реестре github.</span></span></p> + +<h3 id="Вложенные_списки">Вложенные списки</h3> + +<p><span id="result_box" lang="ru"><span>Вполне нормально вложить один список в другой.</span> <span>Возможно, вы захотите, чтобы один список распологался внутри другого.</span> <span>Давайте возьмем второй список из нашего примера рецепта:</span></span></p> + +<pre class="brush: html notranslate"><ol> + <li>Очистите чеснок от кожуры и крупно нарежьте.</li> + <li>Удалите стебель и семена у перца; крупно нарежьте перец.</li> + <li>Добавьте все ингредиенты в пищевой комбайн.</li> + <li>Измельчите все ингридиенты до состояния пасты.</li> + <li>Если вы хотите "грубый" хумус, измельчайте пару минут.</li> + <li>Если вам нужен гладкий хумус, измельчайте дольше.</li> +</ol> </pre> + +<div id="gt-res-content"> +<div class="trans-verified-button-small" dir="ltr" id="gt-res-dir-ctr"><span id="result_box" lang="ru"><span>Поскольку последние две строки очень тесно связаны с тем, что было до них (они читаются как вспомогательные инструкции или варианты, которые подходят под этой маркой), может иметь смысл вложить их в свой собственный неупорядоченный список и поместить этот список внутри текущего</span><span>.</span> <span>Это будет выглядеть так:</span></span></div> +</div> + +<pre class="brush: html notranslate"><ol> + <li>Очистите чеснок от кожуры и крупно нарежьте.</li> + <li>Удалите стебель и семена у перца; крупно нарежьте перец.</li> + <li>Добавьте все ингредиенты в пищевой комбайн.</li> + <li>Измельчите все ингридиенты до состояния пасты. + <ul> + <li>Если вы хотите "грубый" хумус, измельчайте пару минут.</li> + <li>Если вам нужен гладкий хумус, измельчайте дольше.</li> + </ul> + </li> +</ol></pre> + +<p><span id="result_box" lang="ru"><span>Попробуйте вернуться к предыдущему примеру активного обучения и обновить второй список.</span></span></p> + +<h2 id="Акцент_и_важность"><span class="short_text" id="result_box" lang="ru"><span>Акцент и важность</span></span></h2> + +<div id="gt-res-content"> +<div class="trans-verified-button-small" dir="ltr" id="gt-res-dir-ctr"><span id="result_box" lang="ru"><span>В обиходе мы часто подчеркиваем определённые слова, чтобы изменить смысл предложения и мы часто хотим отметить некоторые слова как важные или разные в некотором роде.</span> <span>HTML предоставляет различные семантические элементы, позволяющие нам добавлять текстовые материалы с такими эффектами, и в этом разделе мы рассмотрим несколько наиболее распространенных.</span></span></div> + +<div class="trans-verified-button-small" dir="ltr"></div> +</div> + +<h3 id="Акцент">Акцент</h3> + +<p><span id="result_box" lang="ru"><span>Когда мы хотим добавить акцент в разговорный язык, мы подчеркиваем определенные слова, тонко изменяя смысл того, что мы говорим.</span> <span>Точно так же на письменном языке мы склонны подчеркивать слова, выделяя их <em>курсивом</em>.</span> <span>Например, следующие два предложения имеют разные значения.</span></span></p> + +<p><span class="short_text" id="result_box" lang="ru"><span>Я рад, что ты не опоздал.</span></span></p> + +<p><span class="short_text" id="result_box" lang="ru"><span>Я <em>рад</em>, что ты не <em>опоздал</em>.</span></span></p> + +<p><span id="result_box" lang="ru"><span class="alt-edited">В первом предложении звучит искреннее облегчение, что человек не опоздал. Во втором, напротив, звучит сарказм или пассивная агрессия: так выражена </span></span><span lang="ru"><span class="alt-edited">досада от того, что человек немного опоздал.</span></span></p> + +<p><span id="result_box" lang="ru"><span>В таких случаях в HTML используется элемент {{htmlelement ("em")}} (выделение).</span> <span>Кроме того, чтобы сделать документ более интересным для чтения, они распознаются программами, считывающими с экрана, и произносятся другим тоном.</span> <span>Браузеры стилизуют это по умолчанию курсивом, но вы можете не использовать этот тег, чтобы получить курсив.</span> <span>Для выделения курсивом вы можете использовать элемент {{htmlelement ("span")}} и CSS, или, возможно, элемент {{htmlelement ("i")}} (смотрите ниже).</span></span></p> + +<pre class="brush: html notranslate"><p>Я <em>рад</em>, что ты не <em>опоздал</em>.</p></pre> + +<h3 id="Важное_значение"><span class="short_text" id="result_box" lang="ru"><span>Важное значение</span></span></h3> + +<p><span id="result_box" lang="ru"><span>Чтобы подчеркнуть важные слова, мы склонны подчеркивать их в устной речи и <strong>выделять жирным</strong> на письменном языке.</span> <span>Например:</span></span></p> + +<p><span id="result_box" lang="ru"><span>Эта жидкость <strong>очень токсична</strong>.</span><br> + <br> + <span>Я рассчитываю на вас.</span> <span><strong>Не опаздывай</strong>!</span></span></p> + +<p><span id="result_box" lang="ru"><span>В таких случаях в HTML используется элемент {{htmlelement ("strong")}} (важное значение).</span> <span>Помимо того, что документ становится более полезным, они распознаются программами, считывающими с экрана, и говорят другим тоном.</span> <span>Браузеры стилизуют это как полужирный текст по умолчанию, но вы можете не использовать этот тег, чтобы получить</span></span><span lang="ru"><span> жирный шрифт.</span> <span>Для получения жирного шрифта вы можете использовать элемент {{htmlelement ("span")}} и CSS, или, возможно, элемент {{htmlelement ("b")}} (</span></span><span id="result_box" lang="ru"><span>смотрите ниже</span></span><span lang="ru"><span>).</span></span></p> + +<pre class="brush: html notranslate"><p>Эта жидкость <strong>очень токсична</strong>.</p> + +<p>Я рассчитываю на тебя. <strong>Не </strong>опаздывай!</p></pre> + +<p><span id="result_box" lang="ru"><span>При желании вы можете вложить важные и акцентированные слова друг в друга:</span></span></p> + +<pre class="brush: html notranslate"><p>Эта жидкость <strong>очень токсична</strong> — +если ты выпьешь её, <strong>то можешь<em>умереть</em></strong>.</p></pre> + +<h3 id="Активное_изучение_Давайте_будем_важны!">Активное изучение: <span class="short_text" id="result_box" lang="ru"><span>Давайте будем важны!</span></span></h3> + +<p><span id="result_box" lang="ru"><span>В этом разделе активного обучения мы предоставили редактируемый пример.</span> <span>Внутри него мы хотели бы, чтобы вы попытались добавить акцент и большую важность для слов, которые, по вашему мнению, им нужны, просто для того, чтобы попрактиковаться.</span></span></p> + +<div class="hidden"> +<h6 id="Playable_code_5">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Результат</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label">Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).</p> + +<textarea id="code" class="input" style="min-height: 200px; width: 95%"><h1>Важное объявление</h1> +<p>9 января 2010 года, в воскресенье, +банда вандалов была обнаружена за кражей нескольких +садовых гномов из торгового центра в центре Милуоки. На них были +надеты зелёные спортивные костюмы и глупые шляпы, и, +по-видимому, они были в нетрезвом состоянии. Если у кого-то +есть какая-либо информация об этом инциденте, пожалуйста, +позвоните в полицию немедленно.</p></textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<h1>Важное объявление</h1>\n<p><strong>9 января 2010 года, в воскресенье</strong>, банда <em>вандалов</em> была обнаружена за кражей <strong><em>нескольких</em> садовых гномов</strong> торговом центре в центре <strong>Милуоки</strong>. На них были надеты <em>зелёные спортивные костюмы</em> и <em>глупые шляпы</em>, и, по-видимому, они были в нетрезвом состоянии. Если у кого-то есть <strong>какая-либо</strong> информация об этом инциденте, пожалуйста, позвоните в полицию <strong>немедленно</strong>.</p>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_5', 700, 500) }}</p> + +<h3 id="Курсив_жирный_шрифт_подчеркивание...">Курсив, жирный шрифт, подчеркивание...</h3> + +<div id="gt-res-content"> +<div class="trans-verified-button-small" dir="ltr" id="gt-res-dir-ctr"><span id="result_box" lang="ru"><span>Элементы, которые мы обсуждали до сих пор, имеют четкую привязку к семантике.</span> <span>Ситуация с {{htmlelement ("b")}}, {{htmlelement ("i")}} и {{htmlelement ("u")}} несколько сложнее.</span> <span>Они появились в эпоху, когда CSS поддерживался плохо или вообще не поддерживался</span></span><span lang="ru"><span>, чтобы люди могли писать <strong>жирный </strong>текст, <em>курсив </em>или <u>подчеркнутый</u> текст.</span> <span>Такие элементы, которые влияют только на внешний вид, а не на семантику, известны как элементы представления и больше не должны использоваться, поскольку, как мы видели ранее, семантика очень важна для доступности людям с ограниченными возможностями, SEO и так далее.</span></span></div> + +<div class="trans-verified-button-small" dir="ltr"></div> +</div> + +<p><span id="result_box" lang="ru"><span>HTML5 переопределил <b>, <i> и <u> с новыми, несколько запутанными, семантическими ролями.</span></span></p> + +<p><span id="result_box" lang="ru"><span class="alt-edited">Вот хорошее правило: предпочтительней использовать <b>, <i> или <u> для передачи значения, традиционно передаваемого жирным шрифтом, курсивом или подчеркиванием, при условии, что нет более подходящего элемента. Тем не менее, всегда важно сохранить менталитет доступности. Концепция курсива не очень помогает людям, использующим устройства для чтения с экрана, или людям, использующим систему письма, отличную от латинского алфавита.</span></span></p> + +<ul> + <li>{{HTMLElement ('i')}} используется для передачи значения, традиционно передаваемого курсивом: иностранные слова, таксономические обозначения, технические термины, мысли ...</li> + <li><span id="result_box" lang="ru"><span>{{HTMLElement ('b')}} используется для передачи значения, традиционно передаваемого жирным шрифтом: ключевые слова, названия продуктов, предложения ...</span></span></li> + <li><span id="result_box" lang="ru"><span>{{HTMLElement ('u')}} используется для передачи значения, традиционно передаваемого подчеркиванием: имя собственное</span></span><span lang="ru"><span>, орфографическая ошибка ...</span></span></li> +</ul> + +<div class="note"> +<p><span id="result_box" lang="ru"><span>Предупреждение о подчеркивании:<strong> люди сильно ассоциируют подчеркивание с гиперссылками</strong>.</span> <span>Поэтому в Интернете лучше всего подчеркнуть только ссылки.</span> <span>Используйте элемент <u>, когда он семантически подходит, но подумайте о том, чтобы использовать CSS для изменения подчеркивания по умолчанию для чего-то более подходящего в Интернете.</span> <span>Пример ниже иллюстрирует, как это можно сделать.</span></span></p> +</div> + +<pre class="brush: html notranslate"><!-- Научные наименования --> +<p> + Колибри обыкновенный (<i>архилоус обыкновенный</i>) — +наиболее часто встречающийся вид колибри в северо-восточной Америке. +</p> + +<!-- Иностранные слова --> +<p> + Случился прилив иностранных слов, таких как <i lang="uk-latn">vatrushka</i>, + <i lang="id">nasi goreng</i> и <i lang="fr">soupe à l'oignon</i>. +</p> + +<!-- Явно неправильное произношение или написание --> +<p> + Когда-нибудь я узнаю, как <u>гаварить</u> без ошибок. +</p> + +<!-- Выделение ключевых слов в инструкциях --> +<ol> + <li> + <b>Отрежьте</b> два ломтика хлеба. + </li> + <li> + <b>Добавьте</b> кусочек помидора и лист латука между ломтями хлеба. + </li> +</ol></pre> + +<h2 id="Заключение">Заключение</h2> + +<p><span id="result_box" lang="ru"><span>Вот и всё!</span> <span>Эта статья должна была дать вам хорошее представление о том, как начать разметку текста в HTML, и познакомить вас с некоторыми из наиболее важных элементов в этой области.</span> <span>В этой области есть намного больше семантических элементов, и мы рассмотрим их в нашей статье «Больше семантических элементов» позже в курсе.</span> <span>В следующей статье мы подробно рассмотрим, как </span></span><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">создавать гиперссылки</a><span lang="ru"><span>, возможно, самый важный элемент в Интернете. </span></span></p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></li> +</ul> diff --git a/files/ru/learn/html/введение_в_html/index.html b/files/ru/learn/html/введение_в_html/index.html new file mode 100644 index 0000000000..1ecf1eb84a --- /dev/null +++ b/files/ru/learn/html/введение_в_html/index.html @@ -0,0 +1,67 @@ +--- +title: Введение в HTML +slug: Learn/HTML/Введение_в_HTML +tags: + - HTML + - Введение + - Для чайников + - Заголовок + - Начинающим + - Новичкам + - Основы HTML + - Семантика + - Ссылки + - Структура + - Текст +translation_of: Learn/HTML/Introduction_to_HTML +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">По сути, {{glossary("HTML")}} довольно простой язык, состоящий из элементов, которые могут быть применены к частям текста, чтобы придавать им различные значения (Это абзац? Это маркированный список? Это часть таблицы?), разделять документ на логические секции (есть ли у документа шапка? три столбца с контентом? меню навигации?) и добавлять контент на Вашу страницу, такой как фото и видео. Этот модуль расскажет Вам о первых двух возможностях HTML и научит фундаментальным концепциям и синтаксису, которые вам нужно знать, чтобы понять HTML.</p> + +<h2 id="Необходимые_условия">Необходимые условия</h2> + +<p>Чтобы начать изучение этого модуля, вам не нужны никакие знания HTML, но вы должны иметь хотя бы базовые навыки обращения с компьютером и навыки пассивного использования Веба (т.е просто смотря на него, потребляя контент). У вас должна быть базовая рабочая среда, описанная в разделе <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F">Установка базового програмного обеспечения</a>), а также понимание, как создавать и управлять файлами, что подробно описано в статье <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Работа с файлами</a> — обе статьи являются частью нашего модуля <a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web">Начало работы с сетью</a>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: если вы работаете на компьютере/планшете/другом устройстве, с отсутствием возможности создания собственных файлов, вы можете испробовать примеры кода (большинство) в онлайн-редакторах кода, таких как <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble.</a></p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<p>Этот модуль содержит следующие статьи, которые помогут изучить всю основную теорию HTML и предоставят широкие возможности для проверки некоторых навыков.</p> + +<dl> + <dt><a href="/ru/docs/Learn/HTML/Введение_в_HTML/Начало_работы">Начало работы с HTML</a></dt> + <dd>Охватывает базовые основы HTML, чтобы вы начали изучение - мы опишем элементы, атрибуты и все другие важные термины, о которых вы, возможно, уже слышали, а также где и как они располагаются в языке. Мы также покажем, структуру HTML элемента, как устроена типичная страница HTML, и объясним другие важные языковые особенности. По ходу мы будем играть с HTML так, чтобы вам было интересно!</dd> + <dt><a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></dt> + <dd>Заголовок HTML — это часть документа, которая <strong>не отображается</strong> в браузере при загрузке страницы. Он содержит информацию, такую как: страница {{htmlelement("title")}}, ссылки на {{glossary("CSS")}} (если вы хотите стилизовать свой HTML при помощи CSS), ссылки на пользовательские значки и метаданные (которые представляют собой данные о HTML, например, кто его написал или важные ключевые слова, которые описывают документ).</dd> + <dt><a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></dt> + <dd>Основной задачей HTML является придание тексту значения <strong>(</strong>также известно, как <strong>семантика</strong>), чтобы браузер знал, как его правильно отображать. В этой статье расматривается то, как использовать HTML, чтобы разбить блок текста на структуру из заголовков и абзацев, добавить акцент/значение слов, создать списки и многое другое.</dd> + <dt><a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></dt> + <dd>Гиперссылки очень важны — ведь именно они делают интернет интернетом. В этой статье описан синтаксис, необходимый для создания ссылок, а также описано их наилучшее применение на практике.</dd> + <dt><a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></dt> + <dd>Существует множество других элементов HTML для редактирования текста, про которые мы вам не рассказали в статье <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a>. Описанные здесь элементы менее известны, но о них также полезно знать. Здесь вы узнаете о разметке цитат, списках описания, компьютерном коде и другом сопутствующем тексте, нижнем и верхнем индексах, контактной информации и многом другом.</dd> + <dt><a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></dt> + <dd>Помимо определения отдельных частей страницы (таких как "абзац" или "изображение"), HTML также используется для определения отдельных зон веб-сайта (таких как "шапка", "меню навигации", "столбец с основным содержимым".) В этой статье рассматривается, как планировать базовую структуру веб-сайта и писать HTML для представления этой структуры.</dd> + <dt><a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></dt> + <dd>Писать на HTML хорошо, но что, если что-то идет не так, и вы не можете найти место ошибки в коде? В этой статье вы познакомитесь с некоторыми инструментами, которые могут Вам помочь.</dd> +</dl> + +<h2 id="Оценка">Оценка</h2> + +<p>Следующие задания проверят ваше понимание основ HTML, описанных в приведенных выше руководствах.</p> + +<dl> + <dt><a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></dt> + <dd>Все мы рано или поздно учимся писать письма; также это полезеный тест, для проверки ваших навыков форматирования текста! Поэтому, в этом задании вам будет предоставлено письмо для разметки.</dd> + <dt><a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></dt> + <dd>Этот тест проверит вашу способность использовать HTML для структурирования простой страницы, которая содержит шапку ("хедер") , нижний колонтитул ("футер"), меню навигации, основное содержимое и боковую панель.</dd> +</dl> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<dl> + <dt><a href="https://teach.mozilla.org/activities/web-lit-basics/">Основы интернет-грамотности</a></dt> + <dd>Отличный фундаментальный курс Mozilla, который дает множество тестов, проверяющих знания, о которых мы говорили в модуле <em>Введение в HTML. </em>Учащиееся знакомятся с чтением, письмом и использованием сети в модуле из 6 частей. Откройте для себя основы Интернета через производство и сотрудничество.</dd> +</dl> diff --git a/files/ru/learn/html/введение_в_html/marking_up_a_letter/index.html b/files/ru/learn/html/введение_в_html/marking_up_a_letter/index.html new file mode 100644 index 0000000000..c9ede9d116 --- /dev/null +++ b/files/ru/learn/html/введение_в_html/marking_up_a_letter/index.html @@ -0,0 +1,101 @@ +--- +title: Разметка письма +slug: Learn/HTML/Введение_в_HTML/Marking_up_a_letter +tags: + - HTML +translation_of: Learn/HTML/Introduction_to_HTML/Marking_up_a_letter +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">Мы все учимся писать письма рано или поздно; это также хороший способ испытать наши навыки форматирования! В этом задании у вас будет письмо для проверки ваших навыков форматирования текста HTML, использования гиперссылок и элемента <code><head></code>.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Знания:</th> + <td> + <p>Перед выполнением этого задания вы должны пройти <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a>, <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a>, <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a>, <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a>, и <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a>.</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Проверить базовые и продвинутые навыки HTML форматирования и работы с гиперссылками, и знания о содержимом HTML тега <code><head></code>.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Отправная_точка">Отправная точка</h2> + +<p>Для начала задания, вы должны <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/marking-up-a-letter-start/letter-text.txt">скачать текст</a>, который вам надо отформатировать, и <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/marking-up-a-letter-start/css.txt">CSS стиль</a>, который вы должны подключить к вашему HTML. Создайте .html файл используюя текстовый редактор, которым вы пользуетесь (или воспользуйтесь онлайн редактороми, таким как <a class="external external-icon" href="http://jsbin.com/">JSBin</a> или <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a>).</p> + +<h2 id="Описание_проекта">Описание проекта</h2> + +<p>В этом проекте, ваша задача - отформатировать письмо, которое должно быть размещено во внутренней сети университета. Это письмо - ответ исследователя будущему PhD студенту о его заявлении на работу в университете.</p> + +<p>Блочные элементы / структура:</p> + +<ul> + <li>Вы должны корректно структурировать весь документ, включив в него элементы doctype, и {{htmlelement("html")}}, {{htmlelement("head")}} и {{htmlelement("body")}}.</li> + <li>Письмо в целом должно быть размечено используя параграфы и заголовки, за исключением следующих пунктов - один заголовок верхнего уровня (начинается на "Re:") и три заголовка второго уровня.</li> + <li>Даты начала семестра, изучения предметов и экзотических танцев должны быть помечены используя соответсвующие типы списков.</li> + <li>Два адреса должны быть помещены внутри элементов {{htmlelement("address")}}. Каждая строка адреса должна находиться на новой строке, но не быть новым параграфом.</li> +</ul> + +<p>Строчные элементы:</p> + +<ul> + <li>Имена отправителя и получателя (как и "Tel" и "Email") должны быть выделены жирным.</li> + <li>Четырем датам в документе необходимо выбрать правильные элементы содержащие машинно-читаемые даты.</li> + <li>Первый адрес и первая дата в письме должны иметь аттрибут <code>class</code> со значением <code>"sender-column"</code>; CSS стиль, который вы добавите позже, позволит выравнять по правому боку, как оно и должно быть в классической разметке письма.</li> + <li>Пять акронимов/аббревиатур в главном тексте письма должны быть размечены, чтобы предоставить подсказки для каждого акронима/аббревиатуры.</li> + <li>Шесть под/надстрочных элементов должны быть оформлены корректно в химической формуле, как и числа 10<sup>3</sup> и 10<sup>4 </sup>(степень числа должна быть над числом).</li> + <li>Для разметки символов градуса и умножения воспользуйтесь <a href="https://ru.wikipedia.org/wiki/Мнемоники_в_HTML">справкой</a>.</li> + <li>Постарайтесь выделить как минимум два нужных по смыслу слова в тексте жирным.</li> + <li>Есть два места, где следует разместить гиперссылки; добавьте нужные ссылки с заголовками. В качестве адреса для ссылок используйте http://example.com.</li> + <li>Девиз университета и цитата должны быть размечены соответствующими элементами.</li> +</ul> + +<p>Заголовок документа:</p> + +<ul> + <li>Кодировка документа должна быть указана как utf-8 с использованием соответствующего мета-тега.</li> + <li>Автор письма должен быть указан в соответствующем мета-теге.</li> + <li>Предоставленный CSS должен быть включён в соответствующий тег.</li> +</ul> + +<h2 id="Советы_и_подсказки">Советы и подсказки</h2> + +<ul> + <li>Проверяйте свой HTML в <a href="https://validator.w3.org/">валидаторе W3C</a> — писать валидный код здорово!</li> + <li>Для задания не нужно знать CSS — просто укажите CSS из задания в документе.</li> +</ul> + +<h2 id="Пример">Пример</h2> + +<p>Это скриншот размеченного письма:</p> + +<p><img alt="Example" src="https://mdn.mozillademos.org/files/15811/Letter%20screengrab%202.png" style="border: 1px solid black; display: block; height: 1858px; margin: 0px auto; width: 931px;"></p> + +<h2 id="Оценка">Оценка</h2> + +<p>Если вам дали это задание на каком-то курсе, просто передайте свою страницу для проверки преподавателю. Если вы учитесь сами, обратитесь на <a href="https://discourse.mozilla.org/t/marking-up-a-letter-assignment/24676">форум, в тему этого задания</a>, или по тегу <a href="irc://irc.mozilla.org/mdn">#mdn</a> в нашем IRC-канале (<a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>). Сделайте это задание сами — вам некого обманывать, кроме себя самого.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></li> +</ul> diff --git a/files/ru/learn/html/введение_в_html/structuring_a_page_of_content/index.html b/files/ru/learn/html/введение_в_html/structuring_a_page_of_content/index.html new file mode 100644 index 0000000000..7ade9310c1 --- /dev/null +++ b/files/ru/learn/html/введение_в_html/structuring_a_page_of_content/index.html @@ -0,0 +1,101 @@ +--- +title: Структурируем страницу +slug: Learn/HTML/Введение_в_HTML/Structuring_a_page_of_content +tags: + - HTML +translation_of: Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/HTML/Introduction_to_HTML/Marking_up_a_letter", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">Разметить страницу так, чтобы к ней было просто применить CSS — первое, чему должен научиться будущий веб-разработчик. В этом задании вам придется подумать о том, как должна выглядеть страница, и подобрать подходящую семантическую разметку.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Что нужно знать:</th> + <td>Вам пондобятся навыки из всего курса. Особое внимание уделите разделу <a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Проверить знания структуры веб-страницы и ее перевода в разметку.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Отправная_точка">Отправная точка</h2> + +<p>Чтобы начать это, вы должны перейти и скачать <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/structuring-a-page-of-content-start/assets.zip?raw=true">архив содержаший все начальные активы</a>. Архив содержит:</p> + +<ul> + <li>HTML, где вам нужно добавить структурную разметку.</li> + <li>CSS для стилизации вашей разметки.</li> + <li>Изображения, которые используются на странице.</li> +</ul> + +<p>Создайте пример на вашем локальном компьютере или, альтернативно, используйте сайт, например <a class="external external-icon" href="http://jsbin.com/">JSBin</a> или <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a> для исследования.</p> + +<h2 id="Краткое_описание_проекта">Краткое описание проекта</h2> + +<p>Для этого проекта ваша задача - взять контент для домашней страницы веб-сайта наблюдения за птицами и добавить к нему структурные элементы, чтобы он мог использовать макет страницы. Он должен иметь:</p> + +<ul> + <li>Заголовок, охватывающий всю ширину сайта, содержащий основное название страницы, логотип сайта и меню навигации. Заголовок и логотип появляются рядом друг с другом, когда применяется стилизация, и навигация появляется ниже этих двух элементов.</li> + <li>Основная область содержимого, содержащая два столбца - основной блок, содержащий текст приветствия, и боковую панель для размещения миниатюр изображений.</li> + <li>Нижний колонтитул, содержащий информацию об авторских правах и разработчиках.</li> +</ul> + +<p>Вам необходимо добавить подходящую обертку для:</p> + +<ul> + <li>Заголовока</li> + <li>Меню навигации</li> + <li>Основного содержимого</li> + <li>Приветственного текста</li> + <li>Боковой панели изображения</li> + <li>Нижнего колонтитула</li> +</ul> + +<p>Вы также должны:</p> + +<ul> + <li>Примените предоставленный CSS к странице, добавив еще один элемент {{htmlelement ("link")}} чуть ниже существующего, указанного в начале.</li> +</ul> + +<h2 id="Советы_и_подсказки">Советы и подсказки</h2> + +<ul> + <li>Используйте <a href="https://validator.w3.org/">W3C HTML validator</a> для проверки вашего HTML; вы получите бонусные баллы, если он будет проверять как можно больше (строка «googleapis» используется для импорта пользовательских шрифтов на страницу из службы Google Fonts, она не проверяет, но не беспокойтесь об этом слишком много - валидатор - полезный инструмент, но 100% проверка является идеальным, а не полностью необходимым).</li> + <li>Вам не нужно знать CSS, чтобы сделать эту оценку; вам просто нужно поместить предоставленный CSS внутри HTML-элемента.</li> + <li>Предоставленный CSS разработан таким образом, что при добавлении правильных структурных элементов в разметку они будут отображаться зелеными на отображаемой странице.</li> + <li>Если вы застряли и не можете понять, какие элементы куда помещать, часто помогает вывести простую блок-схему макета страницы и сделать надписи на элементах, которые, по вашему мнению, должны обернуть каждый блок.</li> +</ul> + +<h2 id="Пример">Пример</h2> + +<p>Следующий скриншот показывает пример того, как может выглядеть домашняя страница после маркировки.</p> + +<p><img alt='The finished example for the assessment; a simple webpage about birdwatching, including a heading of "Birdwatching", bird photos, and a welcome message' src="https://mdn.mozillademos.org/files/12449/example-page.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="Оценивание">Оценивание</h2> + +<p>Если вам дали это задание на каком-то курсе, просто передайте свою страницу для проверки преподавателю. Если вы учитесь сами, обратитесь на <a href="https://discourse.mozilla.org/t/structuring-a-page-of-content-assessment/24678">форум, задав тему обсуждения этого упражнения, или в IRC-канале #mdn в IRC Mozilla</a>, или в IRC-канале <a href="irc://irc.mozilla.org/mdn">#mdn</a> в <a href="https://wiki.mozilla.org/IRC">IRC Mozilla</a>. Попробуйте выполнить задание сами, ведь Вам некого обманывать, кроме себя самого!</p> + +<p>{{PreviousMenu("Learn/HTML/Introduction_to_HTML/Marking_up_a_letter", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></li> +</ul> diff --git a/files/ru/learn/html/введение_в_html/the_head_metadata_in_html/index.html b/files/ru/learn/html/введение_в_html/the_head_metadata_in_html/index.html new file mode 100644 index 0000000000..dfb2840569 --- /dev/null +++ b/files/ru/learn/html/введение_в_html/the_head_metadata_in_html/index.html @@ -0,0 +1,300 @@ +--- +title: Что внутри "head"? Метаданные в HTML +slug: Learn/HTML/Введение_в_HTML/The_head_metadata_in_HTML +tags: + - HTML + - Meta + - favicon + - head + - lang + - metadata + - Для начинающих + - Заголовок + - Руководство + - иконка + - метаданные + - язык +translation_of: Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Getting_started", "Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p>Элемент {{glossary("Head", "head")}} HTML-документа не отображается на странице в веб-браузере. Он содержит такую информацию, как:</p> + +<ul> + <li>{{htmlelement("title", "заголовок (title)")}} страницы</li> + <li>ссылки на файлы {{glossary("CSS")}} (если вы хотите применить к вашему HTML стили CSS)</li> + <li>ссылки на иконки</li> + <li>другие метаданные (данные о HTML: автор и важные ключевые слова, описывающие документ.)</li> +</ul> + +<p>В этой статье мы рассмотрим всё вышеперечисленное и многое другое, чтобы дать вам хорошую основу для работы с разметкой.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные требования:</th> + <td>Базовое знакомство с HTML , описанное в <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Начало работы с HTML</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Узнать о заголовке HTML, его значении, важнейших элементах, которые содержатся в нём, и о том, как он может повлиять на HTML-документ.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_<head>">Что такое <head>?</h2> + +<p>Давайте снова посмотрим на <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B#%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_HTML_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0">HTML-документ из прошлой статьи</a>:</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Моя тестовая страница</title> + </head> + <body> + <p>Это — моя страница</p> + </body> +</html></pre> + +<p>Содержимое {{htmlelement("head")}}, в отличие от содержимого элемента {{htmlelement("body")}}, не отображается на странице. Задача <head> — хранить {{glossary("Metadata", "метаданные")}} документа. В приведенном выше примере <head> совсем небольшой:</p> + +<pre class="brush: html notranslate"><head> + <meta charset="utf-8"> + <title>Моя тестовая страница</title> +</head></pre> + +<p>Однако на больших страницах блок <head> может быть довольно объемным. Попробуйте зайти на какие-нибудь из ваших любимых сайтов и посмотреть содержимое <head> с помощью <a href="/ru/docs/Learn/Discover_browser_developer_tools">инструментов разработчика</a>. Наша цель сейчас — не в том, чтобы показать вам, как использовать всё, что только можно добавить в head, а дать представление и научить вас, как использовать основные элементы. Давайте начнем.</p> + +<h2 id="Название_страницы_title">Название страницы (title)</h2> + +<p>Мы уже видели, как работает элемент {{htmlelement("title")}}: его используют для добавления заголовка (названия страницы) в документ. Элемент {{htmlelement("h1")}} тоже иногда назвают заголовком страницы. Но это разные вещи!</p> + +<ul> + <li>Элемент {{htmlelement("h1")}} виден на странице, открытой в браузере, — его используют <strong>один раз на странице</strong>, чтобы выделить название содержимого. Это может быть название истории, заголовок новости или что-то в этом роде.</li> + <li>Элемент {{htmlelement("title")}} — метаданные, название всего HTML-документа, а не заголовок внутри его содержимого. </li> +</ul> + +<h3 id="Активное_изучение_разбор_простого_примера">Активное изучение: разбор простого примера</h3> + +<ol> + <li>Чтобы приступить к активному изучению, скачайте страницу <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/title-example.html">title-example.html</a> из нашего GitHub-репозитория. Это можно сделать двумя способами: + + <ol> + <li>Скопируйте и вставьте код страницы в новый текстовый файл в своём редакторе кода, затем сохраните его в любом удобном месте.</li> + <li>Нажмите на странице кнопку "Raw", нажмите <em>Файл > Сохранить Как...</em> в меню браузера и выберите папку для сохранения.</li> + </ol> + </li> + <li>Откройте файл в браузере. Вы увидите что-то вроде этого: + <p><img alt="A simple web page with the title set to <title> element, and the <h1> set to <h1> element." src="https://mdn.mozillademos.org/files/12323/title-example.png" style="display: block; margin: 0 auto;">Теперь должно стать совершенно ясно, в чём разница между <code><h1></code> и <code><title></code>!</p> + </li> + <li>Откройте код страницы в редакторе, измените содержимое элементов и обновите страницу в браузере. Развлекайтесь!</li> +</ol> + +<p>Содержимое элемента <code><title></code> используется и в других местах. Например, при добавлении страницы в избранное (<em>Bookmarks > Bookmark This Page</em> в Firefox), текст из <code><title></code> предлагается в качестве названия закладки.</p> + +<p><img alt="A webpage being bookmarked in firefox; the bookmark name has been automatically filled in with the contents of the <title> element " src="https://mdn.mozillademos.org/files/12337/bookmark-example.png" style="display: block; margin: 0 auto;"></p> + +<p>Текст из <code><title></code> также появляется в результатах поиска, как мы скоро увидим.</p> + +<h2 id="Метаданные_Элемент_<meta>">Метаданные: Элемент <meta></h2> + +<p>Метаданные — данные, которые описывают данные. У HTML есть «официальное» место для метаданных документа — элемент {{htmlelement("meta")}}. Конечно, другие вещи, о которых мы говорим в этой статье, тоже можно назвать метаданными. Существует множество разновидностей <code><meta></code>. Не станем пытаться охватить их все сразу — так недолго и запутаться, а рассмотрим несколько самых популярных, чтобы разобраться, что к чему.</p> + +<h3 id="Указываем_кодировку_текста_документа">Указываем кодировку текста документа</h3> + +<p>В заголовке примера выше есть следующая строка:</p> + +<pre class="brush: html notranslate"><meta charset="utf-8"></pre> + +<p>В этом элементе указана кодировка документа — набор символов, которые в нём можно использовать . <code>utf-8</code> — универсальный набор символов, который включает почти все символы со всех языков человечества. Такая веб-страница сможет работать с любым языком. Установить эту кодировку на всех веб-страницов, которые вы создаёте — отличная идея! Страница в такой кодировке прекрасно отображает как английские, так и японские символы:</p> + +<p><img alt="a web page containing English and Japanese characters, with the character encoding set to universal, or utf-8. Both languages display fine," src="https://mdn.mozillademos.org/files/12343/correct-encoding.png" style="display: block; margin: 0 auto;">Если использовать, скажем, кодировку <code>ISO-8859-1</code> (набор символов для латиницы), текст страницы испортится:</p> + +<p><img alt="a web page containing English and Japanese characters, with the character encoding set to latin. The Japanese characters don't display correctly" src="https://mdn.mozillademos.org/files/12341/bad-encoding.png" style="display: block; height: 365px; margin: 0px auto; width: 604px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Некоторые браузеры (например, Chrome) автоматически исправляют неправильную кодировку, поэтому, в зависимости от используемого вами браузера, вы можете не увидеть эту проблему. Несмотря на это вам всё равно необходимо указывать кодировку UTF-8 для вашей страницы, чтобы избежать возможных проблем в других браузерах.</p> +</div> + +<h3 id="Активное_изучение_экспериментируем_с_символьными_кодировками">Активное изучение: экспериментируем с символьными кодировками</h3> + +<p>Чтобы проверить это, вернитесь к HTML из примера <code><title></code> (странице <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/title-example.html">title-example.html</a>), поменяйте meta charset на <code>ISO-8859-1</code> и попробуйте написать что-нибудь на японском или русском. Вот текст из нашего примера (кстати, там написано <em>«рис горячий»</em>):</p> + +<pre class="brush: html notranslate"><p>Пример на японском: ご飯が熱い。</p></pre> + +<h3 id="Указываем_автора_и_описание">Указываем автора и описание</h3> + +<p>У элементов <code><meta></code> часто есть атрибуты <code>name</code> и <code>content</code>:</p> + +<ul> + <li><code>name</code> — тип элемента, то есть какие именно метаданные он содержит.</li> + <li><code>content</code> — сами метаданные.</li> +</ul> + +<p>Два полезных элемента метаданных — указание автора страницы и краткое описание её содержимого. Рассмотрим эти элементы на примере:</p> + +<pre class="brush: html notranslate"><meta name="author" content="Крис Миллс"> +<meta name="description" content="Задача MDN — в том, чтобы обучить +новичков всему тому, что нужно им для разработки веб-сайтов и приложений."></pre> + +<p>По указанному имени автора (author) можно найти человека, который написал страницу, и связаться с ним. Некоторые системы управления содержимым (CMS) автоматически обрабатывают эту информацию и делают её доступной для таких целей.</p> + +<p>Краткое описание (description) содержимого страницы учитывается поисковыми системами при совпадении ключевых слов. Такое называют <a href="/en-US/docs/Glossary/SEO">поисковой оптимизацией</a>, или {{glossary("SEO")}}.</p> + +<h3 id="Активное_изучение_как_поисковые_системы_используют_описание">Активное изучение: как поисковые системы используют описание</h3> + +<p>Описание из <code><meta name="description"></code> используется на страницах поисковой выдачи. Проведём небольшое исследование такого сценария.</p> + +<ol> + <li>Перейдите на<a href="https://developer.mozilla.org/en-US/"> главную страницу Mozilla Developer Network</a>.</li> + <li>Откройте исходный код страницы (кликните правой кнопкой мыши и выберите <em>Просмотреть код</em> в контекстном меню.)</li> + <li>Найдите тег meta с описанием. Он выглядит так: + <pre class="brush: html notranslate"><meta name="description" content="Веб-документация на MDN +предоставляет собой информацию об открытых веб-технологиях, +включая HTML, CSS и различные API для веб-сайтов и +прогрессивных веб-приложений. Также на сайте содержатся материалы +для разработчиков о таких продуктах Mozilla, как Инструменты разработчика Firefox."></pre> + </li> + <li>Теперь найдите "Mozilla Developer Network" в своём поисковике (мы использовали Google). Обратите внимание, что описание и название из <code><meta></code> и <code><title></code> используется в результатах поиска, — мы не зря указали их!</li> +</ol> + +<p><img alt="Результат поиска в Google" src="https://mdn.mozillademos.org/files/17061/Updated_search_result__ru.jpg" style="border-style: solid; border-width: 1px; height: 542px; width: 819px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Google также показывает важные страницы MDN под ссылкой на главную страницу. Такие ссылки называются sitelinks, и их можно настроить через <a href="http://www.google.com/webmasters/tools/">Google Search Console</a>, чтобы пользователи могли сразу перейти к ним со страницы поиска.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Многие типы <code><meta></code> больше не используются. Так, поисковые системы больше не используют данные из элемента <code><meta type="keywords" content="ваши, ключевые, слова, введите, здесь"></code>, в котором указывали ключевые слова, по которым можно найти страницу: спамеры засовывали туда все слова, какие могли придумать, чтобы их сайты почаще появлялись в поиске.</p> +</div> + +<h3 id="Другие_виды_метаданных">Другие виды метаданных</h3> + +<p>В сети вы найдете также другие типы метаданных. Многие из них — это собственные форматы, созданные для предоставления определенным сайтам (например, социальных сетей) специальной информации, которую они могут использовать.</p> + +<p>Например, <a href="https://ruogp.me/">Протокол Open Graph</a> создан Facebook чтобы предоставить сайтам дополнительные возможности использования метеданных. В исходном коде MDN Web Docs вы можете найти строки:</p> + +<pre class="brush: html notranslate"><meta property="og:image" content="https://wiki.developer.mozilla.org/static/img/opengraph-logo.72382e605ce3.png"> +<meta property="og:description" content="Веб-документация на MDN предоставляет +собой информацию об открытых веб-технологиях, включая HTML, CSS и различные API для веб-сайтов +и прогрессивных веб-приложений. Также на сайте содержатся материалы для разработчиков о таких +продуктах Mozilla, как Инструменты разработчика Firefox."> +<meta property="og:title" content="MDN Web Docs"></pre> + +<p>Один из результатов добавления этих метеданных в том, что когда вы добавите ссылку MDN Web Docs на facebook, она отобразится с изображением и описанием, улучшая опыт взаимодействия <em><a href="https://ru.wikipedia.org/wiki/%D0%9E%D0%BF%D1%8B%D1%82_%D0%B2%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D1%8F">(User eXperience, UX</a>)</em>.</p> + +<p><img alt="Open graph protocol data from the MDN homepage as displayed on facebook, showing an image, title, and description." src="https://mdn.mozillademos.org/files/12349/facebook-output.png" style="display: block; margin: 0 auto;">У Twitter также есть собственный формат метаданных, с помощью которого создается аналогичный эффект, при отображении URL сайта на twitter.com:</p> + +<pre class="brush: html notranslate"><meta name="twitter:title" content="MDN Web Docs"></pre> + +<h2 id="Добавление_иконок">Добавление иконок</h2> + +<p>Чтобы добавить своему сайту узнаваемости, можно указать в метаданных разные иконки.</p> + +<p><a href="https://ru.wikipedia.org/wiki/Favicon">Favicon</a>, один из старожилов интернета, стал первой из таких иконок. Браузеры показывают её в заголовке вкладки и в списке избранных страниц.<img alt="The Firefox bookmarks panel, showing a bookmarked example with a favicon displayed next to it." src="https://mdn.mozillademos.org/files/12351/bookmark-favicon.png" style="display: block; margin: 0 auto;"></p> + +<p>Чтобы добавить на страницу favicon:</p> + +<ol> + <li>Сохраните изображение в формате <code>.ico</code> (многие браузеры поддерживают и в более привычных форматах, таких как <code>.gif</code> или <code>.png</code>) в папку со своим документом. Старые браузеры, например, Internet Explorer 6, поддерживают только формат <code>.ico</code></li> + <li>Добавьте ссылку на иконку в <code><head></code> документа: + <pre class="brush: html notranslate"><link rel="shortcut icon" href="favicon.ico" type="image/x-icon"></pre> + </li> +</ol> + +<p>Для разных устройств можно указывать разные иконки. Например, на главной странице MDN:</p> + +<pre class="brush: html notranslate"><!-- Для iPad 3 с Retina-экраном высокого разрешения: --> +<link rel="apple-touch-icon-precomposed" sizes="144x144" href="https://developer.cdn.mozilla.net/static/img/favicon144.a6e4162070f4.png"> +<!-- Для iPhone с Retina-экраном высокого разрешения: --> +<link rel="apple-touch-icon-precomposed" sizes="114x114" href="https://developer.cdn.mozilla.net/static/img/favicon114.0e9fabd44f85.png"> +<!-- Для iPad первого и второго поколения: --> +<link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://developer.cdn.mozilla.net/static/img/favicon72.8ff9d87c82a0.png"> +<!-- Для iPhone, iPod Touch без Retina и устройств с Android 2.1+: --> +<link rel="apple-touch-icon-precomposed" href="https://developer.cdn.mozilla.net/static/img/favicon57.a2490b9a2d76.png"> +<!-- Для других случаев - обычный favicon --> +<link rel="shortcut icon" href="https://developer.cdn.mozilla.net/static/img/favicon32.e02854fdcf73.png"></pre> + +<p>В комментариях указано, для чего используется каждая иконка — например, при добавлении страницы на домашний экран iPad будет использована иконка в высоком разрешении. </p> + +<p>Не беспокойтесь о реализации всех этих типов значков — это довольно продвинутая функция, и мы не станем возвращаться к ней в курсе. Основная цель — показать вам, что это такое, если вы столкнетесь с ними при просмотре исходного кода других веб-сайтов.</p> + +<h2 id="Подключение_CSS_и_JavaScript">Подключение CSS и JavaScript</h2> + +<p>Современные сайты используют {{glossary("CSS")}}, чтобы выглядеть привлекательнее, и добавляют интерактивные функции через {{glossary("JavaScript")}}: видеоплееры, карты, игры. Обычно связянные стили добавляют на страницу через элемент {{htmlelement("link")}}, а скрипты — через элемент {{htmlelement("script")}} .</p> + +<ul> + <li> + <p>Элемент {{htmlelement("link")}} помещают в заголовок документа. У него есть два атрибута: <code>rel="stylesheet"</code> показывает, что мы указываем <em>стиль</em> документа, а в <code>href</code> указан путь к файлу:</p> + + <pre class="brush: html notranslate"><link rel="stylesheet" href="my-css-file.css"></pre> + </li> + <li> + <p>Элемент {{htmlelement("script")}} не обязательно находится в заголовке — на самом деле лучше поместить его в самом конце страницы, прямо перед закрывающем тегом <code></body></code>. Так браузер сначала отобразит саму страницу, а уже затем загрузит и запустит скрипт — иначе скрипт может обратиться к ещё не созданному элементу страницы и сломаться.</p> + + <pre class="brush: html notranslate"><script src="my-js-file.js"></script></pre> + + <p><strong>Примечание</strong>: Элемент <code><script></code> кажется пустым, но это не всегда так, и указывать закрывающий тег обязательно. Вместо того чтобы ссылаться на внешний скрипт, код можно писать прямо внутри этого элемента — так можно не тратить время на загрузку отдельного скрипта, но зато не выйдет сослаться на один js-файл с нескольких страниц.</p> + </li> +</ul> + +<h3 id="Активное_изучение_добавляем_на_страницу_CSS_и_JavaScript">Активное изучение: добавляем на страницу CSS и JavaScript</h3> + +<ol> + <li>Для этого упражнения скачайте файлы <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/meta-example.html">meta-example.html</a>, <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/script.js">script.js</a> и <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/style.css">style.css</a> и положите их в одну папку на своём компьютере. Проверьте, что они сохранились с правильными именами и расширениями.</li> + <li>Откройте HTML в браузере и текстовом редакторе.</li> + <li>Следуя изученному материалу, добавьте на страницу скрипт и стиль с помощью элементов {{htmlelement("link")}} и {{htmlelement("script")}}.</li> +</ol> + +<p>Если всё получилось, когда вы сохраните HTML и обновите страницу в браузере, вы увидите кое-что новенькое:</p> + +<p><img alt="Example showing a page with CSS and JavaScript applied to it. The CSS has made the page go green, whereas the JavaScript has added a dynamic list to the page." src="https://mdn.mozillademos.org/files/12359/js-and-css.png" style="display: block; margin: 0 auto;"></p> + +<ul> + <li>JavaScript добавил на страницу пустой список. При нажатии на красную область появляется окно, в которое можно ввести текст нового пункта списка. При нажатии на кнопку OK пункт добавляется на страницу. Текст существующих пунктов списка можно редактировать, нажимая на них.</li> + <li>CSS покрасил фон зелёным и увеличил размер шрифта, а также стилизовал элементы, добавленные JavaScript. Красный прямоугольник и рамка вокруг списка — тоже его рук дело.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Если вам никак не удаётся подключить CSS или JS, посмотрите на наш готовый пример — страницу <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/css-and-js.html">css-and-js.html</a>.</p> +</div> + +<h2 id="Основной_язык_HTML_страницы">Основной язык HTML страницы</h2> + +<p>Наконец, стоит отметить, что вы можете (и действительно должны) установить язык для своей страницы. Это можно сделать, добавив <a href="/en-US/docs/Web/HTML/Global_attributes/lang">атрибут lang</a> в открывающий HTML-тег (как в примере <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/meta-example.html">meta-example.html</a>: и как показано ниже):</p> + +<pre class="syntaxbox notranslate"><html lang="en-US"></pre> + +<pre class="syntaxbox notranslate"><html lang="ru"> +</pre> + +<p>Это полезно во многих случаях. Ваш HTML-документ будет более эффективно индексироваться поисковыми системами, если его язык установлен (что позволяет ему правильно отображаться в языковых результатах), и он полезен людям с нарушением зрения, которые используют программы, читающие страницы вслух (например, слово "шесть" пишется одинаково как на французском, так и на английском языках, но произносится по-разному.).</p> + +<p>Можно также указать язык для части документа. Например, мы могли бы установить язык для части страницы на японском:</p> + +<pre class="brush: html notranslate"><p>Пример на японском: <span lang="jp">ご飯が熱い。</span>.</p></pre> + +<p>Коды языков определены в стандарте <a href="https://en.wikipedia.org/wiki/ISO_639-1">ISO 639-1</a>. Подробнее о работе с языками можно узнать в <a href="https://www.w3.org/International/articles/language-tags/">Языковые тэги в HTML и XML</a>.</p> + +<h2 id="Заключение">Заключение</h2> + +<p>На этом заканчивается наш беглый обзор по HTML-блоку head — с его помощью вы можете делать гораздо больше, но исчерпывающий обзор будет скучным и запутанным на этом этапе, мы же сейчас хотели дать вам представление о самых распространённых вещах, которые вы можете там найти! В следующей статье мы рассмотрим основы разметки текста в HTML.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Getting_started", "Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></li> +</ul> diff --git a/files/ru/learn/html/введение_в_html/начало_работы/index.html b/files/ru/learn/html/введение_в_html/начало_работы/index.html new file mode 100644 index 0000000000..48904b9e17 --- /dev/null +++ b/files/ru/learn/html/введение_в_html/начало_работы/index.html @@ -0,0 +1,772 @@ +--- +title: Начало работы с HTML +slug: Learn/HTML/Введение_в_HTML/Начало_работы +tags: + - Guide + - HTML + - Аттрибуты + - Для начинающих + - Комментарии + - Пробелы + - Программирование + - Руководство + - Урок + - элементы +translation_of: Learn/HTML/Introduction_to_HTML/Getting_started +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Введение_в_HTML/Начало_работы")}}</div> + +<p class="summary">В этой статье мы охватим азы HTML, необходимые для начала работы. Дадим определение «элементам», «атрибутам», «тегам» и прочим важным понятиям, о которых вы, возможно, слышали, а также об их роли в языке. Мы также покажем, как устроены HTML-элементы, типичная HTML-страница, и объясним другие важные аспекты языка. По ходу дела, чтобы вы не заскучали, мы поиграем с настоящей HTML-страницей!</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Умение работать с компьютером, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">наличие необходимого ПО</a>, базовые знания о <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">работе с файлами</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Познакомиться с языком HTML и научиться описывать некоторые его элементы.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_HTML">Что такое HTML?</h2> + +<p>{{glossary("HTML")}} (HyperText Markup Language - язык гипертекстовой разметки) не является языком программирования; это <em>язык разметки</em>, используемый для определения структуры веб-страниц, посещаемых пользователями. Они могут иметь сложную или простую структуру, всё зависит от замысла и желания веб-разработчика. HTML состоит из ряда {{glossary("Element", "элементов")}}, которые вы используете для того, чтобы охватить, обернуть или <em>разметить</em> различные части содержимого, чтобы оно имело определенный вид или срабатывало определенным способом. Встроенные {{glossary("Tag", "тэги")}} могут преобразовать часть содержимого в гиперссылку, по которой можно перейти на другую веб-страницу, выделить курсивом слова и так далее. Например, рассмотрим следующую строку:</p> + +<pre class="notranslate">Мой кот очень сердитый</pre> + +<p>Если мы хотим, чтобы строка отобразилась в таком же виде, мы можем определить её, как "параграф", заключив её в теги элемента "параграф" ({{htmlelement("p")}}), например:</p> + +<pre class="brush: html notranslate"><p>Мой кот очень сердитый</p></pre> + +<div class="note"> +<p><strong>Примечание</strong>: Метки в HTML нечувствительны к регистру, то есть они могут быть записаны в верхнем или нижнем регистре. Например, тег {{htmlelement("title")}} может быть записан как <code><title></code>, <code><TITLE></code>, <code><Title></code>, <code><TiTlE></code>, и т.д., и он будет работать нормально. Лучшей практикой, однако, является запись всех тегов в нижнем регистре для обеспечения согласованности, удобочитаемости и других причин.</p> +</div> + +<h2 id="Структура_HTML_элементов">Структура HTML элементов</h2> + +<p>Давайте рассмотрим элемент "параграф" чуть подробнее:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/16452/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png" style="height: 255px; width: 821px;"></p> + +<p>Основными частями элемента являются:</p> + +<ol> + <li><strong>Открывающий тег:</strong> Он состоит из названия (обозначения) элемента (в нашем случае, p), помещённого внутри <strong>угловых скобок</strong>. Данный тег служит признаком начала элемента, с этого момента тег начинает влиять на следующее после него содержимое.</li> + <li><strong>Закрывающий тег:</strong> выглядит как и открывающий, но содержит слэш перед названием тега. Он служит признаком конца элемента. Пропуски закрывающих тегов — типичная ошибка новичков, которая может приводить к неопределённым результатам — в лучшем случае всё сработает правильно, в других страница может вовсе не прорисоваться или прорисоваться не как ожидалось.</li> + <li><strong>Содержимое:</strong> Как видно, в нашем случае содержимым является простой текст.</li> + <li><strong>Элемент:</strong> открывающий тег + закрывающий тег + содержимое = элемент.</li> +</ol> + +<h3 id="Активное_изучение_создание_вашего_первого_HTML_элемента">Активное изучение: создание вашего первого HTML элемента</h3> + +<p>Отредактируйте строку текста ниже в поле <em>Ввод</em>, обернув ее тегами <code><em></code> и <code></em></code> (вставьте <code><em></code> перед строкой, чтобы <em>указать начало элемента</em>, и <code></em></code> после нее, чтобы <em>указать конец элемента</em>) — эти действия должны выделить строку текста курсивом! Вы можете видеть изменения в реальном времени в поле <em>Вывод</em>.</p> + +<p>Если Вы ошиблись, то всегда можете начать снова, воспользовавшись кнопкой <em>Сбросить</em>. Если упражнение вызывает у Вас затруднения, то нажмите кнопку <em>Показать решение</em>, чтобы увидеть правильный ответ.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Результат</h2> +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label">Нажмите Esc, чтобы выйти из области кода (Tab вставляет символ табуляции).</p> + +<textarea id="code" class="playable-code" style="min-height: 100px;width: 95%"> + Это мой текст. +</textarea> + +<div class="controls"> + <input id="reset" type="button" value="Сбросить" /> + <input id="solution" type="button" value="Показать решение" /> +</div> +</pre> + +<pre class="brush: css notranslate">html { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<em>Это мой текст.</em>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 400, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="Вложенные_элементы">Вложенные элементы</h3> + +<h3 id="Nesting_elements" style="display: none;">Nesting_elements</h3> + +<p>Вы также можете вкладывать элементы внутрь других элементов — это называется <strong>вложенностью</strong>. Если мы хотим подчеркнуть, что наш кот <strong>очень</strong> сердитый, мы можем заключить слово "очень" в элемент {{htmlelement("strong")}} , который означает, что это слово крайне важно в данном контексте:</p> + +<pre class="brush: html notranslate"><p>Мой кот <strong>очень</strong> сердитый.</p></pre> + +<p>Вы должны удостовериться, что элементы вложены должным образом: в следующем примере мы открываем <code>p</code> элемент первым, затем элемент <code>strong</code>, затем мы закрываем элемент <code>strong</code> первым, затем <code>p</code>. Следующее писать неправильно:</p> + +<pre class="example-bad brush: html notranslate"><p>Мой кот <strong>очень сердитый.</p></strong></pre> + +<p>Элементы должны открываться и закрываться правильно таким образом, чтобы явно находиться внутри или снаружи друг друга. Если они перекрываются так, как в примере выше, то ваш браузер попытается «додумать» за вас, что вы имели в виду, и вы получите непредсказуемый результат. Так что не делайте так!</p> + +<h3 id="Блочные_и_строчные_элементы">Блочные и строчные элементы</h3> + +<h3 id="Block_versus_inline_elements" style="display: none;">Block versus inline elements</h3> + +<p>Существует две важных категории элементов в HTML, которые вам стоит знать — элементы блочного уровня и строчные элементы.</p> + +<ul> + <li>Элементы блочного уровня формируют видимый блок на странице — они окажутся на новой строке после любого контента, который шёл до них, и любой контент после них также окажется на новой строке. Чаще всего элементами блочного уровня бывают структурные элементы страницы, представляющие собой, например, параграфы (абзацы), списки, меню навигации, футеры, или подвалы, и т. п. Элементы блочного уровня не вкладываются в строчные элементы, но иногда могут вкладываться в другие элементы блочного уровня.</li> + <li>Строчные элементы — это те, которые содержатся в элементах блочного уровня и окружают только малые части содержимого документа, не целые абзацы и группировки контента. Строчные элементы не приводят к появлению новой строки в документе: они обычно встречаются внутри абзаца текста, например, элемент {{htmlelement("a")}} (ссылка) или акцентирующие элементы вроде {{htmlelement("em")}} или {{htmlelement("strong")}}.</li> +</ul> + +<p>Посмотрите на следующий пример:</p> + +<pre class="brush: html notranslate"><em>Первый</em><em>второй</em><em>третий</em> + +<p>четвертый</p><p>пятый</p><p>шестой</p> +</pre> + +<p>{{htmlelement("em")}} — это строчный элемент, так что, как вы здесь видите, первые три элемента находятся на одной строке друг с другом без пробелов между ними. С другой стороны, {{htmlelement("p")}} — это элемент блочного уровня, так что каждый элемент находится на новой строке, с пространством выше и ниже каждого (этот интервал определяется <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS-оформлением</a> по умолчанию, которое браузеры применяют к абзацам).</p> + +<p>{{ EmbedLiveSample('Block_versus_inline_elements', 700, 200, "", "") }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: HTML5 переопределил категории элементов в HTML: смотрите <a href="http://www.whatwg.org/specs/web-apps/current-work/complete/section-index.html#element-content-categories">Категории типов содержимого элементов</a>. Хотя эти определения точнее и однозначнее, чем те, которые были раньше, их гораздо сложнее понять, чем «блочный» и «строчный», поэтому мы будем придерживаться их в этом разделе.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Не путайте термины «блочный» и «строчный», используемые в этом разделе, с одноименными <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Box_model#Types_of_CSS_boxes">типами отображения в CSS</a>. Хотя по умолчанию они коррелируют, смена типа отображения в CSS не меняет категорию элемента и не влияет на то, во что его можно вкладывать и что можно вкладывать в него. Эта довольно частая путаница — одна из причин, почему HTML5 отказался от этих терминов.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Вам могут пригодиться справочники, включающие списки блочных и строчных элементов — смотри <a href="/en-US/docs/Web/HTML/Block-level_elements">Элементы блочного уровня</a> и <a href="/en-US/docs/Web/HTML/Inline_elements">Строчные элементы</a>.</p> +</div> + +<h3 id="Пустые_элементы">Пустые элементы</h3> + +<h3 id="Empty_elements" style="display: none;">Empty elements</h3> + +<p>Не все элементы соответствуют вышеупомянутому шаблону: открывающий тег, контент, закрывающий тег. Некоторые элементы состоят из одного тега и обычно используются для вставки чего-либо в то место документа, где размещены. Например, элемент {{htmlelement("img")}} вставляет картинку на страницу в том самом месте, где он расположен:</p> + +<pre class="brush: html notranslate"><img src="https://raw.githubusercontent.com/mdn/beginner-html-site/gh-pages/images/firefox-icon.png"></pre> + +<p>Это выведет на вашу страницу следующее:</p> + +<p>{{ EmbedLiveSample('Empty_elements', 700, 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: Пустые элементы иногда называют <em>void-элементами</em>.</p> +</div> + +<h2 id="Атрибуты">Атрибуты</h2> + +<p>У элементов также могут быть атрибуты, которые выглядят так:</p> + +<p><img alt='&amp;amp;lt;p class="editor-note">My cat is very grumpy&amp;amp;lt;/p>' src="https://mdn.mozillademos.org/files/9345/grumpy-cat-attribute-small.png" style="display: block; height: 156px; margin: 0px auto; width: 1287px;"></p> + +<p>Атрибуты содержат дополнительную информацию об элементе, которая, по вашему мнению, не должна отображаться в содержимом элемента. В данном случае атрибут <code>class</code> позволяет вам дать элементу идентификационное имя, которое в дальнейшем может быть использовано для обращения к элементу с информацией о стиле и прочими вещами.</p> + +<p>Атрибут должен иметь:</p> + +<ol> + <li>Пробел между атрибутом и именем элемента (или предыдущим атрибутом, если у элемента уже есть один или несколько атрибутов).</li> + <li>Имя атрибута и следующий за ним знак равенства.</li> + <li>Значение атрибута, заключенное в кавычки.</li> +</ol> + +<h3 id="Активное_изучение_Добавление_атрибутов_в_элемент">Активное изучение: Добавление атрибутов в элемент</h3> + +<h3 id="Active_learning_Adding_attributes_to_an_element" style="display: none;">Active learning: Adding attributes to an element</h3> + +<p>Возьмём для примера элемент {{htmlelement("a")}} — означает anchor (якорь) и делает текст внутри него гиперссылкой. Может иметь несколько атрибутов, вот несколько из них:</p> + +<ul> + <li><code>href</code>: В значении этого атрибута прописывается веб-адрес, на который, по вашей задумке, должна указывать ссылка, куда браузер переходит, когда вы по ней кликаете. Например, <code>href="https://www.mozilla.org/"</code>.</li> + <li><code>title</code>: Атрибут <code>title</code> описывает дополнительную информацию о ссылке, такую как: на какую страницу она ведет. Например, <code>title="The Mozilla homepage"</code>. Она появится в виде всплывающей подсказки, когда вы наведете курсор на ссылку.</li> + <li><code>target</code>: Атрибут <code>target</code> определяет контекст просмотра, который будет использоваться для отображения ссылки. Например, <code>target="_blank"</code> отобразит ссылку на новой вкладке. Если вы хотите отобразить ссылку на текущей вкладке, просто опустите этот атрибут.</li> +</ul> + +<p>Измените строку текста ниже в поле <em>Ввод</em> так, чтобы она вела на ваш любимый вебсайт. Сначала добавьте элемент <code><a></code>затем атрибут <code>href</code> и атрибут <code>title</code>. Наконец, укажите атрибут <code>target</code> чтобы открыть ссылку на новой вкладке. Вы можете наблюдать сделанные изменения в реальном времени в поле <em>Вывод</em>. Вы должны увидеть гиперссылку, при наведении курсора на которую появляется содержимое атрибута <code>title</code>, а при щелчке переходит по адресу в атрибуте <code>href</code>. Помните, что между именем элемента и каждым из атрибутов должен быть пробел.</p> + +<p>Если Вы ошиблись, то всегда можете начать снова, воспользовавшись кнопкой <em>Сбросить</em>. Если упражнение вызывает у Вас затруднения, то нажмите кнопку <em>Показать решение</em>, чтобы увидеть правильный ответ.</p> + +<div class="hidden"> +<h6 id="Playable_code2">Playable code2</h6> + +<pre class="brush: html notranslate"><h2>Результат</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label">Нажмите Esc, чтобы выйти из области кода (Tab вставляет символ табуляции).</p> + +<textarea id="code" class="input" style="min-height: 100px;width: 95%"> + &lt;p&gt;Ссылка на мой любимый веб-сайт.&lt;/p&gt; +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<p>Ссылка на мой <a href="https://www.mozilla.org/" title="Домашняя страница Mozilla" target="_blank">любимый веб-сайт</a>.</p>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code2', 700, 400, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="Булевые_атрибуты">Булевые атрибуты</h3> + +<h3 id="Boolean_attributes" style="display: none;">Boolean attributes</h3> + +<p>Иногда вы будете видеть атрибуты, написанные без значения — это совершенно допустимо. Такие атрибуты называются булевые, и они могут иметь только одно значение, которое в основном совпадает с его именем. В качестве примера возьмем атрибут {{htmlattrxref("disabled", "input")}}, который можно назначить для формирования элементов ввода, если вы хотите, чтобы они были отключены (неактивны), так что пользователь не может вводить какие-либо данные в них.</p> + +<pre class="notranslate"><input type="text" disabled="disabled"></pre> + +<p>Для краткости совершенно допустимо записывать их следующим образом (мы также для справки разместили не деактивированный элемент input, чтобы дать вам большее понимание происходящего):</p> + +<pre class="brush: html notranslate"><input type="text" disabled> + +<input type="text"> +</pre> + +<p>На выходе оба варианта будут выглядеть следующим образом:</p> + +<p>{{ EmbedLiveSample('Boolean_attributes', 700, 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="Опускание_кавычек_вокруг_значений_атрибутов">Опускание кавычек вокруг значений атрибутов</h3> + +<h3 id="Omitting_quotes_around_attribute_values" style="display: none;">Omitting quotes around attribute values</h3> + +<p>Осматриваясь во всемирной сети, вы будете встречать различные незнакомые способы написания разметки, включая написание значений атрибутов без кавычек. Это допустимо при определенных условиях, но разрушит вашу разметку при других. Например, возвращаясь к нашему упражнению с гиперссылкой, мы можем написать основной вариант только с атрибутом <code>href</code> так:</p> + +<pre class="brush: html notranslate"><a href=https://www.mozilla.org/>любимый веб-сайт</a></pre> + +<p>Однако, как только мы добавим атрибут <code>title</code> в таком же стиле, мы поступим неверно:</p> + +<pre class="example-bad brush: html notranslate"><a href=https://www.mozilla.org/ title=The Mozilla homepage>favorite website</a></pre> + +<p>В этом месте браузер неверно истолкует вашу разметку, думая, что атрибут <code>title</code> — это на самом деле три разных атрибута — атрибут title со значением "The" и два булевых атрибута: <code>Mozilla</code> и <code>homepage</code>. Это, очевидно, не то, что имелось в виду, и приведёт к ошибке или неожиданному поведению кода, как это показано в живом примере ниже. Попробуйте навести курсор на ссылку, чтобы увидеть, на что похож текст title!</p> + +<p>{{ EmbedLiveSample('Omitting_quotes_around_attribute_values', 700, 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>Наш совет: всегда используйте кавычки в атрибутах — это позволит избежать подобных проблем, и, следовательно, код будет более читабельным.</p> + +<h3 id="Одинарные_или_двойные_кавычки">Одинарные или двойные кавычки?</h3> + +<h3 id="Single_or_double_quotes" style="display: none;">Single or double quotes?</h3> + +<p>В этой статье вы заметите, что все атрибуты заключены в двойные кавычки. Однако, вы можете видеть одинарные кавычки в HTML документах других людей. Это исключительно дело вкуса, и вы можете свободно выбирать, какие из них предпочитаете. Обе следующие строки эквивалентны:</p> + +<pre class="brush: html notranslate"><a href="http://www.example.com">Ссылка к моему примеру.</a> + +<a href='http://www.example.com'>Ссылка к моему примеру.</a></pre> + +<p>Однако вы должны убедиться, что не смешиваете их вместе. Следующее будет неверным!</p> + +<pre class="example-bad brush: html notranslate"><a href="http://www.example.com'>Ссылка к моему примеру.</a></pre> + +<p>Если вы используете один тип кавычек в своем HTML, то вы можете поместить внутрь их кавычки другого типа, не вызывая никаких проблем:</p> + +<pre class="brush: html notranslate"><a href="http://www.example.com" title="Isn't this fun?">A link to my example.</a></pre> + +<p>Если вы хотите вставить кавычки того же типа, то вы должны использовать <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started#Entity_references_Including_special_characters_in_HTML">объекты HTML</a>. Например, это работать не будет:</p> + +<pre class="example-bad brush: html notranslate"><a href='http://www.example.com' title='Isn't this fun?'>A link to my example.</a></pre> + +<p>Поэтому вам нужно сделать так:</p> + +<pre class="brush: html notranslate"><a href='http://www.example.com' title='Isn&#39;t this fun?'>A link to my example.</a></pre> + +<h2 id="Структура_HTML_документа">Структура HTML документа</h2> + +<p>Ниже дан пример оборачивания основных, самостоятельных HTML элементов, которые сами по себе не очень полезны. Давайте посмотрим, как самостоятельные элементы объединяются для формирования всей HTML страницы:</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Тестовая страница</title> + </head> + <body> + <p>Это — моя страница</p> + </body> +</html></pre> + +<p>Вот что мы имеем:</p> + +<ol> + <li><code><!DOCTYPE html></code>: Объявление типа документа. Очень давно, ещё когда HTML был молод (1991/2), типы документов использовались в качестве ссылок на набор правил, которым HTML-страница должна была следовать, чтобы она считалась хорошей, что может означать автоматическую проверку ошибок и другие полезные вещи. Объявление типа документа выглядело примерно вот так: + + <pre class="notranslate"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"></pre> + Однако в наши дни никто особо не думает о них, и типы документа стали историческим артефактом, которые должны быть включены везде, чтобы всё работало правильно. <code><!DOCTYPE html></code> — это самый короткий вид типа документа, который считается действующим. На самом деле это всё, что нужно вам знать о типах документов .</li> + <li><code><html></html></code>: Элемент {{htmlelement("html")}} содержит в себе всё содержимое на всей странице, и иногда его называют "корневой элемент". </li> + <li><code><head></head></code>: Элемент {{htmlelement("head")}}. Данный элемент выступает в качестве контейнера для всего содержимого, которое вы хотите включить в HTML документ, но не хотите показывать посетителям вашей страницы. Он включает такие вещи, как ключевые слова и описание страницы, которые вы хотели бы показывать в поисковых запросах, CSS для стилизирования вашего контента, объявление поддерживаемого набора символов и многое другое. Вы узнаете больше об этом из следующей статьи данного руководства.</li> + <li><code><meta charset="utf-8"></code>: Этот элемент устанавливает в качестве символьной кодировки для вашего документа utf-8 , который включает большинство символов из всех известных человечеству языков. По существу, теперь страница сможет отобразить любой текстовый контент, который вы сможете в неё вложить. Нет причин не устанавливать эту кодировку, это также позволит избежать некоторых проблем позднее.</li> + <li><code><title></title></code>: Элемент {{htmlelement("title")}}. Этот элемент устанавливает заголовок вашей страницы, который появляется во вкладке браузера, загружающей эту страницу, также это заглавие используется при описании страницы, когда вы сохраняете её в закладках или избранном.</li> + <li><code><body></body></code>: Элемент {{htmlelement("body")}}. Он содержит <em>весь</em> контент, который вы хотите показывать посетителям вашей страницы, — текст, изображения, видео, игры, проигрываемые аудио дорожки или что-то ещё.</li> +</ol> + +<h3 id="Активное_изучение_Добавление_элементов_в_ваш_HTML-документ">Активное изучение: Добавление элементов в ваш HTML-документ</h3> + +<h3 id="Active_learning_Adding_some_features_to_an_HTML_document" style="display: none;">Active learning: Adding some features to an HTML document</h3> + +<p>Если вы хотите поэкспериментировать с написанием HTML на своём компьютере, то можете:</p> + +<ol> + <li>Скопировать пример HTML-страницы, расположенный выше.</li> + <li>Создать новый файл в текстовом редакторе.</li> + <li>Вставить код в ваш новый текстовый файл.</li> + <li>Сохранить файл как <code>index.html</code>.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Вы также можете найти этот базовый пример HTML на <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">MDN Learning Area Github repo</a>.</p> +</div> + +<p>Теперь можете открыть браузер и посмотреть, во что отрисовался код, а потом изменить его, обновить страницу и посмотреть, что получилось. Сначала страница выглядит так:</p> + +<p><img alt="Скриншот примера тестовой страницы" src="https://mdn.mozillademos.org/files/17060/Test_page.jpg" style="border-style: solid; border-width: 1px; height: 293px; width: 415px;"><br> + Для этого упражнения вы можете редактировать код локально на своём компьютере, как предлагается выше, а можете работать в редакторе, расположенном ниже. В редакторе показано только содержимое элемента {{htmlelement("body")}}. Попробуйте сделать следующее:</p> + +<ul> + <li>Добавьте заголовок страницы сразу за открывающим тегом {{htmlelement("body")}}. Текст должен находиться между открывающим тегом <code><h1></code> и закрывающим <code></h1></code> .</li> + <li>Напишите в параграфе о чём-нибудь, что кажется вам интересным.</li> + <li>Выделите важные слова, обернув их в открывающий тег <code><strong></code> и закрывающий <code></strong></code></li> + <li>Добавьте ссылку на свой абзац так, как <a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Active_learning_Adding_attributes_to_an_element">объяснено ранее в статье</a>.</li> + <li>Добавьте изображение в свой документ под абзацем, как <a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Empty_elements">объяснено ранее в статье</a>. Если сможете использовать другую картинку (со своего компьютера или из интернета). Вы большой молодец!</li> +</ul> + +<p>Если вы запутались, всегда можно запустить пример сначала кнопкой <em>Сбросить</em>. Сдаётесь — посмотрите ответ, нажав на <em>Показать решение</em>.</p> + +<div class="hidden"> +<h6 id="Playable_code3">Playable code3</h6> + +<pre class="brush: html notranslate"><h2>Результат</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label">Нажмите Esc, чтобы выйти из области кода (Tab вставляет символ табуляции).</p> + +<textarea id="code" class="input" style="min-height: 100px;width: 95%"> + &lt;p&gt;Это — моя страница&lt;/p&gt; +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +img { + max-width: 100%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = '<em>Спрятать решение</em>'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var htmlSolution = '<p>Мне очень нравится <strong>играть на барабанах</strong>. Мой любимый барабанщик — Нил Пирт, который\ играет в группе <a href="https://en.wikipedia.org/wiki/Rush_%28band%29" title="Rush Wikipedia article">"Rush"</a>.\ Мой любимый альбом Rush — <a href="http://www.deezer.com/album/942295">"Moving Pictures"</a>.</p>\ <img src="http://www.cygnus-x1.net/links/rush/images/albums/sectors/sector2-movingpictures-cover-s.jpg">'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code3', 700, 600, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="Пробелы_в_HTML">Пробелы в HTML</h3> + +<h3 id="Whitespace_in_HTML" style="display: none;">Whitespace in HTML</h3> + +<p>Вы могли заметить, что в примерах кода из этой статьи много пробелов. Это вовсе не обязательно — следующие два примера эквивалентны:</p> + +<pre class="brush: html notranslate"><p>Собаки глупы.</p> + +<p>Собаки + глупы.</p></pre> + +<p>Не важно, сколько пустого места вы используете в разметке (что может включать пробелы и сдвиги строк): браузер при анализе кода сократит всё пустое место до одного пробела. Зачем использовать много пробелов? Ответ: это доступность для понимания — гораздо легче разобраться, что происходит в вашем коде, если он удобно отформатирован, а не просто собран вместе в одном большом беспорядке. В нашем коде каждый вложенный элемент сдвинут на два пробела относительно элемента, в котором он находится. Вы можете использовать любое форматирование (в частности, количество пробелов для отступа), но лучше придерживаться одного стиля.</p> + +<h2 id="Ссылки_на_сущности_Включение_специальных_символов_в_HTML">Ссылки на сущности: Включение специальных символов в HTML</h2> + +<h2 id="Entity_references_Including_special_characters_in_HTML" style="display: none;">Entity references: Including special characters in HTML</h2> + +<p>В HTML символы <code><</code>, <code>></code>, <code>"</code>, <code>'</code> и <code>&</code> являются специальными. Они являются частью самого синтаксиса HTML. Так как же включить в текст один из этих специальных символов? Например, если вы хотите использовать амперсанд или знак «меньше» и не интерпретировать его как код.</p> + +<p>Мы должны использовать ссылки-мнемоники — специальные коды, которые отображают спецсимволы, и могут быть использованы в необходимых позициях. Каждая ссылка-мнемоник начинается с ампресанда (&) и завершается точкой с запятой (;).</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Буквенный символ</th> + <th scope="col">Символьный эквивалент</th> + </tr> + </thead> + <tbody> + <tr> + <td><</td> + <td>&lt;</td> + </tr> + <tr> + <td>></td> + <td>&gt;</td> + </tr> + <tr> + <td>"</td> + <td>&quot;</td> + </tr> + <tr> + <td>'</td> + <td>&apos;</td> + </tr> + <tr> + <td>&</td> + <td>&amp;</td> + </tr> + </tbody> +</table> + +<p>В следующем примере вы видите два абзаца, которые рассказывают о веб-технологиях:</p> + +<pre class="brush: html notranslate"><p>В HTML вы определяете параграф элементом <p>.</p> + +<p>В HTML вы определяете параграф элементом &lt;p&gt;.</p></pre> + +<p>В живом выводе ниже вы можете заметить, что первый абзац выводится неправильно, так как браузер считает, что второй элемент <code><p></code> является началом нового абзаца! Второй абзац нашего кода выводится правильно, потому что мы заменили угловые скобки на ссылки-мнемоники.</p> + +<p>{{ EmbedLiveSample('Entity_references_Including_special_characters_in_HTML', 700, 200, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: Таблица всех доступных в HTML символов-мнемоников — в Википедии: <a class="external text" href="http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references" rel="nofollow">List of XML and HTML character entity references</a>.</p> +</div> + +<h2 id="HTML_комментарии">HTML комментарии</h2> + +<h2 id="HTML_comments" style="display: none;">HTML comments</h2> + +<p>В HTML, как и в большинстве языков программирования, есть возможность писать комментарии в коде. Комментарии игнорируются обозревателем и не видны пользователю, их добавляют для того, чтобы пояснить, как работает написанный код, что делают отдельные его части и т. д. Такая практика полезна, если вы возвращаетесь к коду, который давно не видели или когда хотите передать его кому-то другому.</p> + +<p>Чтобы превратить часть содержимого HTML-файла в комментарий, нужно поместить её в специальные маркеры <code><!--</code> и <code>--></code>, например:</p> + +<pre class="brush: html notranslate"><p> Меня нет в комментариях( </p> + +<!-- <p>А теперь есть!</p> --></pre> + +<p>Как вы увидете ниже, первый параграф будет отображён на экране, а второй нет.</p> + +<p>{{ EmbedLiveSample('HTML_comments', 700, 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Подведение_итогов">Подведение итогов</h2> + +<p>Вы дошли до конца статьи — надемся, вам понравилось путешествие по основам HTML. На этом этапе вы уже должны немного разобраться, как выглядит язык, как он работает на базовом уровне и уметь описать несколько элементов и атрибутов. Сейчас идеальное время и место, чтобы продолжить изучать HTML. В последующих статьях мы рассмотрим некоторые из вещей, которые вы уже рассмотрели, но намного подробнее, а также представим некоторые новые функции языка. Оставайтесь с нами!</p> + +<div class="note"> +<p><strong>Примечание</strong>: Сейчас, когда вы начинаете больше узнавать о HTML, вы также можете начать изучать основы каскадных таблиц стилей Cascading Style Sheets, или <a href="/en-US/docs/Learn/CSS">CSS</a>. CSS — это язык, который используется для стилизации веб-страниц (например, изменение шрифта или цветов или изменение макета страницы). Как вы скоро поймете, HTML и CSS созданы друг для друга.</p> +</div> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="/en-US/docs/Web/HTML/Applying_color">Применение цвета к элементам HTML с помощью CSS</a></li> +</ul> + +<div>{{NextMenu("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Введение_в_HTML/Начало_работы")}}</div> + +<div></div> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></li> +</ul> diff --git a/files/ru/learn/html/введение_в_html/создание_гиперссылок/index.html b/files/ru/learn/html/введение_в_html/создание_гиперссылок/index.html new file mode 100644 index 0000000000..fcee7272e4 --- /dev/null +++ b/files/ru/learn/html/введение_в_html/создание_гиперссылок/index.html @@ -0,0 +1,435 @@ +--- +title: Создание гиперссылок +slug: Learn/HTML/Введение_в_HTML/Создание_гиперссылок +tags: + - Абсолютные + - Гиперссылки + - Единый указатель ресурса + - Заголовок + - Начинающий + - Обучение + - Относительные + - Руководство + - Ссылки + - Язык гипертекстовой разметки +translation_of: Learn/HTML/Introduction_to_HTML/Creating_hyperlinks +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary"><span id="result_box" lang="ru"><span>Гиперссылки действительно важны — </span></span><span lang="ru"><span>они делают Интернет Интернетом.</span> <span>В этой статье представлен синтаксис, необходимый для создания ссылки, а также обсуждаются лучшие практики обращения со ссылками.</span></span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные требования:</th> + <td>Базовое <span class="short_text" id="result_box" lang="ru"><span>знакомство с HTML, описаное в статье</span></span> <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы c HTML</a>. Форматирование текста в HTML, описанное в статье <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Научиться эффективно использовать гиперссылки и связывать несколько файлов вместе.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_гиперссылка">Что такое гиперссылка?</h2> + +<p><span id="result_box" lang="ru"><span class="alt-edited">Гиперссылки — одно из самых интересных нововведений Интернета. Они были особенностью Сети с самого начала, но именно они превращают Интернет в Интернет. Они позволяют нам связывать наши документы с любым другим документом (или ресурсом), с которым мы хотим. С их помощью мы также можем связывать документы с их конкретными частями, и мы можем сделать приложения доступными на простом веб-адресе (сравните это с локальными приложениями, которые должны быть установлены, и другими такими же вещами). Почти любой веб-контент может быть преобразован в ссылку, так что когда вы кликаете по ней (или иным образом активируете), она заставляет веб-браузер перейти на другой веб-адрес</span></span> ({{glossary("URL")}}.)</p> + +<div class="note"> +<p><span id="result_box" lang="ru"><span class="alt-edited"><strong>Примечание:</strong> URL-адрес может указывать на файлы HTML, текстовые файлы, изображения, текстовые документы, видео и аудиофайлы и все остальное, что может жить в Интернете. Если веб-браузер не знает, как отображать или обрабатывать файл, он спросит вас, хотите ли вы открыть файл (в этом случае обязанность открытия или обработки файла передаётся в соответствующее локальное приложение на устройстве) или загрузить файл (в этом случае вы можете попытаться разобраться с ним позже).</span></span></p> +</div> + +<p><span id="result_box" lang="ru"><span>Например, домашняя страница BBC содержит большое количество ссылок, которые указывают не только на множество новостей, но и на различные области сайта (меню), страницы входа / регистрации (пользовательские инструменты) и многое другое.</span></span></p> + +<p><img alt="frontpage of bbc.co.uk, showing many news items, and navigation menu functionality" src="https://mdn.mozillademos.org/files/12405/bbc-homepage.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="Анатомия_ссылки">Анатомия ссылки</h2> + +<p><span id="result_box" lang="ru"><span class="alt-edited">Простая ссылка создаётся путём обёртывания текста (или другого содержимого, смотрите </span></span>{{anch("Ссылки-блоки")}}<span lang="ru"><span class="alt-edited">), который вы хотите превратить в ссылку, в элемент {{htmlelement ("a")}}, и придания этому элементу атрибута {{htmlattrxref ("href", "a")}} (который также известен как <strong>гипертекстовая ссылка,</strong> или <strong>цель</strong>), который будет содержать веб-адрес, на который вы хотите указать ссылку.</span></span></p> + +<pre class="brush: html notranslate"><p>Я создал ссылку на + <a href="https://www.mozilla.org/ru/">домашнюю страницу Mozilla</a>. +</p></pre> + +<p>Это дало нам следующий результат:</p> + +<p>Я создал ссылку на <a class="ignore-external" href="https://www.mozilla.org/ru/">домашнюю страницу Mozilla</a>.</p> + +<h3 id="Добавляем_инфомацию_через_атрибут_title">Добавляем инфомацию через атрибут title</h3> + +<p>Другим атрибутом, который вы можете добавить к своим ссылкам, является — <code>title</code>. Он предназначен для хранения полезной информации о ссылке. Например, какую информацию содержит страница или другие вещи, о которых вам нужно знать. Например:</p> + +<pre class="brush: html notranslate"><p>Я создал ссылку на + <a href="https://www.mozilla.org/ru/" + title="Лучшее место для поиска дополнительной информации + о миссии Mozilla и о том, как внести свой вклад">домашнюю страницу Mozilla + </a>. +</p></pre> + +<p>Вот что получилось (описание появится, если навести курсор на ссылку):</p> + +<p>Я создал ссылку на <a class="ignore-external" href="https://www.mozilla.org/ru/" title="Лучшее место для поиска дополнительной информации о миссии Mozilla и о том, как внести свой вклад">домашнюю страницу Mozilla</a>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Описание из атрибута title отображается только при наведении курсора, значит люди, полагающиеся на клавиатурные элементы управления для навигации по веб-страницам, будут испытывать трудности с доступом к информации, которую содержит title. Если информация заголовка действительно важна для удобства использования страницы, то вы должны представить ее таким образом, который будет доступен для всех пользователей, например, поместив её в обычный текст.</p> +</div> + +<h3 id="Активное_изучение_создаём_собственную_ссылку">Активное изучение: создаём собственную ссылку</h3> + +<p>Время упражнения: мы хотели бы, чтобы вы создали любой HTML-документ в текстовом редакторе на своём компьютере (наш <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">базовый пример</a> подойдёт.)</p> + +<ul> + <li>Попробуйте добавить в тело HTML один или несколько абзацев или другие элементы, о которых вы уже знаете.</li> + <li>Теперь превратите некоторые фрагменты документа в ссылки.</li> + <li>Добавьте ссылкам атрибут <code>title</code>.</li> +</ul> + +<h3 id="Ссылки-блоки">Ссылки-блоки</h3> + +<p>Как упоминалось ранее, вы можете превратить любой элемент в ссылку, даже <a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Block_versus_inline_elements">блочный элемент</a>. Если у вас есть изображение, которые вы хотели бы превратить в ссылку, вы можете просто поместить изображение между тегами <code><a></a>.</code></p> + +<pre class="brush: html notranslate"><a href="https://www.mozilla.org/ru/"> + <img src="mozilla-image.png" alt="логотип mozilla со ссылкой на их домашнюю страницу"> +</a></pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы узнаете гораздо больше об использовании изображений в Интернете в следующей статье.</p> +</div> + +<h2 id="Краткое_руководство_по_URL-адресам_и_путям">Краткое руководство по URL-адресам и путям</h2> + +<p>Чтобы полностью понять адреса ссылок, вам нужно понять несколько вещей про URL-адреса и пути к файлам. Этот раздел даст вам информацию, необходимую для достижения этой цели.</p> + +<p>URL-адрес (Uniform Resource Locator, или единый указатель ресурса, но так его никто не называет) — это просто строка текста, которая определяет, где что-то находится в Интернете. Например, домашняя страница Mozilla находится по адресу <code>https://www.mozilla.org/ru/</code>.</p> + +<p>URL-адреса используют пути для поиска файлов. Пути указывают, где в файловой системе находится файл, который вас интересует. Давайте рассмотрим простой пример структуры каталогов (смотрите каталог <a href="https://github.com/mdn/learning-area/tree/master/html/introduction-to-html/creating-hyperlinks">creating-hyperlinks</a>.)</p> + +<p><img alt="A simple directory structure. The parent directory is called creating-hyperlinks and contains two files called index.html and contacts.html, and two directories called projects and pdfs, which contain an index.html and a project-brief.pdf file, respectively" src="https://mdn.mozillademos.org/files/12409/simple-directory.png" style="display: block; margin: 0 auto;"></p> + +<p><strong>Корень</strong> структуры — каталог <code>creating-hyperlinks</code>. При работе на локальном веб-сайте у вас будет один каталог, в который входит весь сайт. В корне у нас есть два файла — <code>index.html</code> и <code>contacts.html</code>. На настоящем веб-сайте <code>index.html</code> был бы нашей домашней, или лендинг-страницей (веб-страницей, которая служит точкой входа для веб-сайта или определенного раздела веб-сайта).</p> + +<p>В корне есть ещё два каталога — <code>pdfs</code> и <code>projects</code>. У каждого из них есть один файл внутри — <code>project-brief.pdf</code> и <code>index.html</code>, соответсвенно. Обратите внимание на то, что вы можете довольно успешно иметь два <code>index.html</code> файла в одном проекте, <span id="result_box" lang="ru"><span>пока они находятся в разных местах файловой системы.</span></span> Многие веб-сайты так делают. Второй <code>index.html</code><span id="result_box" lang="ru"><span>, возможно, будет главной лендинг-страницей для связанной с проектом информации.</span></span></p> + +<ul> + <li> + <p><strong>Тот же каталог</strong>: Если вы хотите подключить ссылку внутри <code>index.html</code> (верхний уровень <code>index.html</code>), указывающую на <code>contacts.html</code>, вам просто нужно указать имя файла, на который вы хотите установить ссылку, так как он находится в том же каталоге, что и текущий файл. Таким образом, URL-адрес, который вы используете — <code>contacts.html</code>:</p> + + <pre class="brush: html notranslate"><p>Хотите связаться с конкретным сотрудником? + Найдите подробную информацию на нашей + <a href="contacts.html">странице контактов</a>. +</p></pre> + </li> + <li> + <p><strong>Перемещение вниз в подкаталоги</strong>: Если вы хотите подключить ссылку внутри <code>index.html</code> (верхний уровень <code>index.html<font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">), указывающую на </span></font></code><code>projects/index.html</code>, вам нужно спуститься ниже в директории <code>projects</code> перед тем, как указать файл, который вы хотите. Это делается путём указания имени каталога, после которого идёт слэш и затем имя файла. Итак, URL-адрес, который вы используете - <code>projects/index.html</code>:</p> + + <pre class="brush: html notranslate"><p>Посетите мою + <a href="projects/index.html">домашнюю страницу проекта</a>. +</p></pre> + </li> + <li> + <p><strong>Перемещение обратно в родительские каталоги</strong>: Если вы хотите подключить ссылку внутри <code>projects/index.html</code>, указывающую на <code>pdfs/project-brief.pdf</code>, вам нужно будет подняться на уровень каталога, затем спустится в каталог <code>pdf</code>. "Поднятся вверх на уровень каталога" обозначается двумя точками — <code>..</code> — так, URL-адрес, который вы используете <code>../pdfs/project-brief.pdf</code>:</p> + + <pre class="brush: html notranslate"><p>Ссылка на + <a href="../pdfs/project-brief.pdf">краткое описание моего проекта</a>. +</p></pre> + </li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете объединить несколько экземпляров этих функций в сложные URL-адреса, если необходимо, например: <br> + <code>../../../сложный/путь/к/моему/файлу.html</code>.</p> +</div> + +<h3 id="Фрагменты_документа">Фрагменты документа</h3> + +<p>Можно ссылаться на определенную часть документа HTML (известную как <strong>фрагмент документа</strong>), а не только на верхнюю часть документа. Для этого вам сначала нужно назначить атрибут {{htmlattrxref("id")}} элементу, с которым вы хотите связаться. Обычно имеет смысл ссылаться на определённый заголовок, поэтому это выглядит примерно так:</p> + +<pre class="brush: html notranslate"><h2 id="Почтовый_адрес">Почтовый адрес</h2></pre> + +<p>Затем, чтобы связаться с этим конкретным <code>id</code>, вы должны включить его в конец URL-адреса, которому предшествует знак решётки, например:</p> + +<pre class="brush: html notranslate"><p>Хотите написать мне письмо? Используйте наш + <a href="contacts.html#Почтовый_адрес">почтовый адрес</a>. +</p></pre> + +<p>Вы даже можете использовать ссылку на фрагмент документа отдельно для ссылки на <em>другую часть того же документа</em>:</p> + +<pre class="brush: html notranslate"><p> + <a href="#Почтовый_адрес">Почтовый адрес кампании</a> + можно найти в нижней части этой страницы. +</p></pre> + +<h3 id="Абсолютные_и_относительные_URL-адреса">Абсолютные и относительные URL-адреса</h3> + +<p>Два понятия, с которыми вы столкнетесь в Интернете, — это <strong>абсолютный URL</strong> и <strong>относительный URL</strong><strong>:</strong></p> + +<dl> + <dt><strong>Абсолютный URL</strong></dt> + <dd>Указывает на местоположение, определяемое его абсолютным местоположением в Интернете, включая {{glossary("protocol","протокол")}} и {{glossary("domain name","доменное имя")}}. Например, если страница <code>index.html</code> загружается в каталог, называемый <code>projects</code>, который находится внутри корня веб-сервера, а домен веб-сайта — <code>http://www.example.com</code>, страница будет доступна по адресу <code>http://www.example.com/projects/index.html</code> (или даже просто <code>http://www.example.com/projects/</code>), так как большинство веб-серверов просто ищет целевую страницу, такую как <code>index.html</code>, для загрузки, если он не указан в URL-адресе.).</dd> +</dl> + +<p><em>Абсолютный URL</em> всегда будет указывать на одно и то же местоположение, независимо от того, где он используется.</p> + +<dl> + <dt><strong>Относительный URL</strong></dt> + <dd>Указывает расположение <em>относительно </em>файла, с которого вы связываетесь, это больше похоже на случай, который мы рассматривали в предыдущей секции. Для примера, если мы хотим указать со страницы <code>http://www.example.com/projects/index.html</code> на PDF файл, находящийся в той же директории, наш URL может быть просто названием файла — <code>project-brief.pdf</code> — никакой дополнительной информации не требуется. Если PDF расположен в поддериктории <code>pdfs</code> внутри каталога <code>projects</code>, относительная ссылка будет <code>pdfs/project-brief.pdf</code> (аналогичный абсолютный URL был бы <code>http://www.example.com/projects/pdfs/project-brief.pdf</code>.).</dd> +</dl> + +<p><em>Относительный URL</em> будет указывать на различные места, в зависимости от того, где находится файл, в котором он используется, — например, если мы переместим наш файл <code>index.html</code> из каталога <code>projects</code> в корневой каталог веб-сервера (верхний уровень, не в директорию) , то относительный URL <code>pdfs/project-brief.pdf</code> будет вести на <code>http://www.example.com/pdfs/project-brief.pdf</code>, а не на <code>http://www.example.com/projects/pdfs/project-brief.pdf</code>.</p> + +<p>Советуем вам основательно разобраться в этой теме!</p> + +<h2 id="Практика_написания_хороших_ссылок">Практика написания хороших ссылок</h2> + +<p>При написании ссылок рекомендуется следовать некоторым правилам. Давайте рассмотрим их.</p> + +<ul> +</ul> + +<h3 id="Используйте_четкие_формулировки_описания_ссылок">Используйте четкие формулировки описания ссылок</h3> + +<p>На вашей странице легко добавить ссылки. Но этого не совсем достаточно. Мы должны сделать наши ссылки <em>доступными </em>для всех читателей, независимо от их возможностей и инструментов просмотра страницы, которые они предпочитают. Например:</p> + +<ul> + <li>Пользователям программ читающих с экрана нравится переходить по ссылкам на странице, читая адрес ссылки в тексте.</li> + <li>Поисковые системы используют текст ссылки для индексирования файлов, поэтому рекомендуется включать ключевые слова в текст ссылки, чтобы эффективно описывать, куда ведет ссылка.</li> + <li>Пользователи часто бегло просматривают страницу, не читая каждое слово, и их глаза будут привлечены к тексту, который выделяется, например, ссылки. Им будет полезно описание того, куда ведет ссылка.</li> +</ul> + +<p>Взгляните на этот пример:</p> + +<p><em><strong>Хороший</strong> текст ссылки:</em> <a href="https://firefox.com">Скачать Firefox</a></p> + +<pre class="brush: html notranslate"><p><a href="https://firefox.com/"> + Скачать Firefox +</a></p></pre> + +<p><em><strong>Плохой</strong> текст ссылки:</em> <a href="https://firefox.com/">Нажми сюда</a>, чтобы скачать Firefox</p> + +<pre class="brush: html notranslate"><p><a href="https://firefox.com/"> + Нажми сюда +</a> +чтобы скачать Firefox</p> +</pre> + +<p>Советы:</p> + +<ul> + <li>Не пишите URL-адрес как часть текста ссылки. URL-адреса выглядят сложными, а звучат ещё сложнее, когда программы чтения с экрана читают их по буквам.</li> + <li>Не пишите «ссылка» или «ссылки на» в тексте ссылки — это лишнее. Программы чтения с экрана сами проговоаривают, что есть ссылка. На экране пользователи также видят, что есть ссылка, потому что ссылки, как правило, оформлены в другом цвете и подчеркнуты (подчёркивая ссылки, вы соблюдаете правила хорошего тона, поскольку пользователи привыкли к этому).</li> + <li>Следите за тем, чтобы текст ссылки был как можно короче. Длинный текст ссылки особенно раздражает пользователей программ чтения с экрана, которым придётся услышать всё, что написано.</li> + <li>Минимизируйте случаи, когда несколько копий одного и того же текста ссылок указывает на разные страницы. Это может вызвать проблемы для пользователей программ чтения с экрана, которые часто вызывают список ссылок — несколько ссылок, помеченных как «нажмите здесь», «нажмите здесь», «нажмите здесь», будут путать.</li> +</ul> + +<h3 id="Используйте_относительные_ссылки_где_это_возможно">Используйте относительные ссылки, где это возможно</h3> + +<p>Из прочитанного выше, вы можете подумать, что всё время использовать абсолютные ссылки — хорошая идея; в конце концов, они не ломаются, когда страница перемещается. Тем не менее, лучше использовать относительные ссылки везде, где это возможно, в пределах <em>одного сайта</em> (при ссылке на <em>другие сайты</em> необходимо использовать абсолютную ссылку):</p> + +<ul> + <li>Во-первых, гораздо проще прописать в коде относительные URL-адреса, как правило, они намного короче абсолютных URL-адресов, что значительно упрощает чтение кода</li> + <li>Во-вторых, использование относительных URL-адресов эффективней по следующей причине. Когда вы используете абсолютный URL-адрес, браузер начинает поиск реального местоположения сервера запрашивая адрес у Domain Name System ({{glossary("DNS")}}; также прочтите <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/How_the_Web_works">Как работает web</a>), затем он переходит на этот сервер и находит файл, который запрашивается. С относительным URL-адресом проще: браузер просто ищет файл, который запрашивается на том же сервере. Используя абсолютные URL-адреса вместо относительных, вы постоянно нагружаете свой браузер дополнительной работой.</li> +</ul> + +<h3 id="Создавая_ссылки_на_не_HTML_ресурсы_—_добавляйте_описание">Создавая ссылки на не HTML ресурсы — добавляйте описание</h3> + +<p>Когда вы создаёте ссылку на файл, нажав на который можно загрузить документ PDF или Word или открыть просмотр видео, прослушивание аудио файла или перейти на страницу с другим, неожиданным для пользователя результатом (всплывающее окно или загрузка Flash-фильма), добавляйте четкую формулировку, чтобы уменьшить путаницу. Отсуствие описания может раздражать пользователя. Приведем пример:</p> + +<ul> + <li>Если вы используете соединение с низкой пропускной способностью и вдруг нажмёте на ссылку без описания, начнётся загрузка большого файла.</li> + <li>Если у вас нет установленного Flash-плеера и вы нажмёте ссылку, то внезапно перейдёте на страницу с Flash-контентом.</li> +</ul> + +<p>Посмотрите на примеры, чтобы увидеть, как добавить описание:</p> + +<pre class="brush: html notranslate"><p><a href="http://www.example.com/large-report.pdf"> + Скачать отчет о продажах (PDF, 10MB) +</a></p> + +<p><a href="http://www.example.com/video-stream/"> + Посмотреть видео (видео откроется в отдельном окне, HD качество) +</a></p> + +<p><a href="http://www.example.com/car-game"> + Играть в гонки (необходим Flash) +</a></p></pre> + +<h3 id="Используйте_атрибут_download_когда_создаете_ссылку">Используйте атрибут download, когда создаете ссылку</h3> + +<p>Когда создаёте ссылку на файл, который должен быть загружен, а не открыт в браузере, можете использовать атрибут <code>download</code>, чтобы создать имя файла по умолчанию для сохранения . Приведем пример ссылки для загрузки браузера Firefox 39:</p> + +<pre class="brush: html notranslate"><a href="https://download.mozilla.org/?product=firefox-39.0-SSL&os=win&lang=en-US" + download="firefox-39-installer.exe"> + Скачать Firefox 39 для Windows +</a></pre> + +<h2 id="Активное_изучение_создание_меню_навигации">Активное изучение: создание меню навигации</h2> + +<p>Для этого упражнения мы хотим, чтобы вы создали ссылки на страницы в меню навигации в многостраничном сайте. Это один из распространенных способов создания сайта: на каждой странице используется одна и та же структура страниц, включая одно и то же меню навигации, поэтому при нажатии ссылок создается впечатление, что вы остаетесь в одном месте: меню остается на месте, а контент меняется.</p> + +<p>Вам нужно скачать или создать следующие страницы в одном каталоге (Смотрите <a href="https://github.com/mdn/learning-area/tree/master/html/introduction-to-html/navigation-menu-start">navigation-menu-start</a>):</p> + +<ul> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/index.html">index.html</a></li> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/projects.html">projects.html</a></li> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/pictures.html">pictures.html</a></li> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/social.html">social.html</a></li> +</ul> + +<p>Что делать:</p> + +<ol> + <li>Добавьте неупорядоченный список в указанном месте в любом html-файле. Список должен состоять из имен страниц (index, projects и т.д.). Меню навигации обычно представляет собой список ссылок, поэтому создание неупорядоченного списка семантически верно.</li> + <li>Создайте ссылки каждому элементу списка, ведущие на эти страницы.</li> + <li>Скопируйте созданное меню в каждую страницу.</li> + <li>На каждой странице удалите только ссылку, которая указывает на эту же страницу (на странице index.html удалить ссылку index и так далее). Дело в том, что, находясь на странице index.html, нам незачем видеть ссылку в меню на эту же страницу. С одной стороны, нам незачем ещё раз переходить на эту же страницу, с другой, такой прием помогает визуально определить, смотря на меню, в какой части сайта мы находимся.</li> +</ol> + +<p>Когда закончите задание, посмотрите, как это должно выглядеть:</p> + +<p><img alt="An example of a simple HTML navigation menu, with home, pictures, projects, and social menu items" src="https://mdn.mozillademos.org/files/12411/navigation-example.png" style="display: block; margin: 0 auto;"></p> + +<div class="note"> +<p>Если не удается сделать, или вы неуверены, что сделали верно, посмотрите наш вариант <a href="https://github.com/mdn/learning-area/tree/master/html/introduction-to-html/navigation-menu-marked-up">navigation-menu-marked-up</a>.</p> +</div> + +<h2 id="Ссылки_электронной_почты">Ссылки электронной почты</h2> + +<p>Можно создавать ссылки или кнопки, которые при нажатии открывают новое исходящее сообщение электронной почты, а не ссылку на ресурс или страницу. Для этого используется элемент {{HTMLElement("a")}} и <code>mailto:</code> — <em>адрес почты</em>.</p> + +<p>Самыми простыми и часто используемыми формами <code>mailto:</code> являются <em>subject</em>, <em>cc</em>,<em> bcc</em> и <em>body</em>; дальше прописываем адрес электронной почты. Например:</p> + +<pre class="brush: html notranslate"><a href="mailto:nowhere@mozilla.org">Отправить письмо для nowhere</a> +</pre> + +<p>В результате полчим ссылку вида: <a href="mailto:nowhere@mozilla.org">Отправить письмо для nowhere</a>.</p> + +<p>Сам адрес электронной почты не является обязательным для заполнения. Если оставить это поле пустым (в поле {{htmlattrxref("href", "a")}} оставить только "mailto:"), откроется новое исходящее сообщение почтовой программой, в поле получателя будет пусто. Это можно использовать для кнопки "Поделиться".</p> + +<h3 id="Особенности_и_детали">Особенности и детали</h3> + +<p>Помимо адреса электронной почты, вы можете предоставить другую информацию. Фактически, любые стандартные поля для отправки почты могут быть добавлены к указанному вами адресу <code>mailto</code>. Часто используемыми из них являются «subject», «cc» и «body» (которые не являются истинным полем заголовка, но позволяют указать дополнительную информацию для нового сообщения электронной почты). Каждое поле и его значение задаются в качестве условия запроса.</p> + +<p>Вот пример который включает cc(кому отправить копию сообщения, все получатели письма видят список тех кто это письмо получит), bcc(скрытый адрес получателя, никто из получателей не будет видеть полный список получателей письма), subject(тема письма) и body(текст сообщения):</p> + +<pre class="brush: html notranslate"><a href="mailto:nowhere@mozilla.org?cc=name2@rapidtables.com&bcc=name3@rapidtables.com&amp;subject=The%20subject%20of%20the%20email &amp;body=The%20body%20of%20the%20email"> + Send mail with cc, bcc, subject and body +</a></pre> + +<div class="note"> +<p><strong>Примечание:</strong> Значение каждого поля должно быть написано в URL-кодировке (то есть с непечатаемыми символами и пробелами <a href="http://en.wikipedia.org/wiki/Percent-encoding">percent-escaped</a>). Обратите внимание на знак вопроса (?) для разделения основного адреса и дополнительных полей, амперсанд (&) для разделения каждого поля <code>mailto:</code> URL. Для этого используется стандартное описание URL запроса. Прочтите <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data#The_GET_method">о методе GET</a>, чтобы лучше понимать описание URL запроса.</p> +</div> + +<p>Вот несколько примеров использования <code>mailto</code> URLs:</p> + +<ul> + <li><a href="mailto:">mailto:</a></li> + <li><a href="mailto:nowhere@mozilla.org">mailto:nowhere@mozilla.org</a></li> + <li><a href="mailto:nowhere@mozilla.org,nobody@mozilla.org">mailto:nowhere@mozilla.org,nobody@mozilla.org</a></li> + <li><a href="mailto:nowhere@mozilla.org?cc=nobody@mozilla.org">mailto:nowhere@mozilla.org?cc=nobody@mozilla.org</a></li> + <li><a href="mailto:nowhere@mozilla.org?cc=nobody@mozilla.org&subject=This%20is%20the%20subject">mailto:nowhere@mozilla.org?cc=nobody@mozilla.org&subject=This%20is%20the%20subject</a></li> +</ul> + +<h2 id="Заключение">Заключение</h2> + +<p>Этой информации достаточно для создания ссылок! Вы вернётесь к ссылкам позже, когда начнёте изучать стили. Дальше вы рассмотрите семантику текста и более сложные и необычные возможности, которые будут полезны при создании контента сайта. В следующей главе будет рассматриваться продвинутое форматирование текста.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></li> +</ul> + +<div id="SL_balloon_obj" style="display: block;"> +<div class="SL_ImTranslatorLogo" id="SL_button"></div> + +<div id="SL_shadow_translation_result2" style="display: none;"></div> + +<div id="SL_shadow_translator" style="display: none;"> +<div id="SL_planshet"> +<div id="SL_arrow_up" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;"></div> + +<div id="SL_Bproviders"> +<div class="SL_BL_LABLE_ON" id="SL_P0" title="Google">G</div> + +<div class="SL_BL_LABLE_ON" id="SL_P1" title="Microsoft">M</div> + +<div class="SL_BL_LABLE_ON" id="SL_P2" title="Translator">T</div> +</div> + +<div id="SL_alert_bbl" style="display: none;"> +<div id="SLHKclose" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;"></div> + +<div id="SL_alert_cont"></div> +</div> + +<div id="SL_TB"> +<table id="SL_tables"> + <tbody> + <tr> + <td class="SL_td"><input></td> + <td class="SL_td"><select><option value="auto">Detect language</option><option value="af">Afrikaans</option><option value="sq">Albanian</option><option value="ar">Arabic</option><option value="hy">Armenian</option><option value="az">Azerbaijani</option><option value="eu">Basque</option><option value="be">Belarusian</option><option value="bn">Bengali</option><option value="bs">Bosnian</option><option value="bg">Bulgarian</option><option value="ca">Catalan</option><option value="ceb">Cebuano</option><option value="ny">Chichewa</option><option value="zh-CN">Chinese (Simplified)</option><option value="zh-TW">Chinese (Traditional)</option><option value="hr">Croatian</option><option value="cs">Czech</option><option value="da">Danish</option><option value="nl">Dutch</option><option value="en">English</option><option value="eo">Esperanto</option><option value="et">Estonian</option><option value="tl">Filipino</option><option value="fi">Finnish</option><option value="fr">French</option><option value="gl">Galician</option><option value="ka">Georgian</option><option value="de">German</option><option value="el">Greek</option><option value="gu">Gujarati</option><option value="ht">Haitian Creole</option><option value="ha">Hausa</option><option value="iw">Hebrew</option><option value="hi">Hindi</option><option value="hmn">Hmong</option><option value="hu">Hungarian</option><option value="is">Icelandic</option><option value="ig">Igbo</option><option value="id">Indonesian</option><option value="ga">Irish</option><option value="it">Italian</option><option value="ja">Japanese</option><option value="jw">Javanese</option><option value="kn">Kannada</option><option value="kk">Kazakh</option><option value="km">Khmer</option><option value="ko">Korean</option><option value="lo">Lao</option><option value="la">Latin</option><option value="lv">Latvian</option><option value="lt">Lithuanian</option><option value="mk">Macedonian</option><option value="mg">Malagasy</option><option value="ms">Malay</option><option value="ml">Malayalam</option><option value="mt">Maltese</option><option value="mi">Maori</option><option value="mr">Marathi</option><option value="mn">Mongolian</option><option value="my">Myanmar (Burmese)</option><option value="ne">Nepali</option><option value="no">Norwegian</option><option value="fa">Persian</option><option value="pl">Polish</option><option value="pt">Portuguese</option><option value="pa">Punjabi</option><option value="ro">Romanian</option><option value="ru">Russian</option><option value="sr">Serbian</option><option value="st">Sesotho</option><option value="si">Sinhala</option><option value="sk">Slovak</option><option value="sl">Slovenian</option><option value="so">Somali</option><option value="es">Spanish</option><option value="su">Sundanese</option><option value="sw">Swahili</option><option value="sv">Swedish</option><option value="tg">Tajik</option><option value="ta">Tamil</option><option value="te">Telugu</option><option value="th">Thai</option><option value="tr">Turkish</option><option value="uk">Ukrainian</option><option value="ur">Urdu</option><option value="uz">Uzbek</option><option value="vi">Vietnamese</option><option value="cy">Welsh</option><option value="yi">Yiddish</option><option value="yo">Yoruba</option><option value="zu">Zulu</option></select></td> + <td class="SL_td"> + <div id="SL_switch_b" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;" title="Switch languages"></div> + </td> + <td class="SL_td"><select><option value="af">Afrikaans</option><option value="sq">Albanian</option><option value="ar">Arabic</option><option value="hy">Armenian</option><option value="az">Azerbaijani</option><option value="eu">Basque</option><option value="be">Belarusian</option><option value="bn">Bengali</option><option value="bs">Bosnian</option><option value="bg">Bulgarian</option><option value="ca">Catalan</option><option value="ceb">Cebuano</option><option value="ny">Chichewa</option><option value="zh-CN">Chinese (Simplified)</option><option value="zh-TW">Chinese (Traditional)</option><option value="hr">Croatian</option><option value="cs">Czech</option><option value="da">Danish</option><option value="nl">Dutch</option><option value="en">English</option><option value="eo">Esperanto</option><option value="et">Estonian</option><option value="tl">Filipino</option><option value="fi">Finnish</option><option value="fr">French</option><option value="gl">Galician</option><option value="ka">Georgian</option><option value="de">German</option><option value="el">Greek</option><option value="gu">Gujarati</option><option value="ht">Haitian Creole</option><option value="ha">Hausa</option><option value="iw">Hebrew</option><option value="hi">Hindi</option><option value="hmn">Hmong</option><option value="hu">Hungarian</option><option value="is">Icelandic</option><option value="ig">Igbo</option><option value="id">Indonesian</option><option value="ga">Irish</option><option value="it">Italian</option><option value="ja">Japanese</option><option value="jw">Javanese</option><option value="kn">Kannada</option><option value="kk">Kazakh</option><option value="km">Khmer</option><option value="ko">Korean</option><option value="lo">Lao</option><option value="la">Latin</option><option value="lv">Latvian</option><option value="lt">Lithuanian</option><option value="mk">Macedonian</option><option value="mg">Malagasy</option><option value="ms">Malay</option><option value="ml">Malayalam</option><option value="mt">Maltese</option><option value="mi">Maori</option><option value="mr">Marathi</option><option value="mn">Mongolian</option><option value="my">Myanmar (Burmese)</option><option value="ne">Nepali</option><option value="no">Norwegian</option><option value="fa">Persian</option><option value="pl">Polish</option><option value="pt">Portuguese</option><option value="pa">Punjabi</option><option value="ro">Romanian</option><option selected value="ru">Russian</option><option value="sr">Serbian</option><option value="st">Sesotho</option><option value="si">Sinhala</option><option value="sk">Slovak</option><option value="sl">Slovenian</option><option value="so">Somali</option><option value="es">Spanish</option><option value="su">Sundanese</option><option value="sw">Swahili</option><option value="sv">Swedish</option><option value="tg">Tajik</option><option value="ta">Tamil</option><option value="te">Telugu</option><option value="th">Thai</option><option value="tr">Turkish</option><option value="uk">Ukrainian</option><option value="ur">Urdu</option><option value="uz">Uzbek</option><option value="vi">Vietnamese</option><option value="cy">Welsh</option><option value="yi">Yiddish</option><option value="yo">Yoruba</option><option value="zu">Zulu</option></select></td> + <td class="SL_td"> + <div id="SL_TTS_voice" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;" title="Listen to the translation"></div> + </td> + <td class="SL_td"> + <div class="SL_copy" id="SL_copy" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;" title="Copy translation"></div> + </td> + <td class="SL_td"> + <div id="SL_bbl_font_patch"></div> + + <div class="SL_bbl_font" id="SL_bbl_font" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;" title="Font size"></div> + </td> + <td class="SL_td"> + <div id="SL_bbl_help" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;" title="Help"></div> + </td> + <td class="SL_td"> + <div class="SL_pin_off" id="SL_pin" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;" title="Pin pop-up bubble"></div> + </td> + </tr> + </tbody> +</table> +</div> +</div> + +<div id="SL_shadow_translation_result"></div> + +<div class="SL_loading" id="SL_loading" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;"></div> + +<div id="SL_player2"></div> + +<div id="SL_alert100">Text-to-speech function is limited to 200 characters</div> + +<div id="SL_Balloon_options" style="background: rgb(255, 255, 255) repeat scroll 0% 0%;"> +<div id="SL_arrow_down" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;"></div> + +<table id="SL_tbl_opt" style="width: 100%;"> + <tbody> + <tr> + <td><input></td> + <td> + <div id="SL_BBL_IMG" style="background: rgba(0, 0, 0, 0) repeat scroll 0% 0%;" title="Show Translator's button 3 second(s)"></div> + </td> + <td><a class="SL_options" title="Show options">Options</a> : <a class="SL_options" title="Translation History">History</a> : <a class="SL_options" title="ImTranslator Feedback">Feedback</a> : <a class="SL_options" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=GD9D8CPW8HFA2" title="Make a small contribution">Donate</a></td> + <td><span id="SL_Balloon_Close" title="Close">Close</span></td> + </tr> + </tbody> +</table> +</div> +</div> +</div> diff --git a/files/ru/learn/html/введение_в_html/структура_документа_и_веб-сайта/index.html b/files/ru/learn/html/введение_в_html/структура_документа_и_веб-сайта/index.html new file mode 100644 index 0000000000..13f4f458d1 --- /dev/null +++ b/files/ru/learn/html/введение_в_html/структура_документа_и_веб-сайта/index.html @@ -0,0 +1,291 @@ +--- +title: Структура документа и веб-сайта +slug: Learn/HTML/Введение_в_HTML/Структура_документа_и_веб-сайта +tags: + - Guide + - HTML + - Базовая разметка + - Гайд + - Для новичков + - С чего начать + - Структура сайта +translation_of: Learn/HTML/Introduction_to_HTML/Document_and_website_structure +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">В дополнение к определению отдельных частей вашей страницы (таких как «абзац» или «изображение»), {{glossary("HTML")}} также содержит ряд элементов блочного уровня, используемых для определения областей вашего веб-сайта (такие как «заголовок», «навигационное меню», «колонка основного содержимого»). В этой статье рассматривается, как планировать базовую структуру сайта и писать HTML для представления этой структуры.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовое знакомство с HTML, описано в разделе <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Начало работы с HTML</a>. Форматирование текста в HTML, описано в разделе <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">Основы текста в HTML</a>. Как работают гиперссылки, описано в разделе <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Создание гиперссылок</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Изучить, как структурировать документ с помощью семантических тегов и как разработать структуру простого веб-сайта.</td> + </tr> + </tbody> +</table> + +<h2 id="Основные_составляющие_документа">Основные составляющие документа</h2> + +<p>Веб-страницы могут и будут отличаться друг от друга, но все они, преимущественно, состоят из аналогичных стандартных компонентов, если только страница не отображает полноэкранное видео или игру, не является частью какого-либо художественного проекта или просто плохо структурирована:</p> + +<dl> + <dt>Заголовок (колонтитул)</dt> + <dd>Обычно это большая полоса вверху страницы, с крупным заголовком и / или логотипом. Здесь указывается общая информация о веб-сайте, не меняющаяся от страницы к странице.</dd> + <dt>Навигационное меню</dt> + <dd>Ссылки на основные разделы сайта; обычно в виде кнопок, ссылок или вкладок. Также как и заголовок, навигация остается неизменной на всех страницах сайта — наличие непоследовательной навигации на Вашем сайте запутает и разочарует пользователей. Многие веб-дизайнеры считают панель навигации частью заголовка, а не отдельным компонентом, но это не является обязательным требованием; на самом деле, некоторые также утверждают, что их разделение на отдельные компоненты улучшает <a href="/en-US/docs/Learn/Accessibility">доступность</a>, поскольку раздельная структура будет понятнее для людей, пользующихся считывателями экрана.</dd> + <dt>Основное содержимое</dt> + <dd>Большая область в центре страницы, содержащая, в основном, уникальный контент данной веб-страницы, например видео, которое вы хотите посмотреть, или рассказ, который вы читаете, или карту, которую вы хотите просмотреть, или заголовки новостей и т. д. Это одна из частей сайта, которая определенно будет меняться от страницы к странице!</dd> + <dt>Боковая панель</dt> + <dd>Как правило, содержит некоторую второстепенную информацию, ссылки, цитаты, рекламу и т.д. Обычно она относится к содержимому в основном контенте (например, на странице со статьей, боковая панель может содержать биографию автора или ссылки на связанные статьи), но в некоторых случаях здесь размещают и другие элементы, например, вторичную навигационную систему.</dd> + <dt>Нижний колонтитул (футер)</dt> + <dd>Полоса в нижней части страницы, которая обычно содержит уведомления об авторских правах или контактную информацию. Это место для размещения общей информации (например, заголовка), но обычно эта информация не является критичной или вторична для самого веб-сайта. Нижний колонтитул также иногда используется для {{Glossary("SEO")}} целей, предоставляя ссылки для быстрого доступа к популярному контенту.</dd> +</dl> + +<p>"Типичный веб-сайт" может быть структурирован примерно так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/17069/Sample_website__ru.png" style="border-style: solid; border-width: 1px; height: 291px; width: 600px;"></p> + +<h2 id="HTML_для_структурирования_содержимого">HTML для структурирования содержимого</h2> + +<p>Пример, показанный сверху, не красив и примитивен, но идеально подходит для иллюстрирования типичного макета веб-сайта. У некоторых веб-сайтов больше колонок, некоторые — более сложные, но идею Вы поняли. С правильным CSS Вы могли бы использовать практически любые элементы для обёртывания различных разделов и стилизовать их так, как Вам хочется, но, как обсуждалось ранее, нам нужно уважать семантику и <strong>использовать правильный элемент для правильной работы</strong>. </p> + +<p>Это потому, что визуальные эффекты — это ещё не самое главное. Мы используем цвет и размер шрифта для привлечения внимания посетителей к наиболее полезным частям содержимого, такого как навигационное меню или связанные ссылки, но что насчет людей со слабым зрением, к примеру, для которых концепция "розового" и "большого шрифта" не будет полезной?</p> + +<div class="note"> +<p><strong>Заметка</strong>: Люди с дальтонизмом составляют около <a href="http://www.color-blindness.com/2006/04/28/colorblind-population/">8% мирового населения</a>. Слепые и слабовидящие люди составляют примерно 4-5% населения мира (в 2012 году в мире было <a href="https://en.wikipedia.org/wiki/Visual_impairment">285 миллионов таких людей</a>, а общая численность населения составляла <a href="https://en.wikipedia.org/wiki/World_human_population#/media/File:World_population_history.svg">около 7 миллиардов</a>).</p> +</div> + +<p>В своём HTML-коде Вы можете размечать разделы содержимого сайта на основе их <em>функциональности</em> — использовать элементы, которые представляют разделы контента, описанные выше, а вспомогательные технологии, такие как программы чтения с экрана, смогут распознавать эти элементы и помогать в таких задачах, как "найти основную навигацию" или "найти основное содержимое". Как мы упоминали ранее в ходе курса, существует ряд <a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Why_do_we_need_structure">последствий неиспользования правильной структуры элементов и семантики для правильной работы.</a></p> + +<p>Для реализации такой семантической разметки HTML предоставляет выделенные теги, которые можно использовать для создания таких разделов, например:</p> + +<ul> + <li><strong>Заголовок: </strong>{{htmlelement("header")}}.</li> + <li><strong>Навигационное меню: </strong>{{htmlelement("nav")}}.</li> + <li><strong>Основное содержимое: </strong>{{htmlelement("main")}}, с различными подразделами содержимого, представленными элементами {{HTMLElement("article")}}, {{htmlelement("section")}} и {{htmlelement("div")}}.</li> + <li><strong>Боковая панель: </strong>{{htmlelement("aside")}}, обычно располагается внутри {{htmlelement("main")}}.</li> + <li><strong>Нижний колонтитул: </strong>{{htmlelement("footer")}}.</li> +</ul> + +<h3 id="Активное_обучение_исследование_кода_для_нашего_примера">Активное обучение: исследование кода для нашего примера</h3> + +<p>Наш пример, представленный выше, содержит следующий код (Вы также можете <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/document_and_website_structure/index.html">найти пример в нашем репозитории Github</a>). Мы хотели бы, чтобы Вы взгянули на приведенный выше пример, а затем просмотрели код ниже, чтобы узнать, из каких частей он состоит.</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + + <title>Заголовок моей страницы</title> + <link href="https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300|Sonsie+One" rel="stylesheet" type="text/css"> + <link rel="stylesheet" href="style.css"> + + <!-- следующие 3 строки нужны для корректного отображения семантических элементов HTML5 в старых версиях Internet Explorer--> + <!--[if lt IE 9]> + <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script> + <![endif]--> + </head> + + <body> + <!-- Вот наш главный заголовок, который используется на всех страницах нашего веб-сайта --> + + <header> + <h1>Заголовок</h1> + </header> + + <nav> + <ul> + <li><a href="#">Домашняя страница</a></li> + <li><a href="#">Наша команда</a></li> + <li><a href="#">Проекты</a></li> + <li><a href="#">Контакты</a></li> + </ul> + + <!-- Форма поиска — это еще один распространенный нелинейный способ навигации по веб-сайту. --> + + <form> + <input type="search" name="q" placeholder="Search query"> + <input type="submit" value="Go!"> + </form> + </nav> + + <!-- Здесь основное содержимое нашей страницы --> + <main> + + <!-- Она содержит статью --> + <article> + <h2>Заголовок статьи</h2> + + <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Donec a diam lectus. Set sit amet ipsum mauris. Maecenas congue ligula as quam viverra nec consectetur ant hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur.</p> + + <h3>Подраздел</h3> + + <p>Donec ut librero sed accu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor.</p> + + <p>Pelientesque auctor nisi id magna consequat sagittis. Curabitur dapibus, enim sit amet elit pharetra tincidunt feugiat nist imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros.</p> + + <h3>Ещё один подраздел</h3> + + <p>Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum soclis natoque penatibus et manis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p> + + <p>Vivamus fermentum semper porta. Nunc diam velit, adipscing ut tristique vitae sagittis vel odio. Maecenas convallis ullamcorper ultricied. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, is fringille sem nunc vet mi.</p> + </article> + + <!-- Дополнительный контент также может быть вложен в основной контент --> + <aside> + <h2>Связанные темы</h2> + + <ul> + <li><a href="#">Мне нравится стоять рядом с берегом моря</a></li> + <li><a href="#">>Мне нравится стоять рядом с морем</a></li> + <li><a href="#">Даже на севере Англии</a></li> + <li><a href="#">Здесь не перестаёт дождь</a></li> + <li><a href="#">Лаааадно...</a></li> + </ul> + </aside> + + </main> + + <!-- И вот наш главный нижний колонтитул, который используется на всех страницах нашего веб-сайта --> + + <footer> + <p>©Авторские права никому не принадлежат, 2050. Все права защищены.</p> + </footer> + + </body> +</html></pre> + +<p>Потратьте некоторое время, чтобы просмотреть код и понять его — комментарии внутри кода также помогут Вам в этом. Мы не просим Вас делать ничего больше в этом уроке, потому что ключ к пониманию макета документа заключается в написании осмысленной структуры HTML, а затем её развёртывании с помощью CSS. Мы подождем, пока вы не начнете изучать CSS-макет как часть темы CSS.</p> + +<h2 id="Подробнее_об_элементах_HTML_макета">Подробнее об элементах HTML макета</h2> + +<p>Полезно понять общий смысл всех структурных элементов HTML — это то, над чем вы будете работать постепенно, когда начнёте получать больше опыта с веб-разработкой. Вы можете ознакомиться с деталями, прочитав статью <a href="/en-US/docs/Web/HTML/Element">HTML-элементы</a>. Пока что это основные определения, которые вы должны попытаться понять:</p> + +<ul> + <li>{{HTMLElement('main')}} предназначен для содержимого, <em>уникального для этой страницы</em>. Используйте <code><main></code> только <em>один</em> раз на странице и размещайте прямо внутри {{HTMLElement('body')}}. В идеале он не должен быть вложен в другие элементы.</li> + <li>{{HTMLElement('article')}} окружает блок связанного содержимого, который имеет смысл сам по себе без остальной части страницы (например, один пост в блоге).</li> + <li>{{HTMLElement('section')}} подобен <code><article></code>, но больше подходит для группирования одной части страницы, которая представляет собой одну часть функциональности (например, мини-карту или набор заголовков статей и сводок). Считается хорошей практикой начинать каждый раздел с <a href="/en-US/Learn/HTML/Howto/Set_up_a_proper_title_hierarchy">заголовка</a>. Также обратите внимание, что в зависимости от контекста вы можете разбить <code><article></code> на несколько <code><section></code> или, наоборот, <code><section></code> на несколько <code><article></code>.</li> + <li>{{HTMLElement('aside')}} содержит контент, который не имеет прямого отношения к основному содержимому, но может содержать дополнительную информацию, косвенно связанную с ним (словарь, биография автора, связанные ссылки и т. д.).</li> + <li>{{HTMLElement('header')}} представляет собой группу вводного содержимого. Если он дочерний элемент {{HTMLElement('body')}}, то он определяет глобальный заголовок веб-страницы, но если он дочерний элемент {{HTMLElement('article')}} или {{HTMLElement('section')}}, то определяет конкретный заголовок для этого раздела (постарайтесь не путать его с <a href="/en-US/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML#Adding_a_title">titles и headings</a>). </li> + <li>{{HTMLElement('nav')}} содержит основные функции навигации для страницы. Так же часто в нем можно увидеть логотип и / или название сайта или компании. Вторичные ссылки и т. д. не входят в навигацию.</li> + <li>{{HTMLElement('footer')}} представляет собой группу конечного контента для страницы.</li> +</ul> + +<h3 id="Несемантические_обертки">Несемантические обертки</h3> + +<p>Иногда Вы будете сталкиваться с ситуацией, когда Вы не можете найти идеальный семантический элемент, чтобы сгруппировать некоторые элементы вместе или обернуть некоторый контент. Иногда Вам просто нужно будет сгруппировать несколько элементов вместе, чтобы применить к ним, как к единой сущности, {{glossary("CSS")}} или {{glossary("JavaScript")}}. Для таких случаев в HTML есть элементы {{HTMLElement("div")}} и {{HTMLElement("span")}}. Вам следует использовать их с подходящим значением атрибута {{htmlattrxref('class')}} или {{htmlattrxref('id')}}, чтобы можно было легко получить к ним доступ.</p> + +<p>{{HTMLElement("span")}} — это строчный несемантический элемент, который стоит использовать только если Вы не можете подобрать более подходящий семантический текстовый элемент для обёртывания контента или если не хотите добавлять какие-либо конкретные значения. Например:</p> + +<pre class="brush: html notranslate"><p>Пьяный Король возвратился в свою комнату в 01:00 +и всё никак не мог войти в дверь: хмель мешал <span class="editor-note">[Примечание редактора: В этот момент +свет на сцене должен быть приглушён]</span>.</p></pre> + +<p>В этом примере примечание редактора просто сообщает дополнительные пожелания режиссёру пьесы. В нем нет особого семантического значения. Для слабовидящих пользователей, возможно, примечание будет отделено от основного содержимого с помощью CSS.</p> + +<p>{{HTMLElement("div")}} — это блочный несемантический элемент, который следует использовать только если Вы не можете подобрать более подходящий семантический блочный элемент или если не хотите добавлять какие-либо конкретные значения. Например, представьте виджет корзины в интернет-магазине, который Вы можете открыть в любой момент нахождения на сайте:</p> + +<pre class="brush: html notranslate"><div class="shopping-cart"> + <h2>Корзина</h2> + <ul> + <li> + <p><a href=""><strong>Silver earrings</strong></a>: $99.95.</p> + <img src="../products/3333-0985/thumb.png" alt="Серебряные серьги"> + </li> + <li> + ... + </li> + </ul> + <p>Итого: $237.89</p> +</div></pre> + +<p>Ему не подходит <code><aside></code>, поскольку это не обязательно относится к основному содержимому страницы (Вы хотите, чтобы его можно было просматривать из любого места). Также не подходит и <code><section></code>, т. к. это не часть основного содержимого страницы. Поэтому <code><div></code> подходит в этом случае. Мы включили заголовок в качестве указателя, чтобы помочь пользователям программ чтения с экрана в его поиске.</p> + +<div class="warning"> +<p><strong>Внимание</strong>: <code>div</code> настолько просто использовать, что легко переборщить. Поскольку они не несут никакого семантического значения, они просто загромождают Ваш HTML-код. Старайтесь использовать их только тогда, когда нет лучшего семантического решения, и постарайтесь свести их использование к минимуму, иначе Вам будет трудно обновлять и поддерживать Ваши документы.</p> +</div> + +<h3 id="Перенос_строки_и_горизонтальный_разделитель">Перенос строки и горизонтальный разделитель</h3> + +<p>Два элемента, которые Вы будете периодически использовать или захотите узнать о них: {{htmlelement("br")}} и {{htmlelement("hr")}}:</p> + +<p><code><br></code> создает разрыв строки в абзаце, и это единственный способ изменить жёсткую структуру в ситуации, когда Вам нужна серия фиксированных коротких строк, например, в почтовом адресе или стихотворении. Пример:</p> + +<pre class="brush: html notranslate"><p>Жила-была девчушка Нелл,<br> +Любившая писать HTML:<br> +Её семантика ужасна была — <br> +Она и сама прочитать ничего не могла.</p></pre> + +<p>Без элемента <code><br></code> абзац разместится в одну длинную линию (как было сказано ранее, <a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Whitespace_in_HTML">HTML игнорирует переносы строк</a>), а с ним в коде — разметка будет выглядеть следующим образом:</p> + +<p>Жила-была девчушка Нелл,<br> + Любившая писать HTML:<br> + Её семантика ужасна была —<br> + Она и сама прочитать ничего не могла.</p> + +<p><code><hr></code> создает горизонтальный разделитель в документе, это означает тематическое изменение текста (например, изменение темы или сцены). Визуально он просто похож на горизонтальную линию. В качестве примера:</p> + +<pre class="notranslate"><p>Рон был зажат в углу адскими тварями. Он боялся, но твёрдо решил защитить своих друзей, поднял свою волшебную палочку и приготовился к битве, надеясь, что справится со своим несчастьем.</p> +<hr> +<p>Тем временем Гарри сидел дома с раскрытым указом и размышлял о том, когда выйдут новые серии спин-оффов; в это время зачарованное письмо пархнуло в окно и приземлилось у него на коленях. Он прочитал его и подскочил на ноги; он подумал: "Думаю, самое время вернуться к работе".</p></pre> + +<p>Будет выглядеть примерно так:</p> + +<p>Рон был зажат в углу адскими тварями. Он боялся, но твёрдо решил защитить своих друзей, поднял свою волшебную палочку и приготовился к битве, надеясь, что справится со своим несчастьем.</p> + +<hr> +<p>Тем временем Гарри сидел дома с раскрытым указом и размышлял о том, когда выйдут новые серии спин-оффов; в это время зачарованное письмо пархнуло в окно и приземлилось у него на коленях. Он прочитал его и подскочил на ноги; он подумал: "Думаю, самое время вернуться к работе".</p> + +<h2 id="Планирование_простого_веб-сайта">Планирование простого веб-сайта</h2> + +<p>Когда вы уже спланировали содержание одной веб-страницы, следующий логический шаг — продумать содержание всего веб-сайта: какие страницы нужны, как они будут устроены и связаны друг с другом для лучшего восприятия пользователем. Это называется {{glossary("Information architecture")}}. В большом, сложном веб-сайте на планирование может уходить много времени, однако спроектировать простой веб-сайт из нескольких страниц может быть очень легко и весело!</p> + +<ol> + <li><span class="tlid-translation translation">Имейте в виду, что у вас будет несколько элементов, общих для большинства (если не всех) страниц — например, меню навигации и содержимого нижнего колонтитула. Например, для сайта компании хорошая идея разместить контактные данные в нижнем колонтитуле на каждой странице. Составьте список элементов, общих для всех страниц</span>. <img alt="the common features of the travel site to go on every page: title and logo, contact, copyright, terms and conditions, language chooser, accessibility policy" src="https://mdn.mozillademos.org/files/12423/common-features.png" style="border-style: solid; border-width: 1px; display: block; height: 375px; margin: 0px auto; width: 600px;"></li> + <li>Теперь набросайте структуру страниц (можно взять за образец наш простой дизайн, приведенный раннее). Что находится в этих блоках?<img alt="A simple diagram of a sample site structure, with a header, main content area, two optional sidebars, and footer" src="https://mdn.mozillademos.org/files/12429/site-structure.png" style="border-style: solid; border-width: 1px; display: block; height: 232px; margin: 0px auto; width: 600px;"></li> + <li>Теперь составьте список остальной (уникальной для каждой страницы) информации, которую вы разместите на сайте.<img alt="A long list of all the features that we could put on our travel site, from searching, to special offers and country-specific info" src="https://mdn.mozillademos.org/files/12425/feature-list.png" style="border-style: solid; border-width: 1px; display: block; height: 1066px; margin: 0px auto; width: 600px;"></li> + <li>Сгруппируйте информацию по темам. Какие части можно разместить на одной странице? Это похоже на метод {{glossary("Card sorting")}}. <img alt="The items that should appear on a holiday site sorted into 5 categories: Search, Specials, Country-specific info, Search results, and Buy things" src="https://mdn.mozillademos.org/files/12421/card-sorting.png" style="border-style: solid; border-width: 1px; display: block; height: 579px; margin: 0px auto; width: 600px;"></li> + <li>Составьте карту сайта. Обведите каждую страницу рамкой, и продумайте перемещения пользователя между ними. Обычно в центре оказывается главная страница, с которой можно быстро перейти на все остальные. На небольшом сайте большинство страниц помещают в главную навигацию, но не обязательно класть туда все ссылки. Также можете пометить, как выглядят элементы страниц — ссылками, списками, карточками.</li> +</ol> + +<p><img alt="A map of the site showing the homepage, country page, search results, specials page, checkout, and buy page" src="https://mdn.mozillademos.org/files/12427/site-map.png" style="border-style: solid; border-width: 1px; display: block; height: 872px; margin: 0px auto; width: 600px;"></p> + +<h3 id="Самостоятельная_работа_создайте_свою_собственную_карту_сайта">Самостоятельная работа: создайте свою собственную карту сайта</h3> + +<p>Приментие наш метод к своему сайту. О чем он будет?</p> + +<div class="note"> +<p><strong>Примечание</strong>: Сохраните свой код, он Вам ещё понадобится.</p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p><span class="tlid-translation translation">Вы стали лучше понимаеть, как структурировать веб-страницу или сайт. В последней статье этого модуля мы узнаем, как отлаживать HTML.</span></p> + +<h2 id="Дополнительные_материалы">Дополнительные материалы</h2> + +<ul> + <li><a href="/en-US/docs/Web/Guide/HTML/Using_HTML_sections_and_outlines">Using HTML sections and outlines</a>: Продвинутый справочник по семантическим элементам и алгоритму выделения разделов (outline algorithm) в HTML5.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B">Начало работы с HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">Что такое заголовок? Метаданные в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/HTML_text_fundamentals">Основы редактирования текста в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B8%D0%BF%D0%B5%D1%80%D1%81%D1%81%D1%8B%D0%BB%D0%BE%D0%BA">Создание гиперссылок</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Advanced_text_formatting">Углубленное форматирование текста</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0_%D0%B8_%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D0%B0">Структура документа и веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Debugging_HTML">Отладка HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Marking_up_a_letter">Разметка письма</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/Structuring_a_page_of_content">Структурируем страницу</a></li> +</ul> diff --git a/files/ru/learn/html/рецепты/index.html b/files/ru/learn/html/рецепты/index.html new file mode 100644 index 0000000000..1a780e676b --- /dev/null +++ b/files/ru/learn/html/рецепты/index.html @@ -0,0 +1,153 @@ +--- +title: Использование HTML для решения общих задач +slug: Learn/HTML/Рецепты +tags: + - CodingScripting + - HTML + - На русском + - Программирование +translation_of: Learn/HTML/Howto +--- +<p class="summary">Следующие ссылки указывают на решения общих повседневных проблем, которые вам нужно решить с помощью HTML.</p> + +<div class="column-container"> +<div class="column-half"> +<h3 id="Основы_структурирования">Основы структурирования</h3> + +<p>Основное применение HTML - это структура документа. Если вы новичок в HTML, вы должны начать с этого.</p> + +<ul> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Anatomy_of_an_HTML_document">Как создать простой HTML документ</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Divide_a_webpage_into_logical_sections">Как разделять веб-страницы на логические блоки</a></li> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#The_basics_headings_and_paragraphs">Как задавать структуру заголовков и параграфов</a></li> +</ul> + +<h3 id="Основы_организации_гипертекста">Основы организации гипертекста</h3> + +<p>HTML специализируется на предоставлении семантической информации для документа, поэтому HTML отвечает на многие вопросы, которые могут у вас возникнуть о том, как лучше донести ваше сообщение в документе.</p> + +<ul> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Lists">Как создать список элементов с помощью HTML</a></li> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Emphasis_and_importance">Как подчеркнуть или выделить содержание</a></li> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Emphasis_and_importance">Как подчеркнуть важность некоторого текста</a></li> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting#Representing_computer_code">Как отображать компьютерный код в HTML</a></li> + <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Images_in_HTML#Annotating_images_with_figures_and_figure_captions">Как комментировать (подписывать) изображения и видео</a></li> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting#Abbreviations">Как помечать аббревиатуры и делать их понятными</a></li> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting#Quotations">Как добавлять цитаты на веб-страницы</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Define_terms_with_HTML">Как определять термины в HTML</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Гиперссылки">Гиперссылки</h3> + +<p>Одной из главных причин по которым навигация в HTML страницах столь проста являются гиперссылки, которые могут которые возможно использоваться различными способами:</p> + +<ul> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Как создавить гиперссылки</a></li> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#Active_learning_creating_a_navigation_menu">Как создать "оглавление" HTML</a></li> +</ul> + +<h3 id="Изображения_и_мультимедиа">Изображения и мультимедиа</h3> + +<ul> + <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Images_in_HTML#How_do_we_put_an_image_on_a_webpage">Как добавить изображения на веб-страницу</a></li> + <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Как добавить видео на веб-страницу</a></li> + <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Как добавить аудио на веб-страницу</a></li> +</ul> + +<h3 id="Сценарии_и_стили">Сценарии и стили</h3> + +<p>HTML определяет лишь структуру документа. Для улучшения внешнего вида документа обычно используется CSS. Чтобы добавить странице интерактивности вы также можете написать сценарий на одном из скриптовых языков (например JavaScript).</p> + +<ul> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/How_CSS_works#How_to_apply_your_CSS_to_your_HTML">Как использовать CSS внутри веб-страницы</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Use_JavaScript_within_a_webpage">Как использовать JavaScript внутри веб-страницы</a></li> +</ul> + +<h3 id="Встраиваемый_контент">Встраиваемый контент</h3> + +<ul> + <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">Как встроить одну веб-страницу внутрь другой</a></li> + <li><a href="/en-US/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies#The_%3Cembed%3E_and_%3Cobject%3E_elements">Как добавлять Flash содержимое на веб-страницы</a></li> +</ul> +</div> +</div> + +<h2 id="Необычные_или_продвинутые_проблемы">Необычные или продвинутые проблемы</h2> + +<p>Помимо основ, HTML очень богат и предлагает расширенные возможности для решения сложных проблем. Эти статьи помогут вам разобраться с менее распространенными случаями использования, с которыми вы можете столкнуться:</p> + +<div class="column-container"> +<div class="column-half"> +<h3 id="Формы">Формы</h3> + +<p>Форма это сложная HTML структура предназначенная для отправки данных с веб-страницы на веб-сервер. Мы призываем вас просмотреть наше полное посвященное руководство. Вот где вы должны начать:</p> + +<ul> + <li><a href="/en-US/docs/Web/Guide/HTML/Forms/My_first_HTML_form">Как создать простую Веб-форму</a></li> + <li><a href="/en-US/docs/Web/Guide/HTML/Forms/How_to_structure_an_HTML_form">Как организовать Веб форму</a></li> +</ul> + +<h3 id="Таблицы">Таблицы</h3> + +<p>Некоторая информация удобнее всего представима в виде таблиц состоящих из строк и столбцов. Это одна из самых сложных структур в HTML, управлять которой не так просто как кажется:</p> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_a_data_spreadsheet">Как создать таблицу данных</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Make_HTML_tables_accessible">Как сделать HTML-таблицы доступными</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Optimize_HTML_table_rendering">Как оптимизировать рендеринг HTML-таблицы</a></li> +</ul> + +<h3 id="Представление_данных">Представление данных</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTMLHowto/Represent_numeric_values_with_HTML">Как отображать числовые данные с помощью HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Use_data_attributes">How to use data attributes</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Associate_human_readable_content_with_arbitrary_computer_data_structures">How to associate human readable content with arbitrary computer data structures</a></li> +</ul> + +<h3 id="Интерактивность">Интерактивность</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_collapsible_content_with_HTML">How to create collapsible content with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_context_menus_to_a_webpage">Как добавить контекстное меню на веб-страницу</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_dialog_boxes_with_HTML">Как создать диалоговое окно с помощью HTML</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Продвинутая_организация_текста">Продвинутая организация текста</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Take_control_of_HTML_line_breaking">Как контролировать HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Mark_text_insertion_and_deletion">Как отмечать изменения (добавление и удаление текста)</a></li> +</ul> + +<h3 id="Продвинутые_изображения_и_мультимедиа_images_multimedia">Продвинутые изображения и мультимедиа images & multimedia</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">How to add responsive image to a webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">How to add vector image to a webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_a_hit_map_on_top_of_an_image">How to add a hit map on top of an image</a></li> +</ul> + +<h3 id="Локализация">Локализация</h3> + +<p>HTML не одноязычен. Он имеет поддержку средств локализации документов.</p> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_multiple_languages_into_a_single_webpage">Как добавить несколько языков в одну веб-страницу</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Handle_Japanese_ruby_characters">How to handle Japanese ruby characters</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Display_time_and_date_with_HTML">Как отображать дату и время с помощью HTML</a></li> +</ul> + +<h3 id="Производительность">Производительность</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Author_fast-loading_HTML_pages">Как ускорить загрузку HTML страниц</a></li> +</ul> +</div> +</div> + +<p><span style="display: none;"> </span><span style="display: none;"> </span><span style="display: none;"> </span><span style="display: none;"> </span> </p> diff --git a/files/ru/learn/index.html b/files/ru/learn/index.html new file mode 100644 index 0000000000..b986457de7 --- /dev/null +++ b/files/ru/learn/index.html @@ -0,0 +1,128 @@ +--- +title: Изучение веб-разработки +slug: Learn +tags: + - CSS + - HTML + - Index + - Landing + - Learn + - NeedsContent + - TopicStub + - Web + - Новичок + - Обучающий раздел + - Обучение +translation_of: Learn +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Добро пожаловать в обучающий раздел MDN. Эта серия статей направлена на то, чтобы предоставить начинающим с нуля в веб-программировании всё необходимое для того, чтобы начать разрабатывать сайты.</p> + +<p>Задача этого раздела не перевести вас из «новичка» в «эксперта», а перевести вас из «новичка» в «уверенного». Это должно дать вам возможность начать строить свой путь, изучая <a href="https://developer.mozilla.org/ru/">остальные материалы MDN</a> и другие средние и продвинутые материалы, предполагающие существенные начальные знания.</p> + +<p>Если вы начинаете с нуля, веб-разработка может оказаться непростой — мы будем держать вас за руку и давать вам достаточно подробностей, чтобы вы чувствовали себя комфортно и как следует изучили темы. Вы можете чувствовать себя как дома, будь вы студентом, изучающим веб-разработку (самостоятельно или на занятиях), преподавателем, ищущим материал для занятий, любителем или тем, кто просто хочет лучше разобраться в том, как работают веб-технологии.</p> + +<h2 id="Что_нового">Что нового</h2> + +<p>Контент в обучающем разделе регулярно пополняется. Мы начали вести <a href="/en-US/docs/Learn/Release_notes">примечания к версии обучающего раздела</a>, чтобы показать, что изменилось.</p> + +<p>Если у вас есть предложения о добавлении тем, которые вы хотели бы увидеть или которых, как вы считаете, не хватает, напишите нам на нашем <a href="https://discourse.mozilla.org/c/mdn/236">форуме Discourse</a>.</p> + +<div class="in-page-callout webdev"> +<h3 id="Хотите_стать_фронтенд-разработчиком">Хотите стать фронтенд-разработчиком?</h3> + +<p>Мы составили курс, который включает всю важную информацию, необходимую для достижения вашей цели.</p> + +<p><a class="cta primary" href="/docs/Learn/Front-end_web_developer">Начать</a></p> +</div> + +<h2 id="С_чего_начать">С чего начать</h2> + +<ul class="card-grid"> + <li><span>Я новичок</span> Если вы совсем новичок в веб-разработке, мы рекомендуем вам начать работу со статьи «<a href="/ru/docs/Learn/Getting_started_with_the_web">Начало работы с вебом</a>», которая представляет собой практическое вступление в веб-разработку.</li> + <li><span>Уже что-то знаю</span> Если у вас уже есть какой-то набор знаний, то следующим шагом будет изучение {{glossary("HTML")}} и {{glossary("CSS")}} во всех подробностях: начните с нашей статьи «<a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a>», а затем загляните в статью «<a href="/ru/docs/Learn/CSS/Introduction_to_CSS">Вступление в CSS</a>».</li> + <li><span>Погружаемся в программирование</span> Если вы уже чувствуете себя комфортно с HTML и CSS или в основном интересуетесь кодингом, то вы захотите погрузиться в {{glossary("JavaScript")}} или разработку на стороне сервера. Загляните в разделы «<a href="/ru/docs/Learn/JavaScript/First_steps">Первые шаги в JavaScript</a>» и «<a href="/ru/docs/Learn/Server-side/First_steps">Первые шаги в программировании веб-сайтов на стороне сервера</a>».</li> + <li><span>Фреймворки и инструменты</span> Освоив основы ванильного HTML, CSS и JavaScript, стоит приступить к изучению <a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools">инструментов веб-разработки на стороне клиента</a>, а затем углубиться в <a href="/ru/docs/Learn/Tools_and_testing/%D0%A4%D1%80%D0%BE%D0%BD%D1%82%D0%B5%D0%BD%D0%B4_JavaScript_%D1%84%D1%80%D0%B5%D0%B9%D0%BC%D0%B2%D0%BE%D1%80%D0%BA%D0%B8">JavaScript-фреймворки для фронтенда</a> и <a href="/ru/docs/Learn/Server-side">программирование веб-сайтов на стороне сервера</a>.</li> +</ul> + +<div class="note"> +<p><strong>Примечание:</strong> в нашем <a href="/ru/docs/Словарь">словаре</a> вы можете найти термины и их определения. Кроме того, если у вас есть конкретный вопрос по веб-разработке, возможно, ответ найдётся в разделе «<a href="/ru/docs/Learn/Common_questions">Распространённые вопросы</a>».</p> +</div> + +<p>{{LearnBox({"title":"Случайное слово из словаря"})}}</p> + +<h2 id="Изучаемые_темы">Изучаемые темы</h2> + +<p>Ниже приводится список всех тем, которые мы рассматриваем в обучающем разделе MDN.</p> + +<dl> + <dt><a href="/ru/docs/Learn/Getting_started_with_the_web">Начало работы с вебом</a></dt> + <dd>Практическое введение в веб-разработку для начинающих.</dd> + <dt><a href="/ru/docs/Learn/HTML">Изучение HTML: руководства и уроки </a></dt> + <dd>HTML — это язык, который мы используем для структурирования различных частей контента и определения их значения или цели. В этой теме подробно рассматривается HTML.</dd> + <dt><a href="/ru/docs/Learn/CSS">CSS: стилизация веб-страниц</a></dt> + <dd>CSS — это язык, который мы можем использовать для стилизации и разметки веб-контента, а также для описания такого поведения, как анимация. В этой теме подробно рассматривается CSS.</dd> + <dt><a href="/ru/docs/Learn/JavaScript">JavaScript: разработка клиентских скриптов для динамических веб-страниц </a></dt> + <dd>JavaScript — это язык сценариев, используемый для добавления динамической функциональности на веб-страницы. В этой теме рассказывается обо всём необходимом для того, чтобы научиться писать на JavaScript и понимать его.</dd> + <dt><a href="/ru/docs/Learn/HTML/Forms">Веб-формы: работа с пользовательскими данными </a></dt> + <dd>Веб-формы — мощный инструмент для взаимодействия с пользователями. Чаще всего они используются для сбора данных от пользователей или для управления пользовательским интерфейсом. В статьях, перечисленных ниже, мы рассмотрим все важные аспекты структурирования, стилизации и взаимодействия с веб-формами.</dd> + <dt><a href="/ru/docs/Learn/Доступность">Доступность: сделаем интернет доступным для всех </a></dt> + <dd>Доступность — это практика предоставления доступа к веб-контенту как можно большему количеству людей, независимо от ограниченных возможностей здоровья, используемого устройства, региона или других отличительных факторов. В этой теме вы найдёте все, что вам нужно знать.</dd> + <dt><a href="/ru/docs/Learn/Performance">Производительность веб-приложений: делаем сайты быстрыми и отзывчивыми </a></dt> + <dd>Веб-производительность — это искусство обеспечения быстрой загрузки веб-приложений и их реагирования на действия пользователя, независимо от скорости соединения пользователя, размера экрана, сети или возможностей устройства.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing">Инструменты и тестирование</a></dt> + <dd>В этой теме рассматриваются инструменты, которые разработчики используют для оптимизации своей работы, например: инструменты для кросс-браузерного тестирования, линтеры, средства форматирования, инструменты преобразования, системы контроля версий, инструменты развертывания и клиентские JavaScript-фреймворки.</dd> + <dt><a href="/ru/docs/Learn/Server-side">Серверное программирование веб-сайтов</a></dt> + <dd>Даже если вы преимущественно интересуетесь фронтенд-разработкой, всё равно полезно знать, как работают серверы и функции, написанные на серверном коде. В этой теме представлены общие сведения о том, как работает серверная часть, и подробные руководства по созданию серверного приложения с использованием двух популярных фреймворков: Django (Python) и Express (Node.js).</dd> +</dl> + +<h2 id="Получение_наших_примеров_кода">Получение наших примеров кода</h2> + +<p>Представленные в обучающем разделе примеры кода <a href="https://github.com/mdn/learning-area/">доступны на GitHub</a>. Если вы хотите скопировать их все на свой компьютер, самый простой способ — <a href="https://github.com/mdn/learning-area/archive/master.zip">загрузить ZIP-архив с последней веткой основного кода</a>.</p> + +<p>Если вы предпочитаете копировать репозиторий более гибким способом, позволяющим автоматические обновления, вы можете использовать следующую, более сложную инструкцию:</p> + +<ol> + <li><a href="https://git-scm.com/downloads">Установите Git</a> на свой компьютер. Это основное программное обеспечение системы контроля версий, разрабатываемое компанией GitHub.</li> + <li>Откройте <a href="https://www.lifewire.com/how-to-open-command-prompt-2618089">командную строку</a> (Windows) или терминал (<a href="https://help.ubuntu.com/community/UsingTheTerminal">Linux</a>, <a href="https://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line">macOS</a>).</li> + <li>Чтобы скопировать репозиторий обучающего раздела в папку с именем learning-area в текущем местоположении, на которое указывает ваша командная строка / терминал, используйте следующую команду: + <pre class="notranslate">git clone https://github.com/mdn/learning-area</pre> + </li> + <li>Теперь вы можете войти в директорию и найти нужные вам файлы (с помощью Finder/проводника либо <a href="https://ru.wikipedia.org/wiki/Cd_(%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0)">команды cd</a>).</li> +</ol> + +<p>Вы можете обновить репозиторий <code>learning-area</code> и добавить любые изменения, внесённые в основную версию на GitHub, выполнив следующие действия:</p> + +<ol> + <li>В командной строке / терминале войдите в директорию <code>learning-area</code> командой <code>cd</code>. Например, если вы в родительском каталоге: + + <pre class="notranslate">cd learning-area</pre> + </li> + <li>Обновите репозиторий, выполнив следующую команду: + <pre class="notranslate">git pull</pre> + </li> +</ol> + +<h2 id="Связаться_с_нами">Связаться с нами</h2> + +<p>Если вы хотите оставаться с нами на связи, то лучший способ — отправить сообщение в наши <a href="/ru/docs/MDN/Community/Conversations#Asynchronous_discussions">списки рассылки</a> или <a href="https://developer.mozilla.org/ru/docs/MDN/Community/Conversations#Chat_in_IRC">IRC-каналы</a>. Мы хотели бы услышать от вас о том, что на нашем сайте что-то отсутствует или неправильно, запросы новых тем по обучению, просьбы помощи с аспектами, которые вы не понимаете, или что-то ещё.</p> + +<p>Если вам интересно создание или улучшение контента, посмотрите, <a href="/ru/Learn/How_to_contribute">как вы можете помочь</a>, и оставайтесь на связи! Мы будем очень рады поговорить с вами, будь вы обучающийся, преподаватель, опытный веб-разработчик или кто-либо другой, заитересованный в улучшении обучения.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<dl> + <dt><a href="https://www.codecademy.com/">Codecademy</a></dt> + <dd>Крутой интерактивный сайт для изучения языков программирования с нуля.</dd> + <dt><a href="https://code.org/">Code.org</a></dt> + <dd>Базовая теория кода и практика, нацеленная в основном на детей или совсем новичков.</dd> + <dt><a href="https://exlskills.com/learn-en/courses">EXLskills</a> </dt> + <dd>бесплатный и открытые курсы для обучения техническим навыкам, с наставничеством и обучением на основе проектов</dd> + <dt><a href="https://teach.mozilla.org/web-literacy/">Карта веб-грамотности</a></dt> + <dd>Структура веб-грамотности начального уровня и навыков 21 века, которая предоставляет доступ к преподавательской деятельности, отсортированной по категориям.</dd> + <dt><a href="https://teach.mozilla.org/activities">Преподавательская деятельность</a></dt> + <dd>Серия материалов для обучения (и изучения), созданная Mozilla Foundation, покрывающая всё от базовой веб-грамотности и приватности JavaScript до взлома Minecraft.</dd> + <dt><a href="https://edabit.com/challenges">Edabit</a></dt> + <dd>Тысячи интерактивных задач JavaScript.</dd> +</dl> diff --git a/files/ru/learn/javascript/asynchronous/async_await/index.html b/files/ru/learn/javascript/asynchronous/async_await/index.html new file mode 100644 index 0000000000..751e08b45e --- /dev/null +++ b/files/ru/learn/javascript/asynchronous/async_await/index.html @@ -0,0 +1,411 @@ +--- +title: Making asynchronous programming easier with async and await +slug: Learn/JavaScript/Asynchronous/Async_await +translation_of: Learn/JavaScript/Asynchronous/Async_await +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Choosing_the_right_approach", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary">В ECMAScript версии 2017 появились <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async functions</a> и ключевое слово <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a></code> (<a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_Next_support_in_Mozilla">ECMAScript Next support in Mozilla</a>). По существу, такие функции есть синтаксический сахар над Promises и Generator functions (<a href="https://tc39.es/ecmascript-asyncawait/">ts39</a>). С их помощью легче писать/читать асинхронный код, ведь они позволяют использовать привычный синхронный стиль написания. В этой статье мы на базовом уровне разберемся в их устройстве.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Примечания:</th> + <td>Чтобы лучше понять материал, желательно перед чтением ознакомиться с основами JavaScript, асинхронными операциями вообще и объектами Promises.</td> + </tr> + <tr> + <th scope="row">Цель материала:</th> + <td>Научить писать современный асинхронный код с использованием Promises и async functions.</td> + </tr> + </tbody> +</table> + +<h2 id="Основы_asyncawait">Основы async/await</h2> + +<h3 id="Ключевое_слово_async">Ключевое слово async</h3> + +<p>Ключевое слово async позволяет сделать из обычной функции (function declaration или function expression) асинхронную функцию (<a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async function</a>). Такая функция делает две вещи:<br> + - Оборачивает возвращаемое значение в Promise<br> + - Позволяет использовать ключевое слово await (см. дальше)</p> + +<p>Попробуйте выполнить в консоли браузера следующий код:</p> + +<pre class="brush: js notranslate">function hello() { return "Hello" }; +hello();</pre> + +<p>Функция возвращает "Hello" — ничего необычного, верно ?</p> + +<p>Но что если мы сделаем ее асинхронной ? Проверим:</p> + +<pre class="brush: js notranslate">async function hello() { return "Hello" }; +hello();</pre> + +<p>Как было сказано ранее, вызов асинхронной функции возвращает объект Promise.</p> + +<p>Вот пример с <a href="/en-US/docs/Web/JavaScript/Reference/Operators/async_function">async function expression</a>:</p> + +<pre class="brush: js notranslate">let hello = async function() { return "Hello" }; +hello();</pre> + +<p>Также можно использовать стрелочные функции:</p> + +<pre class="brush: js notranslate">let hello = async () => { return "Hello" };</pre> + +<p>Все они в общем случае делают одно и то же.</p> + +<p>Чтобы получить значение, которое возвращает Promise, мы как обычно можем использовать метод <code>.then()</code>:</p> + +<pre class="brush: js notranslate">hello().then((value) => console.log(value))</pre> + +<p>или еще короче</p> + +<pre class="brush: js notranslate">hello().then(console.log) +</pre> + +<p>Итак, ключевое слово <code>async</code>, превращает обычную функцию в асинхронную и результат вызова функции оборачивает в Promise. Также асинхронная функция позволяет использовать в своем теле ключевое слово await, о котором далее.</p> + +<h3 id="Ключевое_слово_await">Ключевое слово await</h3> + +<p>Асинхронные функции становятся по настоящему мощными, когда вы используете ключевое слово <a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a> — по факту, <strong><code>await</code> работает только в асинхронных функциях</strong>. Мы можем использовать await перед promise-based функцией, чтобы остановить поток выполнения и дождаться результата ее выполнения (результат Promise). В то же время, остальной код нашего приложения не блокируется и продолжает работать.</p> + +<p>Вы можете использовать <code>await</code> перед любой функцией, что возвращает Promise, включая Browser API функции.</p> + +<p>Небольшой пример:</p> + +<pre class="brush: js notranslate">async function hello() { + return greeting = await Promise.resolve("Hello"); +}; + +hello().then(alert);</pre> + +<p>Конечно, на практике код выше бесполезен, но в учебных целях он иллюстрирует синтаксис асинхронных функций. Теперь давайте перейдем к реальным примерам.</p> + +<h2 id="Переписываем_Promises_с_ипользованием_asyncawait">Переписываем Promises с ипользованием async/await</h2> + +<p>Давайте посмотрим на пример из предыдущей статьи:</p> + +<pre class="brush: js notranslate">fetch('coffee.jpg') +.then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } else { + return response.blob(); + } +}) +.then(myBlob => { + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}) +.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>К этому моменту вы должны понимать как работают Promises, чтобы понять все остальное. Давайте перепишем код используя async/await и оценим разницу.</p> + +<pre class="brush: js notranslate">async function myFetch() { + let response = await fetch('coffee.jpg'); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } else { + let myBlob = await response.blob(); + + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); + } +} + +myFetch() +.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>Согласитесь, что код стал короче и понятнее — больше никаких блоков <code>.then()</code> по всему скрипту!</p> + +<p>Так как ключевое слово <code>async</code> заставляет функцию вернуть Promise, мы можем использовать гибридный подход:</p> + +<pre class="brush: js notranslate">async function myFetch() { + let response = await fetch('coffee.jpg'); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } else { + return await response.blob(); + } +} + +myFetch().then((blob) => { + let objectURL = URL.createObjectURL(blob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}).catch(e => console.log(e));</pre> + +<p>Можете попрактиковаться самостоятельно, или запустить наш <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await.html">live example</a> (а также <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await.html">source code</a>).</p> + +<h3 id="Минуточку_а_как_это_все_работает">Минуточку, а как это все работает ?</h3> + +<p>Вы могли заметить, что мы обернули наш код в функцию и сделали ее асинхронной с помощью acync. Это было обязательно - нам надо создать контейнер, внутри которого будет запускаться асинхронный код и будет возмоность дождаться его результата с помощью await, не блокируя остальной код нашег скрипта.</p> + +<p>Внутри <code>myFetch()</code> находится код, который слегка напоминает версию на Promise, но есть важные отличия. Вместо того, чтобы писать цепочку блоков <code>.then()</code> мы просто использует ключевое слово <code>await</code> перед вызовом promise-based функции и присваиваем результат в переменную. Ключеовое слово <code>await</code> говорит JavaScript runtime приостановить код в этой строке, не блокируя остальной код скприта за пределами асинхронной функции. Когда вызов promise-based функции будет готов вернуть результат, выполнение продолжится с этой строки дальше.<br> + <br> + Пример:</p> + +<pre class="brush: js notranslate">let response = await fetch('coffee.jpg');</pre> + +<p>Значение Promise, которое вернет <code>fetch()</code> будет присвоено переменной <code>response</code> только тогда, когда оно будет доступно - парсер делает паузу на данной строке дожидаясь этого момента. Как только значение доступно, парсер переходит к следующей строке, в которой создается объект <code><a href="/en-US/docs/Web/API/Blob">Blob</a></code> из результата Promise. В этой строке, кстати, также используется <code>await</code>, потому что метод <code>.blob()</code> также возвращет Promise. Когда результат готов, мы возвращаем его наружу из <code>myFetch()</code>.</p> + +<p>Обратите внимание, когда мы вызываем <code>myFetch()</code>, она возвращает Promise, поэтому мы можем вызвать <code>.then()</code> на результате, чтобы отобразить его на экране.<br> + <br> + К этому моменту вы наверное думаете "Это реально круто!", и вы правы - чем меньше блоков <code>.then()</code>, тем легче читать код.</p> + +<h3 id="Добавляем_обработку_ошибок">Добавляем обработку ошибок</h3> + +<p><br> + Чтобы обработать ошибки у нас есть несколько вариантов</p> + +<p>Мы можем использовать синхронную <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> структуру с <code>async</code>/<code>await</code>. Вот измененная версия первого примера выше:</p> + +<pre class="brush: js notranslate">async function myFetch() { + try { + let response = await fetch('coffee.jpg'); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } else { + let myBlob = await response.blob(); + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); + } + } catch(e) { + console.log(e); + } +} + +myFetch();</pre> + +<p>В блок <code>catch() {}</code> передается объект ошибки, который мы назвали <code>e</code>; мы можем вывести его в консоль, чтобы посмотреть детали: где и почему возникла ошибка.</p> + +<p>Если вы хотите использовать гибридный подходы (пример выше), лучше использовать блок <code>.catch()</code> после блока <code>.then()</code> вот так:</p> + +<pre class="brush: js notranslate">async function myFetch() { + let response = await fetch('coffee.jpg'); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } else { + return await response.blob(); + } +} + +myFetch().then((blob) => { + let objectURL = URL.createObjectURL(blob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}) +.catch((e) => + console.log(e) +);</pre> + +<p>Так лучше, потому что блок <code>.catch()</code> словит ошибки как из асинхронной функции, так и из Promise. Если бы мы использовали блок <code>try</code>/<code>catch</code>, мы бы не словили ошибку, которая произошла в самой <code>myFetch()</code> функции.</p> + +<p>Вы можете посмотреть оба примера на GitHub:</p> + +<ul> + <li><a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await-try-catch.html">simple-fetch-async-await-try-catch.html</a> (смотреть <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await-try-catch.html">source code</a>)</li> + <li><a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await-promise-catch.html">simple-fetch-async-await-promise-catch.html</a> (смотреть <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await-promise-catch.html">source code</a>)</li> +</ul> + +<h2 id="Await_и_Promise.all">Await и Promise.all()</h2> + +<p>Как вы помните, асинхронные функции построены поверх <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promises</a>, поэтому они совместимы со всеми возможностями последних. Мы легко можем подождать выполнение <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code>, присвоить результат в переменную и все это сделать используя синхронный стиль. Опять, вернемся к <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-all.html">an example we saw in our previous article</a>. Откройте пример в соседней вкладке, чтобы лучше понять разницу.</p> + +<p>Версия с async/await (смотрите <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/promise-all-async-await.html">live demo</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/promise-all-async-await.html">source code</a>), сейчас выглядит так:</p> + +<pre class="brush: js notranslate">async function fetchAndDecode(url, type) { + let response = await fetch(url); + + let content; + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } else { + if(type === 'blob') { + content = await response.blob(); + } else if(type === 'text') { + content = await response.text(); + } + + return content; + } + +} + +async function displayContent() { + let coffee = fetchAndDecode('coffee.jpg', 'blob'); + let tea = fetchAndDecode('tea.jpg', 'blob'); + let description = fetchAndDecode('description.txt', 'text'); + + let values = await Promise.all([coffee, tea, description]); + + let objectURL1 = URL.createObjectURL(values[0]); + let objectURL2 = URL.createObjectURL(values[1]); + let descText = values[2]; + + let image1 = document.createElement('img'); + let image2 = document.createElement('img'); + image1.src = objectURL1; + image2.src = objectURL2; + document.body.appendChild(image1); + document.body.appendChild(image2); + + let para = document.createElement('p'); + para.textContent = descText; + document.body.appendChild(para); +} + +displayContent() +.catch((e) => + console.log(e) +);</pre> + +<p>Вы видите, что мы легко изменили <code>fetchAndDecode()</code> функцию в асинхронный вариант. Взгляните на строку с <code>Promise.all()</code>:</p> + +<pre class="brush: js notranslate">let values = await Promise.all([coffee, tea, description]);</pre> + +<p>С помощью <code>await</code> мы ждем массив результатов всех трех Promises и присваиваем его в переменную <code>values</code>. Это асинхронный код, но он написан в синхронном стиле, за счет чего он гораздо читабельнее.<br> + <br> + Мы должны обернуть весь код в синхронную функцию, <code>displayContent()</code>, и мы не сильно сэкономили на количестве кода, но мы извлекли код блока <code>.then()</code>, за счет чего наш код стал гораздо чище.</p> + +<p>Для обработки ошибок мы добавили блок <code>.catch()</code> для функции <code>displayContent()</code>; Это позволило нам отловить ошибки в обоих функциях.</p> + +<div class="blockIndicator note"> +<p><strong>Заметка</strong>: Мы также можем использовать синхронный блок <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#The_finally_clause">finally</a></code> внутри асинхронной функции, вместо асинхронного <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#The_finally_clause">.finally</a>()</code>, чтобы получить информацию о результате нашей операции — смотрите в действии в нашем <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/promise-finally-async-await.html">live example</a> (смотрите <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/promise-finally-async-await.html">source code</a>).</p> +</div> + +<h2 id="Недостатки_asyncawait">Недостатки async/await</h2> + +<p>Асинхронные функции с async/await бывают очень удобными, но есть несколько замечаний, о которых полезно знать.</p> + +<p>Async/await позволяет вам писать код в синхронном стиле. Ключевое слово <code>await</code> блокирует приостанавливает выполнение ptomise-based функции до того момента, пока promise примет статуc fulfilled. Это не блокирует код за пределами вашей асинхронной функции, тем не менее важно помнить, что внутри асинхронной функции поток выполнения блокируется.<br> + <br> + Ваш код может стать медленнее за счет большого количества awaited promises, которые идут один за другим. Каждый <code>await</code> должен дождаться выполнения предыдущего, тогда как на самом деле мы хотим, чтобы наши Promises выполнялись одновременно, как если бы мы не использовали async/await.<br> + <br> + Есть подход, который позволяет обойти эту проблему - сохранить все выполняющиеся Promises в переменные, а уже после этого дожидаться (awaiting) их результата. Давайте посмотрим на несколько примеров.</p> + +<p>We've got two examples available — <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/slow-async-await.html">slow-async-await.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/slow-async-await.html">source code</a>) and <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/fast-async-await.html">fast-async-await.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/fast-async-await.html">source code</a>). Both of them start off with a custom promise function that fakes an async process with a <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> call:</p> + +<pre class="brush: js notranslate">function timeoutPromise(interval) { + return new Promise((resolve, reject) => { + setTimeout(function(){ + resolve("done"); + }, interval); + }); +};</pre> + +<p>Then each one includes a <code>timeTest()</code> async function that awaits three <code>timeoutPromise()</code> calls:</p> + +<pre class="brush: js notranslate">async function timeTest() { + ... +}</pre> + +<p>Each one ends by recording a start time, seeing how long the <code>timeTest()</code> promise takes to fulfill, then recording an end time and reporting how long the operation took in total:</p> + +<pre class="brush: js notranslate">let startTime = Date.now(); +timeTest().then(() => { + let finishTime = Date.now(); + let timeTaken = finishTime - startTime; + alert("Time taken in milliseconds: " + timeTaken); +})</pre> + +<p>It is the <code>timeTest()</code> function that differs in each case.</p> + +<p>In the <code>slow-async-await.html</code> example, <code>timeTest()</code> looks like this:</p> + +<pre class="brush: js notranslate">async function timeTest() { + await timeoutPromise(3000); + await timeoutPromise(3000); + await timeoutPromise(3000); +}</pre> + +<p>Here we simply await all three <code>timeoutPromise()</code> calls directly, making each one alert for 3 seconds. Each subsequent one is forced to wait until the last one finished — if you run the first example, you'll see the alert box reporting a total run time of around 9 seconds.</p> + +<p>In the <code>fast-async-await.html</code> example, <code>timeTest()</code> looks like this:</p> + +<pre class="brush: js notranslate">async function timeTest() { + const timeoutPromise1 = timeoutPromise(3000); + const timeoutPromise2 = timeoutPromise(3000); + const timeoutPromise3 = timeoutPromise(3000); + + await timeoutPromise1; + await timeoutPromise2; + await timeoutPromise3; +}</pre> + +<p>Here we store the three <code>Promise</code> objects in variables, which has the effect of setting off their associated processes all running simultaneously.</p> + +<p>Next, we await their results — because the promises all started processing at essentially the same time, the promises will all fulfill at the same time; when you run the second example, you'll see the alert box reporting a total run time of just over 3 seconds!</p> + +<p>You'll have to test your code carefully, and bear this in mind if performance starts to suffer.</p> + +<p>Another minor inconvenience is that you have to wrap your awaited promises inside an async function.</p> + +<h2 id="Asyncawait_class_methods">Async/await class methods</h2> + +<p>As a final note before we move on, you can even add <code>async</code> in front of class/object methods to make them return promises, and <code>await</code> promises inside them. Take a look at the <a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance#ECMAScript_2015_Classes">ES class code we saw in our object-oriented JavaScript article</a>, and then look at our modified version with an <code>async</code> method:</p> + +<pre class="brush: js notranslate">class Person { + constructor(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + } + + async greeting() { + return await Promise.resolve(`Hi! I'm ${this.name.first}`); + }; + + farewell() { + console.log(`${this.name.first} has left the building. Bye for now!`); + }; +} + +let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']);</pre> + +<p>The first class method could now be used something like this:</p> + +<pre class="brush: js notranslate">han.greeting().then(console.log);</pre> + +<h2 id="Browser_support">Browser support</h2> + +<p>One consideration when deciding whether to use async/await is support for older browsers. They are available in modern versions of most browsers, the same as promises; the main support problems come with Internet Explorer and Opera Mini.</p> + +<p>If you want to use async/await but are concerned about older browser support, you could consider using the <a href="https://babeljs.io/">BabelJS</a> library — this allows you to write your applications using the latest JavaScript and let Babel figure out what changes if any are needed for your user’s browsers. On encountering a browser that does not support async/await, Babel's polyfill can automatically provide fallbacks that work in older browsers.</p> + +<h2 id="Conclusion">Conclusion</h2> + +<p>And there you have it — async/await provide a nice, simplified way to write async code that is simpler to read and maintain. Even with browser support being more limited than other async code mechanisms at the time of writing, it is well worth learning and considering for use, both for now and in the future.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Choosing_the_right_approach", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ru/learn/javascript/asynchronous/concepts/index.html b/files/ru/learn/javascript/asynchronous/concepts/index.html new file mode 100644 index 0000000000..b82d4d4a51 --- /dev/null +++ b/files/ru/learn/javascript/asynchronous/concepts/index.html @@ -0,0 +1,164 @@ +--- +title: Основные понятия асинхронного программирования +slug: Learn/JavaScript/Asynchronous/Concepts +tags: + - JavaScript + - Promises + - Асинхронность + - Обучение + - блокировки + - потоки +translation_of: Learn/JavaScript/Asynchronous/Concepts +--- +<div>{{LearnSidebar}}{{NextMenu("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous")}}</div> + +<p>В этой статье мы бегло познакомимся с основными понятиями, связанными с асинхронным программированием и как они применяются в веб браузерах и JavaScript. Вы должны понять эти концепции, прежде чем приступать к другим статьям этого раздела.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, знакомство с основами JavaScript.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td><span class="tlid-translation translation" lang="ru"><span title="">Понять основные идеи асинхронного программирования, и как они проявляются в веб-браузерах и JavaScript.</span></span></td> + </tr> + </tbody> +</table> + +<h2 id="Что_же_такое_Асинхронность">Что же такое Асинхронность?</h2> + +<p>Как правило, программный код выполняется последовательно, только одна конкретная операция происходит в данный момент времени. Если функция зависит от результата выполнения другой функции, то она должна дождаться пока нужная ей функция не завершит свою работу и не вернет результат и до тех пор пока это не произойдет, выполнение программы, по сути, будет остановлено с точки зрения пользователя.</p> + +<p>Пользователь современного ПК, наверняка, наблюдал, как курсор меняет свой вид и становится "разноцветным спинером" (у пользователей MacOS). Таким образом операционная система сообщает - "текущая программа, ожидает завершения какого то длительного процесса в системе и я решила сообщить тебе, что бы ты не волновался".</p> + +<p><img alt="Multi-colored macOS beachball busy spinner" src="https://mdn.mozillademos.org/files/16577/beachball.jpg" style="display: block; float: left; height: 256px; margin: 0px 30px 0px 0px; width: 250px;"></p> + +<p>Такое поведение удручает и говорит о неправильном использовании процессорного времени, к тому же современные компьютеры имеют процессоры с несколькими ядрами. Не нужно ничего ждать, вы можете передать следующую задачу свободному ядру процессора и когда она завершится, то сообщит вам об этом. Такой подход позволяет выполнять разные задачи одновременно, в этом и заключается задача асинхронности в программировании. Программная среда, которую вы используете (браузер в случае веб разработки), должна иметь возможность выполнять различного рода задачи ассинхронно.</p> + +<h2 id="Блокировка_кода">Блокировка кода</h2> + +<p>Асинхронные техники очень полезны, особенно при веб разработке. Когда ваше приложение запущено в браузере и выполняет свои задачи, не возвращая контроль окружению, браузер может подвисать. Это называется <strong>блокировка</strong>; браузер заблокирован и не может реагировать на действия пользователя и выполнять служебные.задачи, до тех пор пока веб приложение не освободит ресурсы процессора.</p> + +<p>Давайте рассмотрим несколько примеров, которые покажут, что именно значит <strong>блокировка</strong>.</p> + +<p>В нашем <a href="https://github.com/mdn/learning-area/tree/master/javascript/asynchronous/introducing">simple-sync.html</a> примере (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync.html">see it running live</a>), добавим кнопке событие на клик, чтобы при нажатии на нее запускалась трудоемкая операция (рассчет 10000000 дат, и вывод последнейрассчитаной даты на консоль) после чего в DOM добавляется еще один параграф:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); +btn.addEventListener('click', () => { + let myDate; + for(let i = 0; i < 10000000; i++) { + let date = new Date(); + myDate = date + } + + console.log(myDate); + + let pElem = document.createElement('p'); + pElem.textContent = 'This is a newly-added paragraph.'; + document.body.appendChild(pElem); +});</pre> + +<p>Когда запустите этот пример, откройте JavaScript консоль и нажмите на кнопку — вы заметите, что параграф не появится на странице, до тех пор пока все даты не будут рассчитаны и результат последнего вычисления не будет выведен на консоль. Этот код выполняется в том порядке, в котором он написан в файле и самая последняя операция не будет запущена, пока не завершатся все операции перед ней.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Предыдущий пример слишком не реальный. Вам никогда не понадобится считать столько дат в реальном приложении! Однако, он помогает вам понять основную идею.</p> +</div> + +<p>В нашем следующем примере, <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/simple-sync-ui-blocking.html">simple-sync-ui-blocking.html</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync-ui-blocking.html">посмотреть пример</a>), мы сделаем что-нибудь более реалистичное, с чем вы сможете столкнуться на реальной странице. Мы заблокируем действия пользователя отрисовкой страницы. В этом примере у нас две кнопки:</p> + +<ul> + <li>Кнопка "Fill canvas", если на нее кликнуть, рисует в элементе + <div>{{htmlelement("canvas")}}</div> + миллион синих кругов.</li> + <li>Кнопка "Click me for alert", при нажатии показывает предупреждение.</li> +</ul> + +<pre class="brush: js notranslate">function expensiveOperation() { + for(let i = 0; i < 1000000; i++) { + ctx.fillStyle = 'rgba(0,0,255, 0.2)'; + ctx.beginPath(); + ctx.arc(random(0, canvas.width), random(0, canvas.height), 10, degToRad(0), degToRad(360), false); + ctx.fill() + } +} + +fillBtn.addEventListener('click', expensiveOperation); + +alertBtn.addEventListener('click', () => + alert('You clicked me!') +);</pre> + +<p>Если вы быстро нажмете на первую кнопку и затем быстро кликните на вторую, вы увидите, что предупреждение не появится на странице, пока все круги не будут отрисованы. Первая операция блокирует выполнение следующей до тех пор пока не завершится сама.</p> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: Хорошо, в приведенном некрасивом примере, мы получили эффект блокировки, который показывает общую проблему при разработке приложений, с которой все время приходится бороться разработчикам.</p> +</div> + +<p>Почему так происходит? Потому что JavaScript, в общем случае, выполняет команды в <strong>одном потоке</strong>. Пришло время познакомиться с понятием <strong>потока</strong>.</p> + +<h2 id="Потоки">Потоки</h2> + +<p>Под <strong>потоком,</strong> обычно, понимают одиночный процесс, который может использовать программа, для выполнения своих нужд. Каждый поток может выполнять только одну в текущий момент времени:</p> + +<pre class="notranslate">Task A --> Task B --> Task C</pre> + +<p>Каждая задача будет выполнена последовательно; только когда текущая задача завершится, следующая сможет начаться.</p> + +<p>Как мы говорили выше, большинство компьютеров теперь имеют процессор с несколькими ядрами, т.е. могут выполнять несколько задач одновременно. Языки программирования, поддерживающие многопоточность, могут использовать несколько ядер, чтобы выпонять несколько задач одновременно:</p> + +<pre class="notranslate">Thread 1: Task A --> Task B +Thread 2: Task C --> Task D</pre> + +<h3 id="JavaScript_однопоточный">JavaScript однопоточный</h3> + +<p>JavaScript, традиционно для скриптовых языков, однопоточный. Даже, если есть несколько ядер, вы можете использовать их только для выполнения задач в одном потоке, называемом <strong>основной поток</strong>. Наш пример выше, выполняется следующим образом:</p> + +<pre class="notranslate">Main thread: Render circles to canvas --> Display alert()</pre> + +<p>В итоге, JavaScript получил несколько инструментов, которые могут помочь в решении подобных проблем. <a href="/en-US/docs/Web/API/Web_Workers_API">Web workers</a> позволяют вам обработать некоторый JavaScript код в отдельном потоке, который называется обработчик, таким образом вы можете запускать отдельные блоки JavaScript кода одновременно. В основном, вы будете использовать воркеры, чтобы запустить ресурсоемкий процесс, отдельно от основного потока, чтобы не блокировать действия пользователя.</p> + +<pre class="notranslate"> Main thread: Task A --> Task C +Worker thread: Expensive task B</pre> + +<p>Помня об этом, выполните наш следующий пример <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/simple-sync-worker.html">simple-sync-worker.html</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync-worker.html">посмотреть пример в действии</a>), с открытой консолью. Это переписанный предыдущий пример, который теперь рассчитывает 10 миллионов дат в отдельном потоке обработчика. Теперь, когда вы нажимаете на кнопку, браузер может добавить новый элемент на страницу, до того как все даты будут посчитаны. Самая первая операция больше не блокирует выполнение следующей.</p> + +<h2 id="Асинхронный_код">Асинхронный код</h2> + +<p>Воркеры полезный инструмент, но у них есть свои ограничения. Самое существенное, заключается в том, что они не имеют доступа к {{Glossary("DOM")}} — вы не можете использовать воркер для обновления UI. Мы не можем отрисовать миллион наших точек внутри воркера; он может только обработать большой объем информации.</p> + +<p>Следующая проблема заключается в том, что даже если код запущенный в воркере ничего не блокирует, он в целом остается синхронным. Это проблема появляется, когда какой-то функции требуются результаты выполнения нескольких предыдущих функций. Рассмотрим следующую диаграмму потоков:</p> + +<pre class="notranslate">Main thread: Task A --> Task B</pre> + +<p>В этом примере, предположим Task A делает что-то вроде получения картинки с сервера а Task B затем делает что-нибудь с полученной картинкой, например, применяет к ней фильтр. Если запустить выполняться Task A и тут же попытаться выполнить Task B, то вы получите ошибку, поскольку картинка еще не будет доступна.</p> + +<pre class="notranslate"> Main thread: Task A --> Task B --> |Task D| +Worker thread: Task C -----------> | |</pre> + +<p>Теперь, давайте предположим, что Task D использует результат выполнения обеих задач Task B и Task C. Если мы уверенны, что оба результата будут доступны одновременно, тогда не возникнет проблем, однако, часто это не так. Если Task D попытаться запустить, когда какого-то нужного ей результата еще нет, выполнение закончится ошибкой.</p> + +<p>Чтобы избежать подобных проблем, браузеры позволяют нам выполнять определенные операции асинхронно. Такие возможности, как <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> позволяют запустить некоторую операцию (например, получение картинки с сервера), и затем подождать пока операция не вернет результат, перед тем как начать выполнение другой задачи:</p> + +<pre class="notranslate">Main thread: Task A Task B + Promise: |__async operation__|</pre> + +<p>Поскольку операция выполняется где-то отдельно, основной поток не блокируется, при выполнении асинхронных задач.</p> + +<p>В следующей статье, мы покажем вам, как писать асинхронный код. Захватывает дух, неправда ли? Продолжайте читать!</p> + +<h2 id="Заключение">Заключение</h2> + +<p>При проектировании современных программ все больше используется асинхронное программирование, чтобы программа имела возможность выполнять несколько операций в конкретный момент времени. Как только вы начнете использовать новые, более мощные возможности API, вы обнаружите множество ситуаций, где решить нужную задачу можно только асинхронно. Раньше было сложно писать асинхронный код. До сих пор, нужно время, чтобы привыкнуть к такому подходу, но процесс стал намного легче. Далее, в этом разделе, мы будем глубже исследовать вопрос, когда же асинхронный код необходим и как спроектировать программу, чтобы избежать проблем, описанных выше.</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ru/learn/javascript/asynchronous/index.html b/files/ru/learn/javascript/asynchronous/index.html new file mode 100644 index 0000000000..19d66b114c --- /dev/null +++ b/files/ru/learn/javascript/asynchronous/index.html @@ -0,0 +1,59 @@ +--- +title: Асинхронный JavaScript +slug: Learn/JavaScript/Asynchronous +tags: + - Beginner + - CodingScripting + - Guide + - JavaScript + - Landing + - Promises + - async + - asynchronous + - await + - callbacks + - requestAnimationFrame + - setInterval + - setTimeout + - Асинхронность + - асинхронное программирование +translation_of: Learn/JavaScript/Asynchronous +--- +<div>{{LearnSidebar}}</div> + +<p class="summary"><span class="seoSummary">В этом модуле мы рассмотрим {{Glossary("asynchronous")}} {{Glossary("JavaScript")}}, почему это важно, и как это поможет эффективно справляться с потенциальной блокировкой операций, таких как получение ресурсов с сервера или запись в файл.</span></p> + +<h2 id="Необходимые_знания">Необходимые знания</h2> + +<p>Асинхронный JavaScript довольно сложная тема, и мы советуем пройти <a href="/ru/docs/Learn/JavaScript/First_steps">Первые шаги в JavaScript</a> и <a href="/ru/docs/Learn/JavaScript/Building_blocks">Блоки в JavaScript</a> прежде чем начать эту тему.</p> + +<p>Если вы ещё не знакомы с концепциями асинхронного программирования, вам стоит начать со статьи <a href="/ru/docs/Learn/JavaScript/Asynchronous/Concepts">Основные концепции асинхронного программирования</a> в этом модуле. А если уже знакомы, то можете сразу переходить к статье <a href="/ru/docs/Learn/JavaScript/Asynchronous/Introducing">Введение в асинхронный JavaScript</a>.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Если вы работаете за компьютером/планшетом/другим устройством где у вас нет возможности создавать собственные файлы, вы можете попробовать(почти все) примеры кода в одном из веб-приложений, таких, как <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<dl> + <dt><a href="/ru/docs/Learn/JavaScript/Asynchronous/Concepts">Основные концепции асинхронного программирования</a></dt> + <dd> + <p>В этой статье мы пройдёмся по нескольким важным концепциям касающихся асинхронного программирования, и того как это выглядит в браузерах и JavaScript. Вы должны усвоить эти концепции прежде чем изучать другие статьи в этом модуле.</p> + </dd> + <dt><a href="/ru/docs/Learn/JavaScript/Asynchronous/Introducing">Введение в асинхронный JavaScript</a></dt> + <dd>В этой статье мы кратко расскажем о проблемах связанных с синхронным JavaScript-ом, и взглянем на различные техники асинхронного программирования с которыми вы столкнётесь, покажем вам как эти техники помогают решать проблемы синхронного JavaScript.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Asynchronous/Loops_and_intervals">Кооперативная асинхронность в JavaScript: Таймауты и интервалы</a></dt> + <dd>Здесь мы рассматриваем традиционные методы JavaScript, которые позволяют запускать код асинхронно по истечению заданного времени, или с регулярным интервалом (например: заданное количество раз в секунду), обсудим их пользу, а так же их неотъемлемые проблемы.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Asynchronous/Promises">Изящная обработка асинхронных операций с Промисами</a></dt> + <dd>Промисы это достаточно новая функция в языке JavaScript, которая позволяет вам откладывать дальнейшие операции, пока предыдущая не выполнится, или реагировать на её неудачное выполнение. Это очень полезно, для установки нужной последовательности операций для корректной работы. Эта статья показывает как работают промисы, и вы рассмотрите то, как они работают в WebAPIs, и узнаете как писать свои собственные.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Asynchronous/Async_await">Делаем асинхронное программирование проще с async и await</a></dt> + <dd>Промисы могут быть достаточно сложными для написания и понимания, поэтому современные браузеры ввели функцию <code>async</code> и оператор <code>await</code> — где первый позволяет стандартным функциям неявно асинхронно работать с промисами, а последний может использоваться внутри <code>async</code> функций, для ожидания промиса, прежде чем функция продолжит свою работу, что делает работу с промисами проще и улучшает читабельность кода.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Выбор правильного подхода</a></dt> + <dd>В завершение этого модуля, мы рассмотрим технологии и функции, которые мы обсуждали, рассмотрим когда и где их надо использовать. А так же дадим рекомендации и расскажем о распространённых подводных камнях, там где это будет необходимо.</dd> +</dl> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://eloquentjavascript.net/11_async.html">Асинхронное программирование</a> из фантастической онлайн книги Марина Хавербеке, <a href="https://karmazzin.gitbooks.io/eloquentjavascript_ru/">Выразительный JavaScript</a>.</li> +</ul> diff --git a/files/ru/learn/javascript/asynchronous/introducing/index.html b/files/ru/learn/javascript/asynchronous/introducing/index.html new file mode 100644 index 0000000000..b25ca4037e --- /dev/null +++ b/files/ru/learn/javascript/asynchronous/introducing/index.html @@ -0,0 +1,288 @@ +--- +title: Введение в асинхронный JavaScript +slug: Learn/JavaScript/Asynchronous/Introducing +tags: + - Асинхронность + - Введение + - Гайд + - Начинающий + - Промисы + - Статья + - колбэк + - чейнить +translation_of: Learn/JavaScript/Asynchronous/Introducing +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary">В этой статье мы кратко остановимся на проблемах, связанных с синхронным Javascript, а также ознакомимся с несколькими асинхронными методами, демонстрирующими как они могут помочь нам подобные проблемы решить.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимое условие:</th> + <td>Базовая компьютерная грамотность, достаточное понимание основ JavaScript.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Ознакомиться с тем, что такое асинхронный JavaScript, чем он отличается от синхронного и в каких случаях используется.</td> + </tr> + </tbody> +</table> + +<h2 id="Синхронный_JavaScript">Синхронный JavaScript</h2> + +<p>Чтобы (позволить нам) понять что есть <strong>{{Glossary("асинхронный")}}</strong> JavaScript, нам следовало бы для начала убедиться, что мы понимаем что такое <strong>{{Glossary("синхронный")}}</strong> JavaScript. Этот раздел резюмирует некоторую информацию из прошлой статьи.</p> + +<p>Большая часть функционала, которую мы рассматривали в предыдущих обучающих модулях, является синхронной — вы запускаете какой-то код, а результат возвращается, как только браузер может его вернуть. Давайте рассмотрим простой пример ( посмотрите <a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/basic-function.html">онлайн</a>, как это работает и посмотрите <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/basic-function.html">исходный код</a>):</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); +btn.addEventListener('click', () => { + alert('You clicked me!'); + + let pElem = document.createElement('p'); + pElem.textContent = 'This is a newly-added paragraph.'; + document.body.appendChild(pElem); +}); +</pre> + +<p>В этом блоке кода команды выполняются одна за другой:</p> + +<ol> + <li>Получаем ссылку на элемент {{htmlelement("button")}}, который уже есть в DOM.</li> + <li>Добавляем к кнопке обработчик события <code><a href="/en-US/docs/Web/API/Element/click_event">click</a></code> так, что при нажатии на неё: + <ol> + <li>Выводится сообщение <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code>.</li> + <li>После закрытия сообщения создаём элемент {{htmlelement("p")}} (абзац).</li> + <li>Затем добавляем в абзац текст.</li> + <li>В конце добавляем созданный абзац в тело документа.</li> + </ol> + </li> +</ol> + +<p>Пока выполняется каждая операция, ничего больше не может произойти — обработка (отображение) документа приостановлена. Так происходит, как было сказано <a href="/ru/docs/Learn/JavaScript/Asynchronous/Introducing">в предыдущей статье</a>, потому что <a href="/ru/docs/Learn/JavaScript/Asynchronous/Concepts#JavaScript_%D0%BE%D0%B4%D0%BD%D0%BE%D0%BF%D0%BE%D1%82%D0%BE%D1%87%D0%BD%D1%8B%D0%B9">JavaScript является однопоточным</a>. В каждый момент времени может выполняться только одна команда, обрабатываемая в единственном — главном потоке. Все остальные действия блокируются до окончания выполнения текущей команды.</p> + +<p>Так и в примере выше: после нажатия кнопки абзац не сможет появиться пока не будет нажата кнопка OK в окне сообщения. Попробуйте сами:</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><<span class="pl-ent">button</span>>Нажми меня</<span class="pl-ent">button</span>></pre> +</div> + +<p>{{EmbedLiveSample('Synchronous_JavaScript', '100%', '70px')}}</p> + +<div class="blockIndicator note"> +<p><strong>Заметка</strong>: Важно помнить, что <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code>, хоть и часто используется для демонстрации синхронных блокирующих операций, сильно не рекомендован к использованию в реальных приложениях.</p> +</div> + +<h2 id="Асинхронный_JavaScript">Асинхронный JavaScript</h2> + +<p>По причинам, упомянутым ранее (например, относящимся к блокировке), множество Web API особенностей теперь используют асинхронный код, особенно те,что имеют доступ к внешним устройствам или получают от них некоторые ресурсы, такие как получение файла из сети, запрос к базе данных и получение данных из базы, доступ к потоковому видео на веб-камере, просмотр дисплея на гарнитуре виртуальной реальности.</p> + +<p>Почему трудно работать, используя синхронный код? Давайте посмотрим на небольшой пример. Когда вы получаете картинку с сервера, вы не можете мгновенно вернуть результат. Это значит что следующий (псевдо) код не сработает:</p> + +<pre class="brush: js notranslate">let response = fetch('myImage.png'); +let blob = response.blob(); +// display your image blob in the UI somehow</pre> + +<p>Это проиходит потому что вы не знаете сколько времени займет загрузка картинки, следовательно, когда вы начнёте выполнять вторую строку кода, сгенерируется ошибка (возможно, переодически, возможно, каждый раз), потому что <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">response</span></font> еще не доступен. Вместо этого, ваш код должен дождаться возвращения <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">response</span></font> до того, как попытается выполнить дальнешие инструкции.</p> + +<p>Есть два типа стиля асинхронного кода, с которыми вы столкнетесь в коде JavaScript, старый метод — callbacks (обратные вызовы) и более новый — promise (промисы, обещания). В следующих разделах мы познакомимся с каждым из них. </p> + +<h2 id="Асинхронные_обратные_вызовы">Асинхронные обратные вызовы</h2> + +<p>Асинхронные обратные вызовы — это функции, которые определяются как агрументы при вызове функции, которая начнет выполнение кода на заднем фоне. Когда код на заднем фоне завершает свою работу, он вызвает функцию обратного вызова, оповещающую, что работа сделана, либо оповещающую о трудностях в завершении работы. Обратные вызовы — немного устраревшая практика, но они все еще употребляются в некоторых старомодных, но часто используемых API.</p> + +<p>Пример асинхронного обратного вызова вторым параметром {{domxref("EventTarget.addEventListener", "addEventListener()")}} (как мы видели выше):</p> + +<pre class="brush: js notranslate">btn.addEventListener('click', () => { + alert('You clicked me!'); + + let pElem = document.createElement('p'); + pElem.textContent = 'This is a newly-added paragraph.'; + document.body.appendChild(pElem); +});</pre> + +<p>Первый параметр — тип прослушиваемого события, второй параметр — функция обратного вызова, вызываемая при срабатывании события.</p> + +<p>При передаче функциии обратного вызова как аргумента в другую функцию, мы передаем только ссылку на функцию как аргумент, следовательно коллбэк функция <strong>не</strong> выполняется мгновенно. Где-то существует "обратный вызов" (отсюда и название), выполняющийся асинхронно внутри тела, содержащего функцию. Эта функция должна выполнять функцию обратногго вызова в нужный момент.</p> + +<p>Вы можете написать свою собственную функцию, содержащую функцию обратного вызова. Давайте взглянем на еще один пример, в котором происходит загрузка ресурсов через <a href="/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code> API</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/xhr-async-callback.html">запустите пример</a>, и <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/xhr-async-callback.html">посмотрите исходный код</a>):</p> + +<pre class="brush: js notranslate">function loadAsset(url, type, callback) { + let xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = type; + + xhr.onload = function() { + callback(xhr.response); + }; + + xhr.send(); +} + +function displayImage(blob) { + let objectURL = URL.createObjectURL(blob); + + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +} + +loadAsset('coffee.jpg', 'blob', displayImage);</pre> + +<p>Мы создали функцию <code>displayImage()</code>, которая представляет blob, переданный в нее, как обьект URL, и создает картинку, в которой отображается URL, добавляя ее в элемент документа <code><body></code>. Однако, далее мы создаем функцию <code>loadAsset()</code>, которая принимает функцию обратного вызова в качестве параметра, вместе с URL для получения данных и типом контента. Для получения данных из URL используется <code>XMLHttpRequest</code> (часто сокращается до аббревиатуры "XHR") , перед тем как передать ответ в функцию обратного вызова для дальнейшей обработки. В этом случае функция обратного вызова ждет, пока XHR закончит загрузку данных (используя обрабочик события <code><a href="/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code>) перед отправкой данных в функцию обратного вызова.</p> + +<p>Функции обратного вызова универсальны — они не только позволяют вам контролировать порядок, в котором запускаются функции и данные, передающиеся между ними, они также позволяют передавать данные различным функциям, в зависимости от обстоятельств. Вы можете выполнять различные действия с загруженным ответом, такие как <code>processJSON()</code>, <code>displayText()</code>, и другие.</p> + +<p>Заметьте, что не все функции обратного вызова асинхронны — некторые запускаются синхронно. Например, при использовании {{jsxref("Array.prototype.forEach()")}} для перебора элементов массива (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/foreach.html">запустите пример</a>, и <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/foreach.html">посмотрите исходный код</a>):</p> + +<pre class="brush: js notranslate">const gods = ['Apollo', 'Artemis', 'Ares', 'Zeus']; + +gods.forEach(function (eachName, index){ + console.log(index + '. ' + eachName); +});</pre> + +<p>В этом примере мы перебираем массив с именами греческих богов и выводим индексы и значения в консоль. Ожидаемый параметр для <code>forEach() </code> — это функцияобратного вызова, которая содержит два параметра: ссылку на имя массива и значения индексов. Однако эта функция не ожидает никаких действий — она запускается немедленно.</p> + +<h2 id="Промисы">Промисы</h2> + +<p>Промисы — новый стиль написания асинхронного кода, который используется в современных Web API. Хорошим примером является <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code> API, который современнее и эффективнее чем {{domxref("XMLHttpRequest")}}. Посмотрим на краткий пример, из нашей статьи <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a>:</p> + +<pre class="brush: js notranslate">fetch('products.json').then(function(response) { + return response.json(); +}).then(function(json) { + products = json; + initialize(); +}).catch(function(err) { + console.log('Ошибка загрузки: ' + err.message); +});</pre> + +<div class="blockIndicator note"> +<p><strong>Заметка</strong>: Вы можете посмотреть законченную версию на github (<a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store-xhr/can-script.js">посмотрите исходный код</a> и <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store-xhr/">запустите пример</a>).</p> +</div> + +<p>В примере видно, как <code>fetch()</code> принимает один параметр — URL ресурса, который нужно получить из сети, — и возвращает <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">промис</a>. Промис или обещание — это объект, представляющий асинхронную операцию, выполенную удачно или неудачно. Он представляет собой как бы промежуточное состояние. По сути, это способ браузера сказать: "я обещаю вернуться к вам с ответом как можно скорее," отсюда и название "обещание."</p> + +<p>Может пнадобиться много времени, чтобы привыкнуть к данной концепуии; это немного напоминает {{interwiki("wikipedia", "Кот Шрёдингера")}} в действии. Ни один из возможных результатов еще не произошел, поэтому операция fetch в настоящее время ожидает результата. Далее у нас есть три блока кода следующих сразу после <code>fetch()</code>:</p> + +<ul> + <li>Два <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> блока. Оба включают в себя функцию обратного, которая запустится, если предыдущая операция закончилась успешно, и каждая функция обратного вызова принимает на вход результат предыдущей успешно выполненной операции, таким образом вы можете выполнять операции последовательно. Каждый <code>.then()</code> блок возвращает новый promise, это значит что вы можете объеденять в цепочки (чейнить) блоки <code>.then()</code>, таким образом можно выполнить несколько асинхронных операций по порядку, одну за другой.</li> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">catch()</a></code> блок описывается в конце и будет запущен если какой-либо <code>.then()</code> блок завершится с ошибкой — это аналогично синхронному <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code>, ошибка становится доступной внутри <code>catch()</code>, что может быть использовано для сообщения пользователю о типе возникшей ошибки. Однако синхронный <code>try...catch</code> не будет работать с promise, хотя будет работать с <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">async/await</a>, с которыми вы познакомитесь позже.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Заметка</strong>: Вы узнаете намного больше о promise позже в этом модуле, так что не волнуйтесь если вы что-нибудь не поняли.</p> +</div> + +<h3 id="Очередь_событий">Очередь событий</h3> + +<p>Асинхронные операции, такие как промисы, помещаются в <strong>очередь событий</strong>, которая запускается после завершения обработки основного потока, чтобы они <em>не блокировали</em> выполнение JavaScript кода. Поставленные в очередь операции завершатся как можно скорее, а затем вернут свои результаты в среду JavaScript .</p> + +<h3 id="Промисы_и_функции_обратного_вызова">Промисы и функции обратного вызова</h3> + +<p>Промисы имеют некоторое сходство со старомодными функциями обратного вызова. По сути, они являются возвращаемым объектом, к которому вы присоединяете функции обратного вызова, вместо того, чтобы передавать обратные вызовы в функцию.</p> + +<p>Тем не менее, промисы сделаны специально для обработки асинхронных операций, и имеют много преимуществ по сравнению с обратными вызовами:</p> + +<ul> + <li>Вы можете объединить несколько асинхронных операций вместе, используя несколько операций<code>.then()</code>, передавая результат одного в следующий в качестве входных данных. Это гораздо сложнее сделать с обратными вызовами, которые часто заканчиваются массивным «адом обратных вызовов» (также известным как <a href="http://callbackhell.com/">callback hell</a>).</li> + <li>Обратные вызовы Promise всегда вызываются в строгом порядке, который они помещают в очередь событий..</li> + <li>Обработка ошибок намного лучше — все ошибки обрабатываются одним блоком <code>.catch ()</code> в конце блока, а не обрабатываются индивидуально на каждом уровне «пирамиды».</li> + <li>Промисы избегают инверсии управления, в отличие от обратных вызовов, которые теряют полный контроль над тем, как будет выполняться функция при передаче обратного вызова в стороннюю библиотеку.</li> +</ul> + +<h2 id="Природа_асинхронного_кода">Природа асинхронного кода</h2> + +<p>Давайте рассмотрим пример, который дополнительно иллюстрирует природу асинхронного кода, показывая, что может произойти, когда мы не полностью осознаем порядок выполнения кода, и проблемы, связанные с попыткой трактовать асинхронный код как синхронный. Следующий пример довольно похож на тот, что мы видели раньше (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync.html">запустите пример</a>, и <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">посмотрте исходный код</a>). Одно из отличий состоит в том, что мы включили ряд операторов {{domxref("console.log()")}} чтобы проиллюстрировать порядок, в котором, как вы думаете, будет выполняться код.</p> + +<pre class="brush: js notranslate">console.log ('Starting'); +let image; + +fetch('coffee.jpg').then((response) => { + console.log('It worked :)') + return response.blob(); +}).then((myBlob) => { + let objectURL = URL.createObjectURL(myBlob); + image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}).catch((error) => { + console.log('There has been a problem with your fetch operation: ' + error.message); +}); + +console.log ('All done!');</pre> + +<p>Браузер начнет выполнение кода, увидит первый консольный оператор <code>(Starting)</code> и выполнит его, а затем создаст переменную <code>image</code>.</p> + +<p>Затем он переместится на следующую строку и начнет выполнять блок <code>fetch ()</code>, но, поскольку <code>fetch ()</code> выполняется асинхронно без блокировки, выполнение кода продолжается после кода, связанного с промисом, тем самым достигая окончательного оператора (<code>All done!</code>) и выводя его на консоль.</p> + +<p>Только после того, как блок <code>fetch ()</code> полностью завершит работу и доставит свой результат через блоки <code>.then ()</code>, мы наконец увидим второе сообщение <code>console.log ()</code> (<code>It worked ;)</code>). Таким образом, сообщения появились не в том порядке, который вы могли ожидать:</p> + +<ul> + <li>Starting</li> + <li>All done!</li> + <li>It worked :)</li> +</ul> + +<p>Если вы запутались, рассмотрим следующий небольшой пример:</p> + +<pre class="brush: js notranslate">console.log("registering click handler"); + +button.addEventListener('click', () => { + console.log("get click"); +}); + +console.log("all done");</pre> + +<p>Этот пример очень схож с предыдущим в своем поведении — первое и третье сообщения <code>console.log ()</code> будут показаны немедленно, но второе будет заблокировано, пока кто-то не нажмет кнопку мыши. Предыдущий пример работает аналогичным образом, за исключением того, что в этом случае второе сообщение блокируется цепочкой промисов, получая ресурс, а затем отображая его на экране, а не щелчком мыши.</p> + +<p>В менее простом примере кода такая система может вызвать проблему — вы не можете включить блок асинхронного кода, который возвращает результат, на который вы потом будете полагаться в блоке синхронного кода. Вы просто не можете гарантировать, что асинхронная функция вернется до того, как браузер обработает синхронный блок.</p> + +<p>Чтобы увидеть это в действии, попробуйте взять локальную копию нашего <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">примера</a> и измените третий вызов <code>console.log ()</code> следующим образом:</p> + +<pre class="brush: js notranslate">console.log ('All done! ' + image + 'displayed.');</pre> + +<p>Теперь вместо третьего сообщения должна возникнуть следующая ошибка:</p> + +<pre class="notranslate"><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body">TypeError: image is undefined; can't access its "src" property</span></span></span></pre> + +<p>Это происходит потому, что в то же время браузер пытается запустить третий <code>console.log()</code>, блок <code>fetch()</code> еще не закончил выполнение, поэтому переменная <code>image</code> еще не имеет значения.</p> + +<div class="blockIndicator note"> +<p><strong>Заметка</strong>: Из соображений безопасности вы не можете применять <code>fetch() </code> к файлам из вашей локальной системы (или запустить другие такие операции локально); чтобы запустить локально пример выше вам необходимо запустить его через <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">локальный веб-сервер</a>.</p> +</div> + +<h2 id="Активное_обучение_сделайте_все_это_асинхронно!">Активное обучение: сделайте все это асинхронно!</h2> + +<p>Чтобы исправить проблемный пример с <code>fetch()</code> и заставить все три сообщения <code>console.log()</code> появиться в желаемом порядке, вы можете также запустить третье сообщение <code>console.log()</code> асинхронно. Этого можно добиться, переместив его внутрь другого блока <code>.then()</code> присоединенного к концу второго, или просто переместив его внутрь второго блока <code>then()</code>. Попробуйте иправить это сейчас..</p> + +<div class="blockIndicator note"> +<p><strong>Заметка</strong>: Если вы застряли, вы можете <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync-fixed.html">найти ответ здесь</a> (также можно посмотреть <a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync-fixed.html">запущенный пример</a>). Также вы можете найти много информации о промисах в нашем гайде <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Основные понятия асинхронного программирования</a> позднее в этом модуле.</p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>В своей основной форме JavaScript является синхронным, блокирующим, однопоточным языком, в котором одновременно может выполняться только одна операция. Но веб-браузеры определяют функции и API, которые позволяют нам регистрировать функции, которые не должны выполняться синхронно, а должны вызываться асинхронно, когда происходит какое-либо событие (время, взаимодействие пользователя с мышью или получение данных по сети, например). Это означает, что вы можете позволить своему коду делать несколько вещей одновременно, не останавливая и не блокируя основной поток.</p> + +<p>Будем ли мы запускать код синхронно или асинхронно, будет зависеть от того, что мы пытаемся сделать.</p> + +<p>Есть моменты, когда мы хотим, чтобы все загружалось и происходило прямо сейчас. Например, при применении некоторых пользовательских стилей к веб-странице вы хотите, чтобы стили применялись как можно быстрее.</p> + +<p>Если мы выполняем операцию, которая требует времени, например, запрос к базе данных и использование полученных результатов для заполнения шаблонов, лучше вытолкнуть это из основного потока и выполнить задачу асинхронно. Со временем вы узнаете, когда имеет смысл выбирать асинхронную технику вместо синхронной.</p> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/JavaScript/Asynchronous/Concepts">Основные понятия асинхронного программирования</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ru/learn/javascript/asynchronous/таймауты_и_интервалы/index.html b/files/ru/learn/javascript/asynchronous/таймауты_и_интервалы/index.html new file mode 100644 index 0000000000..00506c2a14 --- /dev/null +++ b/files/ru/learn/javascript/asynchronous/таймауты_и_интервалы/index.html @@ -0,0 +1,638 @@ +--- +title: 'Объединенный асинхронный JavaScript: Таймайты и интервалы' +slug: Learn/JavaScript/Asynchronous/Таймауты_и_интервалы +translation_of: Learn/JavaScript/Asynchronous/Timeouts_and_intervals +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary">В этом руководстве рассматриваются традиционные методы, доступные в JavaScript для асинхронного выполнения кода по истечении заданного периода времени или через регулярный интервал (например, заданное количество раз в секунду), обсуждаются их полезные свойства и рассматриваются присущие им проблемы. .</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Базовая компьютерная грамотность, достаточное понимание основ JavaScript.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понимание асинхронных циклов и интервалов, и то как их можно использовать.</td> + </tr> + </tbody> +</table> + +<h2 id="Введение">Введение</h2> + +<p>В течение долгого времени веб-платформа предлагала программистам JavaScript ряд функций, которые позволяли им асинхронно выполнять код по истечении определенного временного интервала и повторно выполнять асинхронный блок кода, пока вы не скажете ему остановиться.</p> + +<p>Эти функции:</p> + +<dl> + <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code></dt> + <dd>Выполняет указанный блок кода один раз по истечении указанного времени</dd> + <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a></code></dt> + <dd>Выполняет указанный блок кода несколько раз с определенным интервалом между каждым вызовом.</dd> + <dt><code><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code></dt> + <dd>Современная версия setInterval (). Выполняут указанный блок кода перед тем, как браузер в следующий раз перерисовывает отображение, позволяя запускать анимацию с подходящей частотой кадров независимо от среды, в которой она выполняется.</dd> +</dl> + +<p>Асинхронный код, установленный этими функциями, выполняется в основном потоке (по истечении указанного им таймера).</p> + +<div> +<p>Важно знать, что вы можете (и часто будете) запускать другой код до выполнения вызова setTimeout () или между итерациями setInterval (). В зависимости от того, насколько интенсивно используются эти операции для процессора, они могут еще больше задержать выполнение асинхронного кода, поскольку любой асинхронный код будет выполняться только после того, как станет доступен основной поток. (Другими словами, когда стек пуст.) Вы узнаете больше по этому вопросу по мере изучения этой статьи.</p> +</div> + +<p>В любом случае эти функции используются для запуска постоянной анимации и другой фоновой обработки на веб-сайте или в приложении. В следующих разделах мы покажем вам, как их можно использовать.</p> + +<h2 id="setTimeout">setTimeout()</h2> + +<p>Как мы ранее отметили, setTimeout () выполняет определенный блок кода один раз по истечении заданного времени. Принимает следующие параметры:</p> + +<ul> + <li>Функция для запуска или ссылка на функцию, определенную в другом месте.</li> + <li>Число, представляющее интервал времени в миллисекундах (1000 миллисекунд равняется 1 секунде) ожидания перед выполнением кода. Если вы укажете значение 0 (или просто опустите значение), функция запустится как можно скорее. (См. Примечание ниже о том, почему он запускается «как можно скорее», а не «сразу».) Подробнее о том, почему вы, возможно, захотите сделать это позже.</li> + <li>Значений, представляющие любые параметры, которые вы хотите передать функции при ее запуске.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>NOTE: </strong> Указанное время (или задержка) не является гарантированным временем выполнения, а скорее минимальным временем выполнения. Обратные вызовы, которые вы передаете этим функциям, не могут выполняться, пока стек в основном потоке не станет пустым.</p> + +<p>Как следствие, такой код, как setTimeout (fn, 0), будет выполняться, как только стек будет пуст, а не сразу. Если вы выполните такой код, как setTimeout (fn, 0), но сразу после выполнения цикла, который насчитывает от 1 до 10 миллиардов, ваш обратный вызов будет выполнен через несколько секунд.</p> +</div> + +<p>В слудующем примере, браузер будет ожидать две секунды перед тем как выполнит анонимную функцию, тогда отобразит сообщение (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/simple-settimeout.html">живой пример</a>, и <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/simple-settimeout.html">исходный код</a>):</p> + +<pre class="brush: js notranslate">let myGreeting = setTimeout(function() { + alert('Hello, Mr. Universe!'); +}, 2000)</pre> + +<p>Указанные вами функции не обязательно должны быть анонимными. Вы можете дать своей функции имя и даже определить ее где-нибудь еще и передать ссылку на функцию в setTimeout (). Следующие две версии фрагмента кода эквивалентны первой:</p> + +<pre class="brush: js notranslate">// С именованной функцией +let myGreeting = setTimeout(function sayHi() { + alert('Hello, Mr. Universe!'); +}, 2000) + +// С функцией определенной отдельно +function sayHi() { + alert('Hello Mr. Universe!'); +} + +let myGreeting = setTimeout(sayHi, 2000);</pre> + +<p>Это может быть полезно, если у вас есть функция, которую нужно вызывать как по таймауту, так например и в ответ на событие. Но это также может помочь поддерживать ваш код в чистоте, особенно если обратный вызов тайм-аута занимает больше, чем несколько строк кода.</p> + +<p><code>setTimeout () </code>возвращает значение идентификатора, которое можно использовать для ссылки на тайм-аут позже, например, когда вы хотите его остановить.</p> + +<h3 id="Передача_параметров_в_функцию_setTimeout">Передача параметров в функцию setTimeout ()</h3> + +<p>Любые параметры, которые вы хотите передать функции, выполняемой внутри setTimeout (), должны быть переданы ей как дополнительные параметры в конце списка.</p> + +<p>Например, вы можете реорганизовать предыдущую функцию, чтобы она передавала привет любому имени, переданному ей:</p> + +<pre class="brush: js notranslate">function sayHi(who) { + alert(`Hello ${who}!`); +}</pre> + +<p>Теперь вы можете передать имя в вызов setTimeout () в качестве третьего параметра:</p> + +<pre class="brush: js notranslate">let myGreeting = setTimeout(sayHi, 2000, 'Mr. Universe');</pre> + +<h3 id="Очистка_таймаутов">Очистка таймаутов</h3> + +<p>Наконец, если был создан тайм-аут, вы можете отменить его до истечения указанного времени, вызвав <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout">clearTimeout()</a></code>, передав ему идентификатор вызова <code>setTimeout()</code> в качестве параметра. Итак, чтобы отменить указанный выше тайм-аут, вы должны сделать следующее:</p> + +<pre class="brush: js notranslate">clearTimeout(myGreeting);</pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: См.<code><a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/greeter-app.html">greeter-app.html</a></code> для более полной демонстрации, которая позволяет вам указать имя для приветствия и отменить приветствие с помощью отдельной кнопки (<a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/greeter-app.html">см. исходный код</a>).</p> +</div> + +<h2 id="setInterval">setInterval()</h2> + +<p><code>setTimeout ()</code> отлично работает, когда вам нужно один раз запустить код по истечении заданного периода времени. Но что происходит, когда вам нужно запускать код снова и снова - например, в случае анимации?</p> + +<p>Здесь пригодится <a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a> . Работает очень похоже на setTimeout (), за исключением того, что функция, которую вы передаете в качестве первого параметра, выполняется повторно не менее чем за количество миллисекунд, заданных вторым параметром. Вы также можете передать любые параметры, необходимые для выполняемой функции, в качестве последующих параметров вызова setInterval ().</p> + +<p>Давайте посмотрим на пример. Следующая функция создает новый объект <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">Date()</a></code>, с помощью <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString">toLocaleTimeString()</a></code> извлекает из него строку с временем и отображает ее в пользовательском интерфейсе. Затем он запускает функцию один раз в секунду с помощью <code>setInterval()</code>, создавая эффект цифровых часов, которые обновляются раз в секунду (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/setinterval-clock.html"> реальный пример</a>, и <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">исходный код</a>):</p> + +<pre class="brush: js notranslate">function displayTime() { + let date = new Date(); + let time = date.toLocaleTimeString(); + document.getElementById('demo').textContent = time; +} + +const createClock = setInterval(displayTime, 1000);</pre> + +<p>Как и <code>setTimeout ()</code>, <code>setInterval ()</code> возвращает определенное значение, которое вы можете использовать позже, когда вам нужно очистить интервал.</p> + +<h3 id="Очистка_интервала">Очистка интервала</h3> + +<p><code>setInterval () </code>выполняет задачу постоянно. setInterval () продолжает выполнять задачу вечно, если вы что-то с ней не сделаете. Возможно, вам понадобится способ остановить такие задачи, иначе вы можете получить ошибки, если браузер не сможет выполнить какие-либо другие версии задачи или если анимация, обрабатываемая задачей, завершилась. Вы можете сделать это так же, как останавливаете <code>timeouts</code> - передавая идентификатор, возвращаемый вызовом <code>setInterval ()</code>, в функцию <code>clearInterval ()</code>:</p> + +<pre class="brush: js notranslate">const myInterval = setInterval(myFunction, 2000); + +clearInterval(myInterval);</pre> + +<h4 id="Активное_обучение_Создание_собственного_секундомера!">Активное обучение: Создание собственного секундомера!</h4> + +<p>Учитывая все вышесказанное, у нас есть для вас задача. Возьмите копию нашего примера <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">setInterval-clock.html</a></code> , и измените ее так, чтобы создать свой собственный простой секундомер.</p> + +<p>Вам нужно отображать время, как и раньше, но в этом примере вам нужно:</p> + +<ul> + <li>Кнопка "Start" для запуска секундомера.</li> + <li>Кнопка "Stop" для паузы/остановки.</li> + <li>Кнопка "Reset", чтобы сбросить счетчик времени на <code>0</code>.</li> + <li>Дисплей времени, чтобы отображать количество прошедших секунд а не фактическое время.</li> +</ul> + +<p>Несколько подсказок для вас:</p> + +<ul> + <li>Вы можете структурировать и стилизовать разметку кнопок по своему усмотрению; просто убедитесь, что вы используете семантический HTML с ковычками, которые позволяют захватывать ссылки на кнопки с помощью JavaScript.</li> + <li>Вероятно, вы захотите создать переменную, которая начинается с 0, а затем увеличивается на единицу каждую секунду с использованием постоянного цикла.</li> + <li>Этот пример проще создать без использования объекта Date (), как мы это делали в нашей версии, но он будет менее точен - вы не можете гарантировать, что обратный вызов сработает ровно через 1000 мс. Более точным способом было бы запустить startTime = Date.now (), чтобы получить метку времени, когда пользователь нажал кнопку запуска, а затем выполнить Date.now () - startTime, чтобы получить количество миллисекунд после того, как была нажата кнопка запуска .</li> + <li>Вам также нужно рассчитать количество часов, минут и секунд как отдельные значения, а затем отображать их вместе в строке после каждой итерации цикла. На втором счетчике вы можете отработать каждую из них.</li> + <li>Как вы могли бы их рассчитать? Подумайте об этом: + <ul> + <li>В одном часе <code>3600 </code>секунд.</li> + <li>Количество минут - это количество секунд, оставшееся после вычитания всех часов, разделенное на 60.</li> + <li>Количество секунд будет количеством секунд, оставшихся после вычитания всех минут.</li> + </ul> + </li> + <li>Вам необходимо включить начальный ноль в отображаемые значения, если сумма меньше <code>10</code>, чтобы они больше походили на традиционные часы.</li> + <li>Чтобы приостановить секундомер, вам нужно очистить интервал. Чтобы сбросить его, вам нудно установить счетчик обратно на <code>0</code>, очистить интервал, а затем немедленно обновить отображение.</li> + <li>Вероятно, вам следует отключить кнопку запуска после ее нажатия один раз и снова включить ее после того, как вы остановили / сбросили ее. В противном случае многократное нажатие кнопки запуска приведет к применению нескольких <code>setInterval ()</code> к часам, что приведет к неправильному поведению.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Если вы застрали, вы можете <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/setinterval-stopwatch.html">увидеть нашу версию</a> (см. также <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-stopwatch.html">исходный код</a> ).</p> +</div> + +<h2 id="Что_нужно_помнить_о_setTimeout_и_setInterval">Что нужно помнить о <code>setTimeout ()</code> и <code>setInterval ()</code></h2> + +<p>При работе с<code> setTimeout ()</code> и <code>setInterval ()</code> следует помнить о нескольких вещах. Давайте рассмотрим их.</p> + +<h3 id="Рекурсивые_таймауты">Рекурсивые таймауты</h3> + +<p>Есть еще один способ использования <code>setTimeout ()</code>: вы можете вызвать его рекурсивно для повторного запуска одного и того же кода вместо использования <code>setInterval ()</code>.</p> + +<p>В приведенном ниже примере используется рекурсивный setTimeout () для запуска переданной функции каждые 100 миллисекунд:</p> + +<pre class="brush: js notranslate">let i = 1; + +setTimeout(function run() { + console.log(i); + i++; + setTimeout(run, 100); +}, 100);</pre> + +<p>Сравните приведенный выше пример со следующим - здесь используется <code>setInterval ()</code> для достижения того же эффекта:</p> + +<pre class="brush: js notranslate">let i = 1; + +setInterval(function run() { + console.log(i); + i++ +}, 100);</pre> + +<h4 id="Чем_рекурсивный_setTimeout_отличается_от_setInterval">Чем рекурсивный <code>setTimeout ()</code> отличается от <code>setInterval () </code>?</h4> + +<p>Разница между двумя версиями приведенного выше кода невелика.</p> + +<ul> + <li>Рекурсивный <code>setTimeout ()</code> гарантирует такую же задержку между выполнениями. (Например, 100 мс в приведенном выше случае.) Код будет запущен, затем подождет 100 миллисекунд, прежде чем запустится снова, поэтому интервал будет одинаковым, независимо от того, сколько времени требуется для выполнения кода.</li> + <li>Пример с использованием <code>setInterval () </code>работает несколько иначе. Выбранный вами интервал включает время, затрачиваемое на выполнение кода, который вы хотите запустить. Предположим, что выполнение кода занимает <code>40 </code>миллисекунд - тогда интервал составляет всего <code>60 </code>миллисекунд.</li> + <li>При рекурсивном использовании <code>setTimeout ()</code> каждая итерация может вычислять различную задержку перед запуском следующей итерации. Другими словами, значение второго параметра может указывать другое время в миллисекундах для ожидания перед повторным запуском кода.</li> +</ul> + +<p>Когда ваш код потенциально может занять больше времени, чем назначенный вами интервал времени, лучше использовать рекурсивный <code>setTimeout ()</code> - это сохранит постоянный временной интервал между выполнениями независимо от того, сколько времени потребуется для выполнения кода, и вы избежите ошибок.</p> + +<h3 id="Немедленные_таймауты">Немедленные таймауты</h3> + +<p>Использование 0 в качестве значения для <code>setTimeout ()</code> позволяет планировать выполнение указанной функции обратного вызова как можно скорее, но только после того, как будет запущен основной поток кода.</p> + +<p>Например, код приведенный ниже (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/zero-settimeout.html">рабочий код</a>) выводит alert содержащий <code>"Hello"</code>, затем alert содержащий <code>"World"</code> как только вы нажмете ОК в первом alert.</p> + +<pre class="brush: js notranslate">setTimeout(function() { + alert('World'); +}, 0); + +alert('Hello');</pre> + +<p>Это может быть полезно в тех случаях, когда вы хотите установить блок кода для запуска, как только весь основной поток завершит работу - поместите его в цикл событий async, чтобы он запускался сразу после этого.</p> + +<h3 id="Очистка_с_помощью_clearTimeout_или_clearInterval">Очистка с помощью <code>clearTimeout()</code> или <code>clearInterval()</code></h3> + +<p>clearTimeout () и <code>clearInterval ()</code> используют один и тот же список записей для очистки. Интересно, что это означает, что вы можете использовать любой метод для очистки setTimeout () или setInterval ().</p> + +<p>Для согласованности следует использовать <code>clearTimeout ()</code> для очистки записей <code>setTimeout ()</code> и <code>clearInterval ()</code> для очистки записей <code>setInterval ()</code>. Это поможет избежать путаницы.</p> + +<h2 id="requestAnimationFrame">requestAnimationFrame()</h2> + +<p><code><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code> это специализированная функция цикла, созданная для эффективного запуска анимации в браузере. По сути, это современная версия <code>setInterval ()</code> - она выполняет указанный блок кода до того, как браузер перерисовывает изображение, позволяя запускать анимацию с подходящей частотой кадров независимо от среды, в которой она выполняется.</p> + +<p>Он был создан в ответ на проблемы с <code>setInterval ()</code>, который, например, не работает с частотой кадров, оптимизированной для устройства, иногда пропускает кадры, продолжает работать, даже если вкладка не является активной вкладкой или анимация прокручивается со страницы и т. д.(<a href="http://creativejs.com/resources/requestanimationframe/index.html">Читай об этом больше в CreativeJS</a>.)</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Вы можете найти примеры использования <code>requestAnimationFrame()</code> в этом курсе — например в <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Рисование графики</a>, and <a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Практика построения объектов</a>.</p> +</div> + +<p>Метод принимает в качестве аргумента обратный вызов, который должен быть вызван перед перерисовкой. Это общий шаблон, в котором он используется:</p> + +<pre class="brush: js notranslate">function draw() { + // Drawing code goes here + requestAnimationFrame(draw); +} + +draw();</pre> + +<p>Идея состоит в том, чтобы определить функцию, в которой ваша анимация обновляется (например, ваши спрайты перемещаются, счет обновляется, данные обновляются или что-то еще). Затем вы вызываете его, чтобы начать процесс. В конце функционального блока вы вызываете <code>requestAnimationFrame ()</code> со ссылкой на функцию, переданной в качестве параметра, и это дает браузеру указание вызвать функцию снова при следующей перерисовке дисплея. Затем он выполняется непрерывно, поскольку код рекурсивно вызывает <code>requestAnimationFrame ().</code></p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Если вы хотите выполнить простое постоянное анимирование DOM , <a href="/en-US/docs/Web/CSS/CSS_Animations">CSS Анимация</a> вероятно будет быстрее. Она высисляется непосредственно внутренним кодом браузера, а не JavaScript.</p> + +<p>Однако, если вы делаете что-то более сложное, включающее объекты, которые не доступны напрямую в the DOM (такие как <a href="/en-US/docs/Web/API/Canvas_API">2D Canvas API</a> или <a href="/en-US/docs/Web/API/WebGL_API">WebGL</a> ), <code>requestAnimationFrame()</code> предпочтительный вариант в большинстве случаев.</p> +</div> + +<h3 id="Как_быстро_работает_ваша_анимация">Как быстро работает ваша анимация?</h3> + +<p>Плавность анимации напрямую зависит от частоты кадров анимации и измеряется в кадрах в секунду (fps). Чем выше это число, тем плавнее будет выглядеть ваша анимация до точки.</p> + +<p>Поскольку большинство экранов имеют частоту обновления 60 Гц, максимальная частота кадров, к которой вы можете стремиться, составляет 60 кадров в секунду (FPS) при работе с веб-браузерами. Однако большее количество кадров означает больше обработки, которая часто может вызывать заикание и пропуски, также известные как пропадание кадров или заедание.</p> + +<p>Если у вас есть монитор с частотой обновления 60 Гц и вы хотите достичь 60 кадров в секунду, у вас есть около 16,7 миллисекунд <code>(1000/60)</code> для выполнения кода анимации для рендеринга каждого кадра. Это напоминание о том, что вам нужно помнить об объеме кода, который вы пытаетесь запустить во время каждого прохождения цикла анимации.</p> + +<p><code>requestAnimationFrame ()</code> всегда пытается приблизиться к этому волшебному значению 60 FPS, насколько это возможно. Иногда это невозможно - если у вас действительно сложная анимация и вы запускаете ее на медленном компьютере, частота кадров будет меньше. Во всех случаях<code> requestAnimationFrame ()</code> всегда будет делать все возможное с тем, что у него есть.</p> + +<h3 id="Чем_отличается_requestAnimationFrame_от_setInterval_and_setTimeout">Чем отличается requestAnimationFrame() от setInterval() and setTimeout()?</h3> + +<p>Давайте поговорим еще немного о том, чем метод <code>requestAnimationFrame ()</code> отличается от других методов, используемых ранее. Глядя на наш код сверху:</p> + +<pre class="brush: js notranslate">function draw() { + // Drawing code goes here + requestAnimationFrame(draw); +} + +draw();</pre> + +<p>Такой же код с использованием <code>setInterval()</code>:</p> + +<pre class="brush: js notranslate">function draw() { + // Drawing code goes here +} + +setInterval(draw, 17);</pre> + +<p>Как мы уже говорили ранее, вы не указываете временной интервал для <code>requestAnimationFrame ()</code>. Просто он работает максимально быстро и плавно в текущих условиях. Браузер также не тратит время на запуск, если по какой-то причине анимация выходит за пределы экрана и т. д.</p> + +<p><code>setInterval ()</code>, с другой стороны, требует указания интервала. Мы пришли к нашему окончательному значению 17 по формуле 1000 миллисекунд / 60 Гц, а затем округлили его в большую сторону. Округление - хорошая идея; если вы округлите в меньшую сторону, браузер может попытаться запустить анимацию со скоростью, превышающей 60 кадров в секунду, и в любом случае это не повлияет на плавность анимации. Как мы уже говорили, стандартная частота обновления - 60 Гц.</p> + +<h3 id="В_том_числе_временная_метка">В том числе временная метка</h3> + +<p>Фактическому обратному вызову, переданному в функцию <code>requestAnimationFrame ()</code>, также может быть задан параметр: значение отметки времени, которое представляет время с момента начала работы <code>requestAnimationFrame ().</code></p> + +<p>Это полезно, поскольку позволяет запускать вещи в определенное время и в постоянном темпе, независимо от того, насколько быстрым или медленным может быть ваше устройство. Общий шаблон, который вы бы использовали, выглядит примерно так:</p> + +<pre class="brush: js notranslate">let startTime = null; + +function draw(timestamp) { + if (!startTime) { + startTime = timestamp; + } + + currentTime = timestamp - startTime; + + // Do something based on current time + + requestAnimationFrame(draw); +} + +draw();</pre> + +<h3 id="Поддержка_браузерами">Поддержка браузерами</h3> + +<p><code>requestAnimationFrame ()</code> поддерживается в более поздних версиях браузеров, чем s<code>etInterval ()</code> / <code>setTimeout ()</code>. Интересно, что он доступен в Internet Explorer 10 и выше.</p> + +<p>Итак, если вам не тербуется поддержка старых версий IE, нет особых причин не использовать <code>requestAnimationFrame()</code>.</p> + +<h3 id="Простой_пример">Простой пример</h3> + +<p>Хватит теории! Давайте выполним упражнение с использованием <code>requestAnimationFrame()</code> . Создадим простую анимацию "spinner animation"—вы могли ее видеть в приложениях когда происходят задержки при ответе с сервера и т.п..</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Для такой простой анимации, вам следовало бы использовать CSS . Однако такой вид анимации очень полезен для демонстрации <code>requestAnimationFrame()</code> , вы скорее всего будете использовать этот метод когда делаете что-то более сложное, например обновление отображения игры в каждом кадре.</p> +</div> + +<ol> + <li> + <p>Возьмите базовый HTML шаблон (<a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">такой как этот</a>).</p> + </li> + <li> + <p>Поместите пустой {{htmlelement("div")}} елемент внутри элемента {{htmlelement("body")}}, затем добавьте внутрь символ ↻ . Этот символ будет действовать как spinner в нашем примере.</p> + </li> + <li> + <p>Применитеpply следующий CSS к HTML шаблону (любым предпочитаемым способом). Он установ красный фон на странице, высоту <code><body></code> равную <code>100%</code> высоты {{htmlelement("html")}} , и центрирует <code><div></code> внутри <code><body></code>, по горизонтали и вертикали.</p> + + <pre class="brush: css notranslate">html { + background-color: white; + height: 100%; +} + +body { + height: inherit; + background-color: red; + margin: 0; + display: flex; + justify-content: center; + align-items: center; +} + +div { + display: inline-block; + font-size: 10rem; +}</pre> + </li> + <li> + <p>Разместите {{htmlelement("script")}} элемент перед <code></body></code> .</p> + </li> + <li> + <p>Разместите следующий JavaScript код в <code><script></code> . Здесь вы сохраняете ссылку на <code><div></code> внутри, устанавливаете дяпеременной <code>rotateCount</code> значение <code>0</code>, устанавливаете неинициализированную переменную, которая позже будет использоваться для хранения ссылки на вызов <code>requestAnimationFrame()</code>, и устанавливатете для переменной <code>startTime</code> значение <code>null</code>, которая будет позже использоваться для хранения времени начала <code>requestAnimationFrame()</code>.</p> + + <pre class="brush: js notranslate">const spinner = document.querySelector('div'); +let rotateCount = 0; +let startTime = null; +let rAF; +</pre> + </li> + <li> + <p>Под предыдущим котом вставьте функцию <code>draw()</code> соторая будет использоваться для хранения нашешо кода анимации, который включает параметр <code>timestamp</code> :</p> + + <pre class="brush: js notranslate">function draw(timestamp) { + +}</pre> + </li> + <li> + <p>Внутри <code>draw ()</code> добавьте следующие строки. Они определят время начала, если оно еще не определено (это произойдет только на первой итерации цикла), и установят для параметра <code>rotateCount</code> значение для поворота счетчика (текущая временная метка, возьмите начальную временную метку, разделенную на три, чтобы замедлиться):</p> + + <pre class="brush: js notranslate"> if (!startTime) { + startTime = timestamp; + } + + rotateCount = (timestamp - startTime) / 3; +</pre> + </li> + <li> + <p>Под предыдущей строкой внутри <code>draw ()</code> добавьте следующий блок - он проверяет, превышает ли значение <code>rotateCount 359</code> (например, <code>360</code>, полный круг). Если это так, он устанавливает значение по модулю <code>360</code> (то есть остаток, оставшийся после деления значения на <code>360</code>), поэтому круговая анимация может продолжаться непрерывно с разумным низким значением. Обратите внимание, что это не является строго необходимым, но легче работать со значениями от 0 до <code>359</code> градусов, чем со значениями типа «<code>128000</code> градусов».</p> + + <pre class="brush: js notranslate">if (rotateCount > 359) { + rotateCount %= 360; +}</pre> + </li> + <li>Затем, под предыдущим блоком, добавьте следующую строку, чтобы вращать spinner: + <pre class="brush: js notranslate">spinner.style.transform = `rotate(${rotateCount}deg)`;</pre> + </li> + <li> + <p>В самом низу внутри функции <em>draw ()</em> вставьте следующую строку. Это ключ ко всей операции - вы устанавливаете для переменной, определенной ранее, активный вызов<em> requestAnimation ()</em>, который принимает функцию <em>draw ()</em> в качестве своего параметра. Это запускает анимацию, постоянно выполняя функцию <em>draw ()</em> со скоростью, близкой к 60 FPS.</p> + + <pre class="brush: js notranslate">rAF = requestAnimationFrame(draw);</pre> + </li> + <li> + <p>Ниже, вызовите функцию <code>draw()</code> для запуска анимации.</p> + + <pre class="brush: js notranslate">draw();</pre> + </li> +</ol> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Вы можете посмотреть <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/simple-raf-spinner.html">рабочий образец на GitHub</a>. ( <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/simple-raf-spinner.html">исходный код</a>.)</p> +</div> + +<h3 id="Очbстка_вызова_requestAnimationFrame">Очbстка вызова requestAnimationFrame() </h3> + +<p>Очистить вызов <code>requestAnimationFrame ()</code> можно, вызвав соответствующий метод <code>cancelAnimationFrame ()</code>. (Обратите внимание, что имя функции начинается с «cancel», а не «clear», как у методов «set ...».)</p> + +<p>Просто передайте ему значение, возвращаемое вызовом requestAnimationFrame () для отмены, которое вы сохранили в переменной rAF:</p> + +<pre class="brush: js notranslate">cancelAnimationFrame(rAF);</pre> + +<h3 id="Активное_обучение_запуск_и_остановка_нашей_анимации">Активное обучение: запуск и остановка нашей анимации</h3> + +<p>В этом упражнении мы хотели бы, чтобы вы протестировали метод <code>cancelAnimationFrame ()</code>, взяв наш предыдущий пример и обновив его, добавив прослушиватель событий для запуска и остановки счетчика при щелчке мышью в любом месте страницы.</p> + +<p>Подсказки:</p> + +<ul> + <li>Обработчик события щелчка можно добавить к большинству элементов, включая документ <code><body></code>. Имеет смысл поместить его в элемент <code><body></code>, если вы хотите максимизировать интерактивную область - событие всплывает до его дочерних элементов.</li> + <li>Вы захотите добавить переменную отслеживания, чтобы проверить, вращается ли счетчик или нет, очистив кадр анимации, если он есть, и снова вызвать его, если это не так.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Для начала попробуйте сами; если вы действительно застряли, посмотрите наш <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/start-and-stop-spinner.html">живой пример</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/start-and-stop-spinner.html">исходный код</a>.</p> +</div> + +<h3 id="Регулировка_анимации_requestAnimationFrame">Регулировка анимации <code>requestAnimationFrame()</code> </h3> + +<p>Одним из ограничений <code>requestAnimationFrame ()</code> является то, что вы не можете выбирать частоту кадров. В большинстве случаев это не проблема, так как обычно вы хотите, чтобы ваша анимация работала как можно плавнее. Но как насчет того, чтобы создать олдскульную 8-битную анимацию?</p> + +<p>Это было проблемой, например в анимации ходьбы, вдохновленной островом обезьян, из статьи <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing Graphics</a>:</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/loops_animation/7_canvas_walking_animation.html", '100%', 260)}}</p> + +<p>В этом примере вы должны анимировать как положение персонажа на экране, так и отображаемый спрайт. В анимации спрайта всего 6 кадров. Если бы вы показывали разные кадры спрайта для каждого кадра, отображаемого на экране, с помощью requestAnimationFrame (), Guybrush двигал бы конечностями слишком быстро, и анимация выглядела бы нелепо. Следовательно, в этом примере регулируется скорость, с которой спрайт циклически повторяет свои кадры, используя следующий код:</p> + +<pre class="brush: js notranslate">if (posX % 13 === 0) { + if (sprite === 5) { + sprite = 0; + } else { + sprite++; + } +}</pre> + +<p>Таким образом, код циклически повторяет спрайт только один раз каждые 13 кадров анимации.</p> + +<p>... Фактически, это примерно каждые 6,5 кадров, поскольку мы обновляем posX (положение персонажа на экране) на два кадра:</p> + +<pre class="brush: js notranslate">if (posX > width/2) { + newStartPos = -( (width/2) + 102 ); + posX = Math.ceil(newStartPos / 13) * 13; + console.log(posX); +} else { + posX += 2; +}</pre> + +<p>Это код, который вычисляет, как обновлять позицию в каждом кадре анимации.</p> + +<p>Метод, который вы используете для регулирования анимации, будет зависеть от вашего конкретного кода. Например, в предыдущем примере счетчика вы могли заставить его двигаться медленнее, увеличивая rotateCount только на единицу в каждом кадре вместо двух.</p> + +<h2 id="Активное_обучение_игра_на_реакцию">Активное обучение: игра на реакцию</h2> + +<p>В последнем разделе этой статьи вы создадите игру на реакцию для двух игроков. В игре будет два игрока, один из которых управляет игрой с помощью клавиши <kbd>A</kbd>, а другой - с помощью клавиши<kbd> L</kbd>.</p> + +<p>При нажатии кнопки «Start» счетчик, подобный тому, что мы видели ранее, отображается в течение случайного промежутка времени от 5 до 10 секунд. По истечении этого времени появится сообщение «PLAYERS GO !!» - как только это произойдет, первый игрок, который нажмет свою кнопку управления, выиграет игру.</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/asynchronous/loops-and-intervals/reaction-game.html", '100%', 500)}}</p> + +<p>Давайте поработаем над этим:</p> + +<ol> + <li> + <p>Прежде всего, скачайте <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/reaction-game-starter.html">стартовый файл</a>. Он содержит законченную структуру HTML и стили CSS, что дает нам игровую доску, которая показывает информацию двух игроков (как показано выше), но с счетчиком и параграфом результатов, отображаемыми друг над другом. Вам нужно просто написать JavaScript код.</p> + </li> + <li> + <p>Внутри пустого элемента {{htmlelement("script")}} на вашей старнице, начните с добавления следующих строк кода, котороые определяют некотороые переменные и константы, которые вам понадобятся в дальнейшем:</p> + + <pre class="brush: js notranslate">const spinner = document.querySelector('.spinner p'); +const spinnerContainer = document.querySelector('.spinner'); +let rotateCount = 0; +let startTime = null; +let rAF; +const btn = document.querySelector('button'); +const result = document.querySelector('.result');</pre> + + <p>В следующем порядке:</p> + + <ol> + <li>Ссылка на спиннер, чтобы вы могли его анимировать.</li> + <li>Ссылка на элемент {{htmlelement("div")}} содержащий спиннер, используемый для отображения и скрытия.</li> + <li>Счетчик поворотов. Он определяет, на сколько вы хотите показывать вращение спиннера на каждом кадре анимации.</li> + <li>Нулевое время начала. Это будет заполнено временем начала, когда счетчик начнет вращаться.</li> + <li>Неинициализировання переменная для последующего хранения вызова {{domxref("Window.requestAnimationFrame", "requestAnimationFrame()")}} который анимирует спиннер.</li> + <li>Ссылка на кнопку Start .</li> + <li>Ссылка на параграф результатов.</li> + </ol> + </li> + <li> + <p>Ниже добавьте следующую функцию. Она просто берет два числа и возвращает случайное число между ними. Это понадобится вам позже, чтобы сгенерировать случайный интервал ожидания.</p> + + <pre class="brush: js notranslate">function random(min,max) { + var num = Math.floor(Math.random()*(max-min)) + min; + return num; +}</pre> + </li> + <li> + <p>Затем добавьте функцию draw(), которая анимирует спиннер. Это очень похоже на версию из предыдущего примера просторо счетчика:</p> + + <pre class="brush: js notranslate">function draw(timestamp) { + if(!startTime) { + startTime = timestamp; + } + + rotateCount = (timestamp - startTime) / 3; + + if(rotateCount > 359) { + rotateCount %= 360; + } + + spinner.style.transform = 'rotate(' + rotateCount + 'deg)'; + rAF = requestAnimationFrame(draw); +}</pre> + </li> + <li> + <p>Теперь пришло время настроить начальное состояние приложения при первой загрузке страницы. Добавьте следующие две строки, которые просто скрывают абзац результатов и контейнер счетчика с помощью <code>display: none</code> ;.</p> + + <pre class="brush: js notranslate">result.style.display = 'none'; +spinnerContainer.style.display = 'none';</pre> + </li> + <li> + <p>Затем определите функцию<code> reset ()</code>, которая возвращает приложение в исходное состояние, необходимое для повторного запуска игры после ее завершения. Добавьте в конец кода следующее:</p> + + <pre class="brush: js notranslate">function reset() { + btn.style.display = 'block'; + result.textContent = ''; + result.style.display = 'none'; +}</pre> + </li> + <li> + <p>Хорошо, хватит подготовки! Пришло время сделать игру доступной! Добавьте в свой код следующий блок. Функция <code>start ()</code> вызывает <code>draw ()</code>, чтобы запустить вращение спиннера и отобразить его в пользовательском интерфейсе, скрыть кнопку Start, чтобы вы не могли испортить игру, запустив ее несколько раз одновременно, и запускает вызов <code>setTimeout ()</code>, который выполняется функция <code>setEndgame ()</code> по прошествии случайного интервала от 5 до 10 секунд. Следующий блок также добавляет прослушиватель событий к вашей кнопке для запуска функции <code>start ()</code> при ее нажатии.</p> + + <pre class="brush: js notranslate">btn.addEventListener('click', start); + +function start() { + draw(); + spinnerContainer.style.display = 'block'; + btn.style.display = 'none'; + setTimeout(setEndgame, random(5000,10000)); +}</pre> + + <div class="blockIndicator note"> + <p><strong>Note</strong>: Вы увидете, что этот пример вызывает <code>setTimeout()</code> без сохранения возвращаемого значения. (не <code>let myTimeout = setTimeout(functionName, interval)</code>.) </p> + + <p>Это прекрасно работает, если вам не нужно очищать интервал / тайм-аут в любой момент. Если вы это сделаете, вам нужно будет сохранить возвращенный идентификатор!</p> + </div> + + <p>Конечным результатом предыдущего кода является то, что при нажатии кнопки «Start» отображается спиннер, и игроки вынуждены ждать произвольное количество времени, прежде чем их попросят нажать их кнопку. Эта последняя часть обрабатывается функцией <code>setEndgame ()</code>, которую вы определите позже.</p> + </li> + <li> + <p>Добавьте в свой код следующую функцию:</p> + + <pre class="brush: js notranslate">function setEndgame() { + cancelAnimationFrame(rAF); + spinnerContainer.style.display = 'none'; + result.style.display = 'block'; + result.textContent = 'PLAYERS GO!!'; + + document.addEventListener('keydown', keyHandler); + + function keyHandler(e) { + let isOver = false; + console.log(e.key); + + if (e.key === "a") { + result.textContent = 'Player 1 won!!'; + isOver = true; + } else if (e.key === "l") { + result.textContent = 'Player 2 won!!'; + isOver = true; + } + + if (isOver) { + document.removeEventListener('keydown', keyHandler); + setTimeout(reset, 5000); + } + }; +}</pre> + + <p>Пройдите через это:</p> + + <ol> + <li>Во-первых, отмените анимацию спиннера с помощью {{domxref("window.cancelAnimationFrame", "cancelAnimationFrame()")}} (всегда полезно очистить ненужный процессы), и скройте контейнер счетчика.</li> + <li>Затем, отобразите абзац с результатами и установите для его текстового содержимого значение "PLAYERS GO!!" чтобы сообщить игрокам, что теперь они могут нажать свою кнопку, чтобы победить.</li> + <li>Прикрепите к документу прослушиватель событий <code><a href="/en-US/docs/Web/API/Document/keydown_event">keydown</a></code> . При нажатии любой кнопки запускается функция <code>keyHandler()</code>.</li> + <li>Внутри <code>keyHandler()</code>, код включает обьект события в качестве параметра (представленного <code>e</code>) — его свойство {{domxref("KeyboardEvent.key", "key")}} содержит только что нажатую клавишу, и вы можете использовать это для твета на определенные нажатия клавиш определенными действиями.</li> + <li>Установите для переменной <code>isOver</code> значение false, чтобы мы могли отслеживать, были ли нажаты правильные клавиши, чтобы игрок 1 или 2 выиграл. Мы не хотим, чтобы игра заканчивалась при нажатии неправильной клваиши.</li> + <li>Регистрация <code>e.key</code> в консоли, это полезный способ узнать значение различных клавиш, которые вы нажимаете.</li> + <li>Когда <code>e.key</code> принимает значение "a", отобразить сообщение о том, что Player 1 выиграл, а когда <code>e.key</code> это "l", отобразить сообщение о том, что Player 2 выиграл. (<strong>Note:</strong> Это будет работать только со строчными буквами a и l — если переданы прописные A или L , это считается другими клавишами!) Если была нажата одна из этих клавишь, установите для <code>isOver</code> значение <code>true</code>.</li> + <li>Только еслиf <code>isOver</code> равно <code>true</code>, удалите прослушиватель событий <code>keydown</code> с помощью {{domxref("EventTarget.removeEventListener", "removeEventListener()")}} чтобы после того, как произошло выигрышное нажатие, больше не было возможности ввода с клавиатуры, чтобы испортить финальный результат игры. Вы также используете <code>setTimeout()</code> для вызова <code>reset()</code> через 5 секунд — как обьяснялось ранее, эта функция сбрасывает игру обратно в исходное состояние, чтобы можно было начать новую игру.</li> + </ol> + </li> +</ol> + +<p>Вот и все - вы справились!</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Если вы где то застряли, взгляните на <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/reaction-game.html">наша версия игры</a> (см. также <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/reaction-game.html">исходный код</a> ).</p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>Вот и все — все основы асинхронных циклов и интервалов рассмотрены в статье. Вы найдете эти методы полезными во многих ситуациях, но постарайтесь не злоупотреблять ими! Поскольку они по-прежнему выполняются в основном потоке, тяжелые и интенсивные обратные вызовы (особенно те, которые управляют DOM) могут действительно замедлить страницу, если вы не будете осторожныl.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">Основные понятия асинхронного программирования</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Введение в асинхронный JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Обьединенный асинхронный JavaScript: Таймауты и интервалы</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Сделайте асинхронное программирование легче с async и await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> + +<div id="gtx-trans" style="position: absolute; left: 70px; top: 13746px;"> +<div class="gtx-trans-icon"></div> +</div> diff --git a/files/ru/learn/javascript/building_blocks/build_your_own_function/index.html b/files/ru/learn/javascript/building_blocks/build_your_own_function/index.html new file mode 100644 index 0000000000..fab6711d39 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/build_your_own_function/index.html @@ -0,0 +1,254 @@ +--- +title: Создайте свою функцию +slug: Learn/JavaScript/Building_blocks/Build_your_own_function +translation_of: Learn/JavaScript/Building_blocks/Build_your_own_function +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Эта статья призвана дать практический опыт на основе теоретических знаний приведенныйх в<a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions"> предыдущей статье</a>. Попутно мы также объясним некоторые важные детали работы с функциями.<br> + </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS, <a href="/ru/docs/Learn/JavaScript/Первые_шаги">первые шаги в JavaScript</a>, <a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — блоки кода используемые многократно</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Научить создавать пользовательской функции и объяснить еще несколько полезных деталей.</td> + </tr> + </tbody> +</table> + +<h2 id="Активное_обучение_пострение_функции">Активное обучение: пострение функции</h2> + +<p>Пользовательская функция, которую мы собираемся построить, будет называться <code>displayMessage()</code>. Она отобразит настраиваемое окно сообщения на веб-странице и будет действовать как настраиваемая замена встроенной в браузер функции <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/alert">alert()</a>. Мы видели эту функцию раньше. Введите следующую команду в консоли JavaScript браузера на любой странице:</p> + +<pre class="brush: js">alert('This is a message');</pre> + +<p>Функция <code>alert</code> принимает один аргумент - строку, которая отображается в окне сообщения на веб-странице Попробуйте изменить строку, чтобы изменить сообщение.</p> + +<p>Функция <code>alert</code> ограничена: вы можете изменить текст сообщения, но не получится изменить его стиль, например, цвет, значок или что-то еще. Создадим сообщение, более интересное по стилю.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Этот пример будет работать во всех современных браузерах, но стиль может выглядеть немного смешным в более старых браузерах. Мы рекомендуем вам выполнять это упражнение в современном браузере, таком как Firefox, Opera или Chrome.</p> +</div> + +<h2 id="Основная_функция">Основная функция</h2> + +<p>Для начала давайте соберем основную функцию.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Для согласований имен функций нужно следовать тем же правилам, что и <a href="/ru/docs/Learn/JavaScript/Первые_шаги/Variables#Правила_именования_переменных">правила именования переменных</a>. Отличить имена функций от имен переменных просто: после имен функций указываются круглые скобки, а после имен переменных их нет.</p> +</div> + +<ol> + <li>Откройте файл <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-start.html">function-start.html</a> и скопируйте его себе на компьютер. Код HTML в нем предельно прост: body содержит только одну кнопку. Также здесь представлен базовый CSS для создания настраиваемого окна сообщений и пустой элемент {{htmlelement ("script")}} для размещения нашего JavaScript.</li> + <li>Затем добавьте строку внутри элемента <code><script></code>: + <pre class="brush: js">function displayMessage() { + +}</pre> + Мы начинаем с ключевого слова <code>function</code>, что означает, что мы определяем функцию. За ним следует имя, которое мы хотим дать нашей функции, набор круглых скобок и набор фигурных скобок. Любые параметры, которые мы хотим задать нашей функции, заключают в круглые скобки, а код, который запускается при вызове функции, находится внутри фигурных скобок.</li> + <li>Наконец, добавьте следующий код внутри фигурных скобок: + <pre class="brush: js">var html = document.querySelector('html'); + +var panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel); + +var msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +var closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn); + +closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + </li> +</ol> + +<p>Рассмотрим этот код по строкам (прим. - в оригинале статьи: "bit by bit").</p> + +<p>В первой строке используется функция DOM API под именем {{domxref ("document.querySelector()")}} для выбора элемента {{htmlelement ("html")}}, сохраняющая ссылку на него в переменной <code>html</code>, чтобы позже мы могли с ней что-то сделать:</p> + +<pre class="brush: js">var html = document.querySelector('html');</pre> + +<p>В следующем разделе используется другая функция DOM API, называемая {{domxref ("Document.createElement()")}}, применяется для создания элемента {{htmlelement ("div")}} и сохраняет ссылку на него в переменной, называемой <code>panel</code>. Этот элемент будет внешним контейнером нашего окна сообщений.</p> + +<p>Затем мы используем еще одну функцию DOM API, называемую {{domxref ("Element.setAttribute()")}}, чтобы установить атрибут <code>class</code> на нашей панели со значением <code>msgBox</code>. Это упрощает стилизацию элемента. Если вы посмотрите на CSS на странице, вы увидите, что мы используем селектор класса <code>.msgBox</code> для стилизации окна сообщения и его содержимого.</p> + +<p>Наконец, мы вызываем функцию DOM с именем {{domxref ("Node.appendChild()")}} в переменной <code>html</code>, которую мы сохранили ранее, которая вкладывает один элемент в другой как его дочерний элемент. Указываем панель <code><div></code> как дочерний элемент, который мы хотим вложить внутрь элемента <code><html></code>. То есть, когда мы создаем какой-то элемент, он не просто будет отображаться на странице сам по себе, нам нужно указать, куда его поместить.</p> + +<pre class="brush: js">var panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel);</pre> + +<p>В следующих двух разделах используются те же функции <code>createElement()</code> и <code>appendChild()</code>, которые мы уже видели, чтобы создать два новых элемента: {{htmlelement ("p")}} и {{htmlelement ("button")}}, и вставить их на страницу, как дочерних элементов панели <code><div></code>. Мы используем свойство {{domxref ("Node.textContent")}}, которое представляет текстовое содержимое элемента, для вставки сообщения внутри абзаца и символ «x» внутрь кнопки. Нажатие/активация этой кнопки будет закрывать окно сообщения.</p> + +<pre class="brush: js">var msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +var closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn);</pre> + +<p>В заключении мы используем обработчик событий {{domxref ("GlobalEventHandlers.onclick")}}, чтобы при нажатии кнопки был запущен некоторый код для удаления всей панели со страницы, т.е. для закрытия окна сообщения.</p> + +<p>Вкратце, обработчик <code>onclick</code> — это свойство, доступное для кнопки (или, фактически, для любого элемента страницы), которое можно установить в функцию, чтобы указать, какой код следует запускать при нажатии кнопки. Вы узнаете об этом больше в нашей статье о последующих событиях. Мы делаем обработчик <code>onclick</code> равным анонимной функции, которая содержит код, запускаемый при нажатии кнопки. Строка внутри функции использует функцию {{domxref ("Node.removeChild()")}} DOM API, чтобы указать, что мы хотим удалить определенный дочерний элемент внутри HTML — в данном случае панель <code><div></code>.</p> + +<pre class="brush: js">closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + +<p>В принципе, весь этот блок кода генерирует блок HTML, который выглядит так и вставляет его на страницу:</p> + +<pre class="brush: html"><div class="msgBox"> + <p>This is a message box</p> + <button>x</button> +</div></pre> + +<p>Вам не обязательно запоминать сейчас, как работает каждый элемент во всем этом коде. Основная задача — понять структуру и использование функции, при этом мы хотели показать что-то интересное для этого примера.</p> + +<h2 id="Вызов_функции">Вызов функции</h2> + +<p>Теперь у вас есть определение функции, написанное в вашем элементе <code><script></code>, но оно ничего не будет делать в том виде, в каком оно есть.</p> + +<ol> + <li>Попробуйте написать следующую строку под своей функцией, чтобы вызвать ее: + <pre class="brush: js">displayMessage();</pre> + Эта строка вызывает функцию, немедленно запуская ее. Когда вы сохраните код и перезагрузите его в браузере, вы увидите, что небольшое окно сообщения появляется сразу и только один раз.</li> + <li> + <p>Теперь откройте инструменты разработчика браузера на странице примера, перейдите в консоль JavaScript и снова введите эту строку. Вы увидите, что окно появится снова! Теперь у нас есть функция многократного использования, которую мы можем вызвать в любое время.</p> + + <p>Но мы, вероятно, хотим, чтобы оно появлялось в ответ на действия пользователя и системы. В реальном приложении такое окно сообщения, вероятно, будет вызвано в ответ на доступность новых данных или, если произошла ошибка, или, например, если пользователь пытаюется удалить свой профиль («вы уверены в этом?»), или если пользователь добавляет новый контакт и операция успешно завершена и т. д.</p> + + <p>В этой демонстрации мы получим окно сообщения, когда пользователь нажимает кнопку.</p> + </li> + <li>Удалите предыдущую добавленную строку.</li> + <li>Затем мы выберем кнопку и сохраним ссылку на нее в переменной. Добавьте следующую строку в свой код, над определением функции: + <pre class="brush: js">var btn = document.querySelector('button');</pre> + </li> + <li>Наконец, добавьте следующую строку ниже предыдущей: + <pre class="brush: js">btn.onclick = displayMessage;</pre> + Аналогично нашей строке <code>closeBtn.onclick...</code> внутри функции здесь мы вызываем некоторый код в ответ на нажатие кнопки. Но в этом случае вместо вызова анонимной функции, содержащей некоторый код, мы вызываем имя нашей функции напрямую.</li> + <li>Сохраните и обновите страницу. Теперь вы должны увидеть окно с сообщением, когда вы нажимаете кнопку.</li> +</ol> + +<p>Возможно, вам интересно, почему мы не включили круглые скобки после имени функции. Это связано с тем, что нам нужно не сразу вызвать функцию, а только после нажатия кнопки. Если вы попытаетесь изменить строку на</p> + +<pre class="brush: js">btn.onclick = displayMessage();</pre> + +<p>сохраните и перезагрузите страницу, вы увидите, что окно сообщения появляется без нажатия кнопки! Скобки в этом контексте иногда называют «оператором вызова функции». Вы используете их только в том случае, если хотите немедленно запустить функцию в текущей области. В этом же отношении код внутри анонимной функции не запускается сразу, так как он находится внутри области функций.</p> + +<p>Если вы пробовали последний эксперимент, перед тем, как продолжить, обязательно отмените последнее изменение.</p> + +<h2 id="Улучшение_функции_с_параметрами">Улучшение функции с параметрами</h2> + +<p>В нынешнем виде функция по-прежнему не очень полезна — мы не хотим показывать одно и то же сообщение по умолчанию каждый раз. Давайте улучшим нашу функцию, добавив некоторые параметры, позволяющие нам называть ее различными вариантами.</p> + +<ol> + <li> + <p>Прежде всего, обновите первую строку функции:</p> + + <pre class="brush: js">function displayMessage() {</pre> + + <p>к этому:</p> + + <pre class="brush: js">function displayMessage(msgText, msgType) {</pre> + Теперь, когда мы вызываем функцию, мы можем предоставить два значения переменных в круглых скобках, чтобы указать сообщение для отображения в окне сообщения, а также тип сообщения.</li> + <li>Чтобы использовать первый параметр, обновите следующую строку внутри своей функции: + <pre class="brush: js">msg.textContent = 'This is a message box';</pre> + + <p>к этому:</p> + + <pre class="brush: js">msg.textContent = msgText;</pre> + </li> + <li>И последнее, но не менее важное: теперь вам нужно обновить вызов функции, чтобы включить в него обновленный текст сообщения. Измените следующую строку: + <pre class="brush: js">btn.onclick = displayMessage;</pre> + + <p>к этому блоку:</p> + + <pre class="brush: js">btn.onclick = function() { + displayMessage('Woo, this is a different message!'); +};</pre> + Если мы хотим указать параметры в круглых скобках для вызываемой нами функции, то мы не можем назвать ее напрямую, нам нужно поместить ее в анонимную функцию, чтобы она не находилась непосредственно в области видимости и, следовательно, не вызывалась немедленно. Теперь она не будет вызываться до нажатия кнопки.</li> + <li>Перезагрузите и протестируйте код еще раз, и вы увидите, что он по-прежнему работает, только теперь вы также можете изменять сообщение внутри параметра, чтобы отображать разные сообщения в окне.</li> +</ol> + +<h3 id="Более_сложный_параметр">Более сложный параметр</h3> + +<p>Переход к следующему параметру. Это потребует немного больше работы. Установим его так, чтобы в зависимости от того, какой параметр <code>msgType</code> установлен, функция отображала другой значок и другой цвет фона.</p> + +<ol> + <li>Для начала, загрузите значки, необходимые для этого упражнения (<a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/warning.png">warning</a> и <a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/chat.png">chat</a> [тут черные иконки на черном фоне... тролли на GitHub]) из GitHub. Сохраните их в новой папке <code>icons</code> в том же месте, что и ваш HTML-файл. + + <div class="note"><strong>Примечание</strong>: иконки <a href="https://www.iconfinder.com/icons/1031466/alarm_alert_error_warning_icon">warning</a> и <a href="https://www.iconfinder.com/icons/1031441/chat_message_text_icon">chat</a> были найдены на <a href="https://www.iconfinder.com/" rel="noopener">iconfinder.com</a>, и разработаны <a href="https://www.iconfinder.com/nazarr">Nazarrudin Ansyari</a>. Спасибо! (Фактические страницы значков были перемещены или удалены.) </div> + </li> + <li>Затем найдите CSS внутри вашего HTML-файла. Мы сделаем несколько изменений, чтобы освободить место для иконок. Во-первых, обновите ширину <code>.msgBox</code>: + <pre class="brush: css">width: 200px;</pre> + + <p>измените на:</p> + + <pre class="brush: css">width: 242px;</pre> + </li> + <li>Затем добавьте следующие строки в правило <code>.msgBox p { ... }</code> : + <pre class="brush: css">padding-left: 82px; +background-position: 25px center; +background-repeat: no-repeat;</pre> + </li> + <li>Теперь нам нужно добавить код в нашу функцию <code>displayMessage()</code>для обработки отображений значков. Добавьте следующий блок чуть выше закрывающей фигурной скобки "<code>}</code>" вашей функции: + <pre class="brush: js">if (msgType === 'warning') { + msg.style.backgroundImage = 'url(icons/warning.png)'; + panel.style.backgroundColor = 'red'; +} else if (msgType === 'chat') { + msg.style.backgroundImage = 'url(icons/chat.png)'; + panel.style.backgroundColor = 'aqua'; +} else { + msg.style.paddingLeft = '20px'; +}</pre> + Здесь, если параметр <code>msgType</code> установлен как <code>'warning'</code>, отображается значок предупреждения, а цвет фона панели устанавливается красным. Если для него установлено значение<code>'chat'</code>, отображается значок чата, а цвет фона панели становится голубым. Если параметр <code>msgType</code> не задан вообще (или задано что-то другое), тогда вступает в действие <code>else {...}</code>, а абзацу просто присваиваются заданные по умолчанию отступы, нет никакого значка, при этом не задается цвет фона окна сообщения. Это обеспечивает состояние по умолчанию, если не указан параметр <code>msgType</code>, что означает, что это необязательный параметр!</li> + <li>Давайте протестируем нашу обновленную функцию, попробуем обновить вызов displayMessage () из этого: + <pre class="brush: js">displayMessage('Woo, this is a different message!');</pre> + + <p>к одному из них:</p> + + <pre class="brush: js">displayMessage('Your inbox is almost full — delete some mails', 'warning'); +displayMessage('Brian: Hi there, how are you today?','chat');</pre> + Вот, насколько полезной становится наша (теперь не очень) маленькая функция.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Если у вас возникли проблемы с запуском примера, не стесняйтесь проверять свой код на готовой версии <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html">GitHub</a> (см. также <a href="https://mdn.github.io/learning-area/javascript/building-blocks/functions/function-stage-4.html">в режиме реального времени</a>) или обратитесь к нам за помощью.</p> +</div> + +<h2 id="Вывод">Вывод</h2> + +<p>В этой статье мы познакомились со всем процессом создания практической пользовательской функции, которую с небольшими доработками можно перенести в реальный проект. В следующей статье мы рассмотрим еще одну важную концепцию — возвращаемые значения функций.</p> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</p> + +<p> </p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/conditionals">Принятие решений в Вашем коде — условные конструкции</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">Зацикливание кода</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — Переиспользуемые блоки кода</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создайте свою собственную функцию</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Return_values">Возвращаемое значение функции</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/События">Введение в события</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Image_gallery">Создание галереи</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/javascript/building_blocks/conditionals/index.html b/files/ru/learn/javascript/building_blocks/conditionals/index.html new file mode 100644 index 0000000000..970c31d43b --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/conditionals/index.html @@ -0,0 +1,746 @@ +--- +title: Принятие решений в Вашем коде — условные конструкции +slug: Learn/JavaScript/Building_blocks/conditionals +tags: + - JavaScript + - Switch + - else + - if + - Для начинающих + - Операторы + - Статья +translation_of: Learn/JavaScript/Building_blocks/conditionals +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Во многих языках программирования код должен иметь возможность принимать решения на основе введеных пользователем данных. Например, в игре, если у пользователя осталось 0 жизней, то игра завершается. В приложении о погоде утром отображается восход солнца, а вечером звезды и луна. В этой статье мы рассмотрим как в JavaScript работают так называемые "условия".</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимое условие:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять принципы использования операторов условий в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Выбор_одного_условия!..">Выбор одного условия!..</h2> + +<p>Люди (и животные) принимают какие-либо решения всю жизнь, от малозначимых ("стоит ли мне съесть одну печеньку или две?") до жизнеопределяющих ("стоит ли мне остаться дома и работать на ферме отца или переехать в другую страну и изучать астрофизику?")</p> + +<p>Операторы условия в JavaScript позволяют нам указать разного рода действия в зависимости от выбранного пользователем или системой ответа (например одна печенька или две) и связать его с действием (результатом), например, результатом "съесть одну печеньку" будет "все еще буду чуствовать себя голодным", а результатом "съесть две печеньки" будет "буду чуствовать себя сытым, но мама меня наругает за то, что я съел все сладости". </p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13703/cookie-choice-small.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="Оператор_if_..._else">Оператор if ... else</h2> + +<p>Давайте глянем на наиболее распространенный тип условного оператора, который вы будете использовать в JavaScript — <code><a href="/ru/docs/Web/JavaScript/Reference/Statements/if...else">if ... else</a></code><a href="/ru/docs/Web/JavaScript/Reference/Statements/if...else"> оператор</a>.</p> + +<h3 id="Базовый_if_..._else_синтаксис">Базовый if ... else синтаксис</h3> + +<p>Базовый <code>if...else</code> синтаксис выглядит как {{glossary("pseudocode")}}:</p> + +<pre class="notranslate">if (condition) { + code to run if condition is true +} else { + run some other code instead +}</pre> + +<p>Что мы имеем:</p> + +<ol> + <li>Ключевое слово <code>if</code> расположено перед круглыми скобками.</li> + <li>Условие для проверки (condition), расположено внутри круглых скобок (например "это значение больше другого значения?", или "это значение существует?"). Это условие использует операторы сравнения (<a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">comparison operators</a>), которые мы изучим позже, и возвратит нам <code>true</code> или <code>false</code>.</li> + <li>Внутри скобок { } расположен код, который будет выполняться только в том случае, если условие (condition) верно (<code>true)</code>.</li> + <li>Ключевое слово <code>else (иначе)</code>.</li> + <li>Еще скобки { }, код внутри которых выполнится, только если условие не верно (не <code>true)</code>.</li> +</ol> + +<p>Этот код довольно читабелен — он говорит "<strong>if (если)</strong> <strong>condition (условие) </strong>возвращает <code>true (истина)</code>, запусти код A, <strong>else (иначе) </strong>запусти B"</p> + +<p>Стоит заметить, что <code>else</code> и второй блок скобок { } не обязателен — следующий код так же будет работать:</p> + +<pre class="notranslate">if (condition) { + код, который должен выполнить, если условие истина +} + +какой-то другой код</pre> + +<p>Тем не менее, следует быть осторожным — в случае, если код внутри вторых скобок { } не контролируется условием, то этот код будет выполняться <strong>всегда</strong>. Это не плохо, просто вы должны помнить об этом, чаще вы хотите запустить один кусок кода <em>или </em>другой, но не оба.</p> + +<p>И, наконец, иногда вы можете встретить код <code>if...else</code> без фигурных скобок в сокращенной форме:</p> + +<pre class="notranslate">if (condition) code to run if condition is true +else run some other code instead</pre> + +<p>Это абсолютно рабочий код, но он менее читаем, лучше использовать фигурные скобки, новые строки и отступы.</p> + +<h3 id="Реальный_пример">Реальный пример</h3> + +<p>Чтобы лучше понять синтаксис, давайте рассмотрим реальный пример. Представьте, что мать или отец попросили помочь с работой по дому своего ребенка. Родитель может сказать: "Если ты поможешь мне с покупками, то я дам тебе дополнительные деньги на карманные расходы, которые ты сможешь потратить на игрушку, какую захочешь". В JavaScript, мы можем представить это так: </p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone === true) { + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<p>В этом коде, как показано, всегда будет <code>shoppingDone</code> равный <code>false</code>, что означает разочарование для нашего бедного ребенка. Мы должны предоставить механизм для родителя, чтобы установить для переменной <code>shoppingDone</code> значение <code>true</code> , если ребенок помог с покупками.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете увидеть больше в <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/allowance-updater.html">полной версии этого примера на GitHub</a> (также посмотреть как он <a href="http://mdn.github.io/learning-area/javascript/building-blocks/allowance-updater.html">работает вживую</a>.)</p> +</div> + +<h3 id="else_if">else if</h3> + +<p>В предыдущем примере предоставлено два выбора, или результата — но что, если мы хотим больше, чем два?</p> + +<p>Существует способ привязать дополнительные варианты/результаты к вашему <code>if...else</code> — использовать<code>else if</code>. Для каждого дополнительного выбора требуется дополнительный блок, который нужно расположить между <code>if() { ... }</code> и <code>else { ... }</code> — проверьте следующий более сложный пример, который может быть частью простого приложения прогноза погоды:</p> + +<pre class="brush: html notranslate"><label for="weather">Выберите тип погоды сегодня: </label> +<select id="weather"> + <option value="">--Сделайте выбор--</option> + <option value="sunny">Солнечно</option> + <option value="rainy">Дождливо</option> + <option value="snowing">Снежно</option> + <option value="overcast">Облачно</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + +function setWeather() { + var choice = select.value; + + if (choice === 'sunny') { + para.textContent = 'Сегодня хорошо и солнечно. Носите шорты! Идите на пляж, или в парк, и купите мороженое.'; + } else if (choice === 'rainy') { + para.textContent = 'Дождь падает за окном; возьмите плащ и зонт, и не находитесь слишком долго на улице.'; + } else if (choice === 'snowing') { + para.textContent = 'Снег падает - морозно! Лучше всего посидеть с чашкой горячего шоколада или слепить снеговика.'; + } else if (choice === 'overcast') { + para.textContent = 'Дождя нет, но небо серое и мрачное; он все может измениться в любую минуту, поэтому на всякий случай возьмите дождевик.'; + } else { + para.textContent = ''; + } +} + +</pre> + +<p>{{ EmbedLiveSample('else_if', '100%', 100) }}</p> + +<ol> + <li>Здесь у нас есть элемент HTML {{htmlelement("select")}} который позволяет нам выбирать разные варианты погоды и простой абзац.</li> + <li>В JavaScript, мы создаем ссылки на элементы {{htmlelement("select")}} и {{htmlelement("p")}}, и добавляем обработчик события для элемента <code><select></code> , чтобы при изменении его значения, запускалась функция <code>setWeather()</code>.</li> + <li>Когда функция будет запущена, первоначально мы определим значение переменной <code>choice</code>, которая равна выбранному значению в элементе <code><select></code>. Затем мы используем условный оператор для отображения текста внутри абзаца в зависимости от того, какое значение у переменной <code>choice</code>. Обратите внимание, как все условия проверяются в <code>else if() {...}</code> блоках, за исключением первого, который использует <code>if() {...}</code>блок.</li> + <li>Последний выбор, внутри <code>else {...}</code> блока, в основном является «последним средством» — код внутри него будет запущен, если ни одно из условий не будет <code>true</code>. В этом случае он служит для удаления текста из абзаца, если ничего не выбрано, например, если пользователь решает повторно выбрать опцию "--Сделайте выбор--" которая указана в начале.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-else-if.html">найти этот пример на GitHub</a> (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-else-if.html">увидеть как он работает</a>)</p> +</div> + +<h3 id="Примечание_об_операторах_сравнения">Примечание об операторах сравнения</h3> + +<p>Операторы сравнения используют для проверки условий внутри наших условных операторов. Сначала мы посмотрели на операторы сравнения в нашей статье <a href="/ru/docs/Learn/JavaScript/Первые_шаги/Math#Comparison_operators">Базовая математика в JavaScript — цифры и операторы</a> . Наш выбор это:</p> + +<ul> + <li><code>===</code> и <code>!==</code> — проверяет одно значение идентично или не идентично другому.</li> + <li><code><</code> и <code>></code> — проверяет одно значение меньше или больше, чем другое.</li> + <li><code><=</code> и <code>>=</code> — проверяет одно значение меньше или равно, либо больше или равно другому.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Просмотрите материал по предыдущей ссылке, если вы хотите освежить свою память.</p> +</div> + +<p>Мы хотели бы особо обратить внимание на проверку булевых значений (<code>true</code>/<code>false</code>), и общий шаблон, который вы будете встречать снова и снова. Любое значение, которое не есть <code>false</code>, <code>undefined</code>, <code>null</code>, <code>0</code>, <code>NaN</code>, или пустая строка (<code>''</code>) фактически возвращает <code>true</code> при тестировании как условного оператора. Поэтому вы можете просто использовать имя собственной переменной, чтобы проверить, равна ли она <code>true</code>, или существует (т. е. переменная не равна undefined). Например:</p> + +<pre class="brush: js notranslate">var cheese = 'Cheddar'; + +if (cheese) { + console.log('Ура! Есть сыр для приготовления бутерброда.'); +} else { + console.log('Сегодня нет сыра для бутерброда.'); +}</pre> + +<p>И, возвращаясь к нашему предыдущему примеру о ребенке, выполняющем поручение своего родителя, вы можете это записать так:</p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone) { // не нужно явно указывать '=== true' + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<h3 id="Вложенность_if_..._else">Вложенность if ... else</h3> + +<p>Вполне нормально использовать один условный оператор <code>if...else</code> внутри другого — вложить их. Например, мы могли бы обновить наше приложение прогноза погоды, чтобы показать еще один набор вариантов в зависимости от температуры:</p> + +<pre class="brush: js notranslate">if (choice === 'sunny') { + if (temperature < 86) { + para.textContent = 'Сейчас ' + temperature + ' градусов по фаренгейту — хорошо и солнечно. Идите на пляж, или в парк, и купите мороженое.'; + } else if (temperature >= 86) { + para.textContent = 'Сейчас ' + temperature + ' градусов по фаренгейту — Жара! Если вы хотите выйти на улицу, обязательно используйте солнцезащитный крем.'; + } +}</pre> + +<p>Несмотря на то, что весь код работает вместе, каждый условный оператор <code>if...else</code> работает полностью отдельно от другого.</p> + +<h3 id="Логические_операторы_И_ИЛИ_и_НЕ">Логические операторы: И, ИЛИ и НЕ</h3> + +<p>Если Вы хотите проверить несколько условий без записи вложенных <code>if...else</code> условий, <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators">логические операторы</a> помогут Вам. При использовании в условиях, первые два оператора делают следующее:</p> + +<ul> + <li><code>&&</code> — И; позволяет объединить два или более выражения так, что каждое из них отдельно должно иметь значение <code>true</code> , чтобы в итоге общее выражение имело значение <code>true</code>.</li> + <li><code>||</code> — ИЛИ; позволяет объединить два или более выражения так, что одно или несколько из них должно иметь значение <code>true</code> , чтобы в итоге общее выражение имело значение<code>true</code>.</li> +</ul> + +<p>Чтобы дать вам пример оператора И, предыдущий фрагмент кода можно переписать так:</p> + +<pre class="brush: js notranslate">if (choice === 'sunny' && temperature < 86) { + para.textContent = 'Сейчас ' + temperature + ' градусов по фаренгейту — хорошо и солнечно. Идите на пляж, или в парк, и купите мороженое.'; +} else if (choice === 'sunny' && temperature >= 86) { + para.textContent = 'Сейчас ' + temperature + ' градусов по фаренгейту — Жара! Если вы хотите выйти на улицу, обязательно используйте солнцезащитный крем.'; +}</pre> + +<p>Так, для примера, первый блок кода выполнится только в том случае, если <code>choice === 'sunny'</code> <em>и</em><code>temperature < 86</code> вернут значение <code>true</code>.</p> + +<p>Давайте посмотрим на быстрый пример оператора ИЛИ:</p> + +<pre class="brush: js notranslate">if (iceCreamVanOutside || houseStatus === 'в огне') { + //если подъехал фургон с мороженым или дом горит + console.log('Вы должны быстро покинуть дом.'); +} else { + console.log('Вероятно, можно в нем оставаться.'); +}</pre> + +<p>Последний тип логического оператора НЕ, выраженный <code>!</code> оператором, можно использовать для отрицания выражения. Давайте объединим его с ИЛИ в приведенном выше примере:</p> + +<pre class="brush: js notranslate">if (!(iceCreamVanOutside || houseStatus === 'on fire')) { + console.log('Вероятно, можно в нем оставаться.'); +} else { + console.log('Вы должны быстро покинуть дом.'); +}</pre> + +<p>В этом фрагменте, если условие ИЛИ возвращает <code>true</code>, оператор НЕ будет отрицать это и выражение вернет <code>false</code>.</p> + +<p>Можно сочетать любое количество логических операторов, в любой последовательности и в любой комбинации. В следующем примере код в блоке будет выполняться только в том случае, если оба условия с ИЛИ возвращают true, а следовательно, и оператор И возвращает true:</p> + +<pre class="brush: js notranslate">if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === 'Steve')) { + // код выполняется +}</pre> + +<p>Распространенной ошибкой при использовании логического оператора ИЛИ в условном выражении является указание переменной, значение которой нужно проверить со списком возможных значений этой переменной, разделенных операторами <code>||</code> (ИЛИ). Например.</p> + +<pre class="example-bad brush: js notranslate">if (x === 5 || 7 || 10 || 20) { + // выполнить код +}</pre> + +<p>В данном примере условие в <code>if(...)</code> всегда будет оцениваться как true, поскольку 7 (или любое другое ненулевое значение) всегда будет оцениваться как true. Фактически, это условие гласит «если х равен 5, или 7 является true». Но нам требуется совсем не это. Чтобы достичь нужной цели, придется выполнять полноценную проверку после каждого оператора ИЛИ:</p> + +<pre class="brush: js notranslate">if (x === 5 || x === 7 || x === 10 ||x === 20) { + // выполнить код +}</pre> + +<h2 id="Оператор_switch">Оператор switch</h2> + +<p>Выражения <code>if...else</code> отлично справляются с добавлением условного кода, однако они не лишены недостатков. Они хорошо подходят для ситуации, когда имеется всего пара вариантов развития событий, каждый из которых имеет блок с приемлемым количеством кода, а также в случаях, когда условие является довольно сложным и включает несколько логических операторов. Если же нам требуется всего лишь задать переменную для определенного выбранного значения или напечатать конкретную фразу при определенном условии, изученный нами синтаксис может оказаться довольно громоздким, особенно если имеется большое количество вариантов выбора.</p> + +<p>В этом случае нам поможет <a href="/en-US/docs/Web/JavaScript/Reference/Statements/switch">оператор <code>switch</code> </a>– он принимает одно единственное выражение или значение, а затем просматривает ряд вариантов, пока не найдут вариант, соответствующий этому значению, после чего выполняет код, назначенный этому варианту. Вот пример использования этого оператора:</p> + +<pre class="notranslate">switch (выражение) { + case choice1: + выполнить этот код + break; + + case choice2: + выполнить этот код, а не предыдущий + break; + + // вариантов может быть любое количество + + default: + а вообще-то, выполнить только этот код +}</pre> + +<p>Что мы имеем:</p> + +<ol> + <li>Ключевое слово <code>switch</code>, за которым следует пара круглых скобок.</li> + <li>В скобках приводится выражение или значение.</li> + <li>Ключевое слово <code>case</code>, за которым следует вариант выбора (именно он проверяется на соответствие выражению или значению) и двоеточие.</li> + <li>Код, который будет выполняться, если вариант совпадает с выражением.</li> + <li>Оператор <code>break</code>, за которым следует точка с запятой. Если вариант совпал с выражением или значением, браузер закончит выполнять блок кода, дойдя до оператора <code>break</code>, и перейдет к выполнению кода, расположенного после оператора switch.</li> + <li>Вариантов выбора (пункты 3–5) может быть сколь угодно много.</li> + <li>Ключевое слово <code>default</code> используется точно также, как любой другой вариант выбора (пункты 3–5) за тем исключением, что после <code>default</code> нет других вариантов выбора, поэтому инструкция <code>break</code> не требуется, никакого кода дальше нет. Это вариант выбора по умолчанию, выбираемый, если ни один из других вариантов не совпал с выражением.</li> +</ol> + +<div class="note"> +<p><strong>Примечание.</strong> Вариант выбора <code>default</code> может быть пропущен, если выражение гарантированно совпадет с одним из вариантов выбора. В противном случае вариант <code>default</code> необходим.</p> +</div> + +<h3 id="Пример_оператора_switch">Пример оператора switch</h3> + +<p>Давайте рассмотрим реальный пример — перепишем наше приложение прогноза погоды с использованием оператора switch:</p> + +<pre class="brush: html notranslate"><label for="weather">Выберите тип погоды сегодня: </label> +<select id="weather"> + <option value="">--Сделайте выбор--</option> + <option value="sunny">Солнечно</option> + <option value="rainy">Дождливо</option> + <option value="snowing">Снежно</option> + <option value="overcast">Облачно</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + + +function setWeather() { + var choice = select.value; + + switch (choice) { + case 'sunny': + para.textContent = 'Сегодня хорошо и солнечно. Наденьте шорты! Идите на пляж или в парк, и купите мороженое.'; + break; + case 'rainy': + para.textContent = 'На улице дождь. Возьмите плащ и зонт, и не гуляйте слишком долго'; + break; + case 'snowing': + para.textContent = 'Идет снег - морозно! Лучше всего посидеть с чашкой горячего шоколада или слепить снеговика.'; + break; + case 'overcast': + para.textContent = 'Дождя нет, но небо серое и мрачное; он все может измениться в любую минуту, поэтому на всякий случай возьмите дождевик.'; + break; + default: + para.textContent = ''; + } +}</pre> + +<p>{{ EmbedLiveSample('Пример_оператора_switch', '100%', 100) }}</p> + +<div class="note"> +<p><strong>Note</strong>: Вы можете <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-switch.html">найти этот пример на GitHub</a> (также увидеть <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-switch.html">как он работает</a>.)</p> +</div> + +<h2 id="Тернарный_оператор">Тернарный оператор</h2> + +<p>Это последний теоретический раздел данной статьи и мы перейдем к практическим упражнениям. <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Тернарный или условный оператор</a> имеет простой синтаксис: он проверяет условие и возвращает одно значение или выражение, если условие является <code>true</code>, и другое значение/выражение, если условие является <code>false</code>. Часто это очень удобная альтернатива блоку <code>if...else</code>, позволяющая затрачивать меньшие усилия на написание кода, когда имеется всего лишь два варианта, выбираемых на основе условия <code>true</code>/<code>false</code>. Общая схема оператора:</p> + +<pre class="notranslate">( условие) ? выполнить этот код : выполнить этот код вместо первого</pre> + +<p>Приведем простой пример:</p> + +<pre class="brush: js notranslate">var greeting = ( isBirthday ) ? 'С днем рождения, г-н Кузнецов! Хорошо Вам повеселиться!' : 'Доброе утро, г-н Кузнецов.';</pre> + +<p>У нас есть переменная <code>isBirthday</code> , если она <code>true</code>, мы отправляем посетителю поздравление с днем рождения; если нет – выдаем стандартное приветствие.</p> + +<h3 id="Пример_тернарного_оператора">Пример тернарного оператора</h3> + +<p>При использовании тернарного оператора не обязательно ограничиваться лишь значениями переменной, можно выполнять функции или строки кода; все, что угодно. В следующем примере показано простое средство выбора темы, задающее внешний вид веб-сайта с помощью тернарного оператора.</p> + +<pre class="brush: html notranslate"><label for="theme">Выберите тему: </label> +<select id="theme"> + <option value="white">Белая</option> + <option value="black">Черная</option> +</select> + +<h1>Это мой веб-сайт</h1></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var html = document.querySelector('html'); +document.body.style.padding = '10px'; + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +} + +select.onchange = function() { + ( select.value === 'black' ) ? update('black','white') : update('white','black'); +} +</pre> + +<p>{{ EmbedLiveSample('Пример_тернарного_оператора', '100%', 300) }}</p> + +<p>Мы используем элемент {{htmlelement('select')}} для выбора темы (черная или белая), а также простой {{htmlelement('h1')}} для отображения заголовка веб-сайта. Кроме того, у нас есть функция <code>update()</code>, принимающая в качестве параметров (входных данных) два цвета. В качестве фона используется первый переданный цвет, а в качестве цвета текста – второй переданный цвет.</p> + +<p>Наконец, у нас есть слушатель событий <a href="/en-US/docs/Web/API/GlobalEventHandlers/onchange">onchange</a> , использующийся для запуска функции, содержащей тернарный оператор. Сначала она проверяет условие — <code>select.value === 'black'</code>. Если возвращается <code>true</code>, мы запускаем функцию <code>update()</code> с параметрами черного и белого, в результате чего получаем черный цвет фона и белый цвет текста. Если возвращается <code>false</code>, мы запускаем функцию <code>update()</code> с параметрами белого и черного, в результате чего цвета веб-сайта меняются на противоположные.</p> + +<div class="note"> +<p><strong>Note</strong>: Вы можете <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-ternary.html">найти этот пример на GitHub</a> (также увидеть <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-ternary.html">как он работает</a>.)</p> +</div> + +<h2 id="Практическое_упражнение_простой_календарь">Практическое упражнение: простой календарь</h2> + +<p>В данном примере вы поможете нам закончить простое приложение календаря. Код включает:</p> + +<ul> + <li>Элемент {{htmlelement("select")}}, позволяющий пользователю выбирать разные месяцы.</li> + <li>Обработчик событий <code>onchange</code> для обнаружения изменения значения, выбранного в меню <code><select></code>.</li> + <li>Функция <code>createCalendar()</code> , рисующая календарь и отображающая правильный месяц в элементе {{htmlelement("h1")}}.</li> +</ul> + +<p>Вы должны написать условную конструкцию в функции обработчика <code>onchange</code> , сразу после комментария <code>// ДОБАВЬТЕ СЮДА УСЛОВНОЕ ВЫРАЖЕНИЕ</code>. Конструкция должна:</p> + +<ol> + <li>Проверить выбранный месяц (хранящийся в переменной <code>choice</code>. Это будет значение элемента <code><select></code> после изменения значения, например, "Январь".)</li> + <li>Задать переменную, скажем, <code>days</code>, равную количеству дней в выбранном месяце. Для этого нужно будет проверить количество дней в каждом месяце. Високосный год можно не учитывать.</li> +</ol> + +<p>Советы:</p> + +<ul> + <li>Советуем использовать логический оператор OR для группировки нескольких месяцев в рамках одного условия; многие месяцы имеют одинаковое количество дней.</li> + <li>Подумайте, какое количество дней в месяце встречается чаще всего и используйте его в качестве варианта по умолчанию.</li> +</ul> + +<p>Если допустили ошибку, используйте кнопку «Сброс», чтобы вернуться к исходному виду примера. Если у вас совсем ничего не получается, нажмите «Показать решение».</p> + +<div class="blockIndicator note"> +<p>В HTML коде внутри <code><select></code> названия месяцев <code>value=""</code> введены на русском языке. Соответственно ссылки на них из вашего скрипта так же на русском. Не забываем про синтаксис. (прим. - <a href="/ru/profiles/ConstantineZz">ConstantineZz</a>)</p> +</div> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 500px;overflow: auto;"> +<label for="month">Выберите месяц: </label> +<select id="month"> +<option value="Январь">Январь</option> +<option value="Февраль">Февраль</option> +<option value="Март">Март</option> +<option value="Апрель">Апрель</option> +<option value="Май">Май</option> +<option value="Июнь">Июнь</option> +<option value="Июль">Июль</option> +<option value="Август">Август</option> +<option value="Сентябрь">Сентябрь</option> +<option value="Октябрь">Октябрь</option> +<option value="Ноябрь">Ноябрь</option> +<option value="Декабрь">Декабрь</option> +</select> +<h1></h1> +<ul></ul> </div> + +<h2>Editable code</h2> + +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="playable-code" style="height: 400px;width: 95%"> +var select = document.querySelector('select'); +var list = document.querySelector('ul'); +var h1 = document.querySelector('h1'); + +select.onchange = function() { + var choice = select.value; + + // <code>ДОБАВЬТЕ СЮДА УСЛОВНОЕ ВЫРАЖЕНИЕ</code> + + createCalendar(days, choice); +} + +function createCalendar(days, choice) { + list.innerHTML = ''; + h1.textContent = choice; + for (var i = 1; i <= days; i++) { + var listItem = document.createElement('li'); + listItem.textContent = i; + list.appendChild(listItem); + } +} + +createCalendar(31,'Январь'); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сброс"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">.output * { + box-sizing: border-box; +} + +.output ul { + padding-left: 0; +} + +.output li { + display: block; + float: left; + width: 25%; + border: 2px solid white; + padding: 5px; + height: 40px; + background-color: #4A2DB6; + color: white; +} + +html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Скрыть решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var jsSolution = 'var select = document.querySelector(\'select\');\nvar list = document.querySelector(\'ul\');\nvar h1 = document.querySelector(\'h1\');\n\nselect.onchange = function() {\n var choice = select.value;\n var days = 31;\n if(choice === \'Февраль\') {\n days = 28;\n } else if(choice === \'Апрель\' || choice === \'Июнь\' || choice === \'Сентябрь\'|| choice === \'Ноябрь\') {\n days = 30;\n }\n\n createCalendar(days, choice);\n}\n\nfunction createCalendar(days, choice) {\n list.innerHTML = \'\';\n h1.textContent = choice;\n for(var i = 1; i <= days; i++) {\n var listItem = document.createElement(\'li\');\n listItem.textContent = i;\n list.appendChild(listItem);\n }\n }\n\ncreateCalendar(31,\'Январь\');'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 1110) }}</p> + +<h2 id="Практическое_упражнение_расширяем_выбор_цветов">Практическое упражнение: расширяем выбор цветов</h2> + +<p>В данном примере вы будете использовать пример тернарного оператора, который мы рассматривали ранее, и превратите тернарный оператор в инструкцию switch, что позволит увеличить количество вариантов выбора для простого веб-сайта. Посмотрите на {{htmlelement("select")}} — на этот раз он включает не два, а целых пять вариантов тем. Нужно добавить инструкцию switch сразу под комментарием <code>// ДОБАВЬТЕ ИНСТРУКЦИЮ SWITCH</code>:</p> + +<ul> + <li>Она должна принимать переменную <code>choice</code> в качестве входного выражения.</li> + <li>Каждый элемент case должен содержать вариант выбора, соответствующий одному из доступных для выбора значений: белая, черная, лиловая, желтая или психоделическая тема.</li> + <li>В блоке каждого элемента case необходимо вызывать функцию <code>update()</code>, которой передается два цвета: первый – это цвет фона, а второй – цвет текста. Помните, что значения цветов – это строковые значения, поэтому их нужно заключать в кавычки.</li> +</ul> + +<p>Если допустили ошибку, используйте кнопку «Сброс», чтобы вернуться к исходному виду примера. Если у вас совсем ничего не получается, нажмите «Показать решение».</p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html notranslate"><div class="output" style="height: 300px;"> + <label for="theme">Выберите тему: </label> + <select id="theme"> + <option value="white">Белая</option> + <option value="black">Черная</option> + <option value="purple">Лиловая</option> + <option value="yellow">Желтая</option> + <option value="psychedelic">Психоделическая</option> + </select> + + <h1>Это мой веб-сайт</h1> +</div> + +<hr> + +<textarea id="code" class="playable-code" style="height: 450px;"> +var select = document.querySelector('select'); +var html = document.querySelector('.output'); + +select.onchange = function() { + var choice = select.value; + + // ДОБАВЬТЕ ИНСТРУКЦИЮ SWITCH +} + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +}</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сброс"> + <input id="solution" type="button" value="Показать решение"> +</div> +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Скрыть решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var jsSolution = 'var select = document.querySelector(\'select\');\nvar html = document.querySelector(\'.output\');\n\nselect.onchange = function() {\n var choice = select.value;\n\n switch(choice) {\n case \'black\':\n update(\'black\',\'white\');\n break;\n case \'white\':\n update(\'white\',\'black\');\n break;\n case \'purple\':\n update(\'purple\',\'white\');\n break;\n case \'yellow\':\n update(\'yellow\',\'darkgray\');\n break;\n case \'psychedelic\':\n update(\'lime\',\'purple\');\n break;\n }\n}\n\nfunction update(bgColor, textColor) {\n html.style.backgroundColor = bgColor;\n html.style.color = textColor;\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } + }; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; + } + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + +updateCode(); + +}; + +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 650) }}</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Это все, что вам нужно знать на данный момент об условных логических структурах! Уверены, вы хорошо разобрались в теоретическом материале и с легкостью справились с предложенными упражнениями. Если же что-то осталось для вас непонятным, перечитайте статью еще раз или <a href="/en-US/Learn#Contact_us">свяжитесь с нами</a>.</p> + +<h2 id="См._также">См. также</h2> + +<ul> + <li><a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">Comparison operators</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Conditional_statements">Conditional statements in detail</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if...else reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Conditional (ternary) operator reference</a></li> +</ul> + +<p>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</p> diff --git a/files/ru/learn/javascript/building_blocks/functions/index.html b/files/ru/learn/javascript/building_blocks/functions/index.html new file mode 100644 index 0000000000..b612858b42 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/functions/index.html @@ -0,0 +1,390 @@ +--- +title: Функции — Переиспользуемые блоки кода +slug: Learn/JavaScript/Building_blocks/Functions +tags: + - Функции + - аргументы + - методы + - параметры +translation_of: Learn/JavaScript/Building_blocks/Functions +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Другая важная концепция в кодировании — <strong>функции </strong>— позволяют хранить фрагмент кода, который выполняет одну задачу внутри определенного блока, а затем вызывать этот код всякий раз, когда вам это нужно, используя одну короткую команду, вместо того, чтобы вводить один и тот же код несколько раз.</p> + +<p class="summary">В этой статье мы рассмотрим фундаментальные концепции функций, такие как базовый синтаксис, способы вызова и их определения, область действия и параметры.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Начальная компьютерная грамотность, основы HTML и CSS, <a href="/ru/docs/Learn/JavaScript/First_steps">первые шаги JavaScript</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять фундаментальные основы функций языка JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Где_можно_встретить_функции">Где можно встретить функции?</h2> + +<p>В JavaScript, Вы везде уведите функции. На самом деле, мы пользовались функциями на протяжении всего курса; только мы не говорили об этом слишком часто. Теперь наступило время, чтобы поговорить о функциях более конкретно и разобрать их синтаксис.</p> + +<p>В значительном количестве случаев, когда вы пользуетесь структурой JavaScript, в которой есть пара обычных скобок — <code>()</code> — и при этом, это не является структурой типа <a href="/ru/Learn/JavaScript/Building_blocks/Looping_code#The_standard_for_loop">цикл for </a>, <a href="/ru/Learn/JavaScript/Building_blocks/Looping_code#while_and_do_..._while">while, или do...while цикл</a>, или <a href="/ru/Learn/JavaScript/Building_blocks/conditionals#if_..._else_statements">if...else конструкция</a>, Вы используете функцию.</p> + +<h2 id="Встроенные_функции_браузера">Встроенные функции браузера</h2> + +<p>В этом курсе мы использовали функции, встроенные в браузер. Каждый раз, когда мы манипулировали текстовой строкой, например:</p> + +<pre class="brush: js notranslate">var myText = 'Я строка'; +var newString = myText.replace('строка', 'сосиска'); +console.log(newString); +// Функция строки replace() принимает строку, +// заменяет одну строку на другую, и возвращает +// новую строку с замененным содержимым</pre> + +<p>Или каждый раз, когда мы манипулировали массивом:</p> + +<pre class="brush: js notranslate">var myArray = ['Я', 'люблю', 'шоколадных', 'лягушек']; +var madeAString = myArray.join(' '); +console.log(madeAString); +// Функция join() принимает массив, соединяет +// все элементы массива вместе в одну строку, +// и возвращает эту новую строку</pre> + +<p>Или каждый раз, когда мы генерировали случайное число:</p> + +<pre class="brush: js notranslate">var myNumber = Math.random() +// Функция random() генерирует случайное число от 0 до 1, +// и возвращает это число</pre> + +<p>...мы использовали функции!</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете вставить эти строки в консоль вашего браузера, чтобы посмотреть, как работают эти функции.</p> +</div> + +<p>Фактически, часть кода, который вы вызываете, когда ссылаетесь на встроенную функцию браузера (воображаемое слово для её запуска или выполнения), не может быть написана на JavaScript — многие из этих функций вызывают части фонового кода браузера, который написан в основном на системных языках низкого уровня, таких как C ++, а не на веб-языках, таких как JavaScript.</p> + +<p>Имейте в виду, что некоторые встроенные функции браузера не являются частью основного языка JavaScript — некоторые из них являются частью API браузера, которые основываются на языке по умолчанию, чтобы обеспечить еще большую функциональность (подробнее см. <a href="/ru/docs/Learn/JavaScript/Первые_шаги/What_is_JavaScript#Так_что_же_он_действительно_может_делать">один из предыдущих разделов этого курса</a>). Более подробно рассмотрим использование API браузера в более позднем модуле курса.</p> + +<h2 id="Функции_или_методы">Функции или методы</h2> + +<p>Одну вещь, которую нам нужно прояснить, прежде чем двигаться дальше - технически, встроенные функции браузера не являются функциями — это <strong>методы</strong>. Это звучит немного страшно и запутанно, но не волнуйтесь — функции и методы слова во многом взаимозаменяемы, по крайней мере для наших целей, на данном этапе вашего обучения.</p> + +<p>Разница между методом и функцией лишь в том, что методы - это функции, определенные внутри объектов. Встроенные функции (методы) браузера и переменные (так называемые <strong>свойства</strong>) хранятся внутри структурированных объектов, чтобы сделать код более эффективным и более простым в использовании.</p> + +<p>Вам пока не нужно изучать внутреннюю работу структурированных объектов JavaScript - вы можете подождать, пока наш более поздний модуль не научит вас внутренним работам объектов и тому, как создавать свои собственные. На данный момент мы просто хотим устранить любую возможную путаницу метода, в сравнении с функциями - вы, вероятно, встретите оба термина, когда будете смотреть на доступные связанные ресурсы через Интернет.</p> + +<h2 id="Пользовательские_функции">Пользовательские функции</h2> + +<p>В этом курсе так же использовались <strong>пользовательские функции</strong> — это функции, которые вы определяете в своем коде, а не внутри браузера. Каждый раз, когда вы видели произвольное слово (имя функции) с круглыми скобками прямо после него, вы использовали пользовательскую функцию. В нашем примере <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/random-canvas-circles.html">random-canvas-circles.html</a> (подробнее см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html">исходный код</a>) из нашей <a href="/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">статьи о циклах</a> мы включили пользовательскую функцию <code>draw()</code>, которая выглядит так:</p> + +<pre class="brush: js notranslate">function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } +}</pre> + +<p>Эта функция рисует 100 случайных кругов внутри элемента {{htmlelement("canvas")}}. Каждый раз, когда мы хотим это сделать, мы можем вызвать эту функцию следующим образом</p> + +<pre class="brush: js notranslate">draw();</pre> + +<p>вместо того, чтобы каждый раз, когда мы хотим повторить этот код, не писать его заново. И функции могут содержать любой код, который вам нравится - вы можете даже вызывать другие функции внутри своих функций. Вышеупомянутая функция, например, вызывает функцию <code>random()</code> три раза, которая выглядит следующим образом:</p> + +<pre class="brush: js notranslate">function random(number) { + return Math.floor(Math.random()*number); +}</pre> + +<p>Нам понадобилась эта функция, потому что встроенная в браузер функция <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> генерирует случайное дробное число от 0 до 1. Но мы хотим случайное целое число от 0 до указанного числа.</p> + +<h2 id="Вызов_функций">Вызов функций</h2> + +<p>Скорее всего, вы уже поняли это, но на всякий случай ... чтобы использовать функцию после того, как она была определена, вам нужно запустить или вызвать ее. Это делается путем включения имени функции в код где-нибудь, за которым следуют скобки.</p> + +<pre class="brush: js notranslate">function myFunction() { + alert('привет'); +} + +myFunction() +// Единовременный вызов функции</pre> + +<h2 id="Безымянные_функции">Безымянные функции</h2> + +<p>Вы можете видеть функции, определенные и вызываемые несколькими разными способами. До этого мы создавали функции таким способом:</p> + +<pre class="brush: js notranslate">function myFunction() { + alert('привет'); +}</pre> + +<p>Но вы также можете создавать функции без имени:</p> + +<pre class="brush: js notranslate">function() { + alert('привет'); +}</pre> + +<p>Такая функция называется <strong>безымянная функция</strong> (или анонимная) — она не имеет имени! Она сама по себе ничего не делает. Обычно такие функции используются вместе с обработчиком событий, например, следующее будет вызывать код внутри функции каждый раз, по нажатию соответствующей кнопки:</p> + +<pre class="brush: js notranslate">var myButton = document.querySelector('button'); + +myButton.onclick = function() { + alert('привет'); +}</pre> + +<p>В приведенном примере требуется, чтобы на странице был элемент {{htmlelement ("button")}} (кнопка), которую нужно нажать. Вы уже видели такую структуру несколько раз на протяжении всего курса, подробнее о ней вы узнаете из следующей статьи.</p> + +<p>Вы также можете присвоить к переменной анонимную функцию, например:</p> + +<pre class="brush: js notranslate">var myGreeting = function() { + alert('привет'); +}</pre> + +<p>Теперь эту функцию можно вызвать, используя:</p> + +<pre class="brush: js notranslate">myGreeting();</pre> + +<p>Фактически такой способ присваивает переменной имя; вы также можете присвоить функцию значением нескольких переменных, например:</p> + +<pre class="brush: js notranslate">var anotherGreeting = function() { + alert('привет'); +}</pre> + +<p>Теперь функцию можно вызвать, используя любую из переменных</p> + +<pre class="brush: js notranslate">myGreeting(); +anotherGreeting();</pre> + +<p>Но это может ввести в заблуждение, так что не стоит так делать! При создании функций лучше всего придерживаться следующего вида:</p> + +<pre class="brush: js notranslate">function myGreeting() { + alert('привет'); +}</pre> + +<p>Чаще всего вы будете использовать анонимные функции, чтобы просто запускать код при срабатывания события - например, нажатие кнопки - с помощью обработчика событий. Опять же, это выглядит примерно так:</p> + +<pre class="brush: js notranslate">myButton.onclick = function() { + alert('привет'); + // При желании, внутри этой функции + // можно написать много кода. +}</pre> + +<h2 id="Параметры_функции">Параметры функции</h2> + +<p>Некоторые функции при их вызове требуют указание параметров — это значения, которые должны быть вставлены в круглые скобки функции, необходимые для корректной работы функции.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Параметры иногда называются аргументами, свойствами или атрибутами.</p> +</div> + +<p>Например встроенная в браузер функция <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> не требует параметров. При вызове, она всегда возвращает случайное число от 0 до 1:</p> + +<pre class="brush: js notranslate">var myNumber = Math.random();</pre> + +<p>Браузерная встроенная функция, работающая со строкой, <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a> ожидает два параметра — это подстрока для поиска в основной строке и строка, на которую происходит замена в основной строке:</p> + +<pre class="brush: js notranslate">var myText = 'Я строка'; +var newString = myText.replace('строка', 'сосиска');</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Если необходимо указать несколько параметров, их разделяют запятыми.</p> +</div> + +<p>Следует также отметить, что иногда параметры являются необязательными - вам не нужно их указывать. Если вы этого не сделаете, функция, как правило, примет какое-то поведение по умолчанию. В качестве примера параметр функции массива <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/join">join()</a> необязателен:</p> + +<pre class="brush: js notranslate">var myArray = ['Я', 'люблю', 'шоколадных', 'лягушек']; +var madeAString = myArray.join(' '); +// Вернет 'Я люблю шоколадных лягушек' +var madeAString = myArray.join(); +// Вернет 'Я,люблю,шоколадных,лягушек'</pre> + +<p>Если не указан параметр для символа соединения / разграничения, по умолчанию используется запятая.</p> + +<h2 id="Область_видимости_функции_и_конфликты">Область видимости функции и конфликты</h2> + +<p>Давайте немного поговорим о {{glossary("scope")}} - очень важная концепция при работе с функциями. Когда вы создаете функцию, переменные и другие вещи, определенные внутри функции, находятся внутри их отдельной <strong>области (scope)</strong>, что означает, что они заперты в своих отдельных отсеках, недоступных из других функций или из кода вне функций.</p> + +<p>Верхний уровень за пределами всех ваших функций называется <strong>глобальной областью (global scope)</strong>. Значения, определенные в глобальном масштабе, доступны извне в коде.</p> + +<p>JavaScript настроен таким образом по разным причинам - но главным образом из-за безопасности и организации. Иногда вы не хотите, чтобы переменные были доступны извне в коде - внешние скрипты, которые вы вызывали из других источников, могут начать работать с вашим кодом и вызывать проблемы, потому что они используют одни и те же имена переменных, как и другие части кода , вызывая конфликты. Это может быть сделано злонамеренно или просто случайно.</p> + +<p>Например, скажем, у вас есть файл HTML, который вызывается в двух внешних файлах JavaScript, и оба они имеют переменную и определенную функцию, которые используют одно и то же имя:</p> + +<pre class="brush: html notranslate"><!-- Excerpt from my HTML --> +<script src="first.js"></script> +<script src="second.js"></script> +<script> + greeting(); +</script></pre> + +<pre class="brush: js notranslate">// first.js +var name = 'Chris'; +function greeting() { + alert('Hello ' + name + ': welcome to our company.'); +}</pre> + +<pre class="brush: js notranslate">// second.js +var name = 'Zaptec'; +function greeting() { + alert('Our company is called ' + name + '.'); +}</pre> + +<p>Обе функции, которые вы хотите вызвать, называются <code>greeting()</code>, но вы можете получить доступ только к функции <code>greeting()</code> файла <code>first.js</code> (функция файла <code>second.js</code> игнорируется). Кроме того, попытка объявить переменную <code>name</code> второй раз через <code>let</code> в файле <code>second.js</code> приведет к ошибке.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Этот пример можно увидеть в режиме <a href="https://mdn.github.io/learning-area/javascript/building-blocks/functions/conflict.html">Live на GitHub</a> (см. также <a href="/ru/docs/https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/functions">исходный код</a>).</p> +</div> + +<p>Хранение частей вашего кода, заблокированных функциями, позволяет избежать таких проблем и считается наилучшей практикой.</p> + +<p>Это немного похоже на зоопарк. Львы, зебры, тигры и пингвины находятся в своих собственных ограждениях и имеют доступ только к вещам внутри их вольеров - таким же образом, как и в области функций. Если бы они смогли попасть в другие вольеры, возникли проблемы. В лучшем случае разные животные будут чувствовать себя неудобно в незнакомых местах обитания - лев или тигр будут чувствовать себя ужасно внутри водянистой, ледяной области пингвинов. В худшем случае львы и тигры могут попытаться съесть пингвинов!</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14079/MDN-mozilla-zoo.png" style="display: block; margin: 0 auto;"></p> + +<p>Хранитель зоопарка подобен глобальной переменной - он или она имеет ключи для доступа к каждому вольеру, для пополнения запасов пищи, ухода за больными животными и т. д.</p> + +<h3 id="Активное_обучение_игра_с_scope">Активное обучение: игра с scope</h3> + +<p>Давайте посмотрим на реальный пример, демонстрирующий обзор.</p> + +<ol> + <li>Сначала создайте локальную копию нашего примера <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-scope.html">function-scope.html</a>. Это содержит две функции, называемые <code>a()</code> и <code>b()</code>, и три переменные - <code>x</code>, <code>y</code> и <code>z</code> - две из которых определены внутри функций и одна в глобальной области. Он также содержит третью функцию, называемую <code>output()</code>, которая принимает один параметр и выводит его в абзаце на странице.</li> + <li>Откройте пример в браузере и в текстовом редакторе.</li> + <li>Откройте консоль JavaScript в инструментах разработчика вашего браузера. В консоли JavaScript введите следующую команду: + <pre class="brush: js notranslate">output(x);</pre> + Вы должны увидеть значение переменной <code>x</code> вывод на экране.</li> + <li>Теперь попробуйте ввести следующее в консоли + <pre class="brush: js notranslate">output(y); +output(z);</pre> + Оба из них должны возвращать ошибку в строке "<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: y is not defined</a>". Почему это? Из-за функции scope - <code>y</code> и <code>z</code> блокируются внутри функций <code>a() </code>и <code>b()</code>, поэтому <code>output()</code> не может получить к ним доступ при вызове из глобальной области.</li> + <li>Однако как насчет того, когда он вызван изнутри другой функции? Попробуйте отредактировать функции <code>a()</code> и <code>b()</code>, чтобы они выглядели следующим образом: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(y); +} + +function b() { + var z = 3; + output(z); +}</pre> + Сохраните код и перезагрузите его в своем браузере, затем попробуйте вызвать функции <code>a()</code> и <code>b()</code> из консоли JavaScript: + + <pre class="brush: js notranslate">a(); +b();</pre> + Вы должны увидеть значения y и z, выводимые на странице. Это отлично работает, так как функция <code>output() </code>вызывается внутри других функций - в той же области, где переменные, которые она печатает, определяются в каждом случае. <code>output()</code> доступен из любого места, поскольку он определен в глобальной области.</li> + <li>Теперь попробуйте обновить свой код следующим образом: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(x); +} + +function b() { + var z = 3; + output(x); +}</pre> + Сохраните и перезагрузите снова и повторите попытку в консоли JavaScript:</li> + <li> + <pre class="brush: js notranslate"><code>a(); +b();</code></pre> + + <p>Оба вызова <code>a()</code> и <code>b()</code> должны выводить значение x - 1. Они работают нормально, потому что, хотя вызовы <code>output()</code> не находятся в той же области, где определено <code>x</code>, <code>x</code> - глобальная переменная, поэтому она доступна внутри всего кода, везде</p> + </li> + <li>Наконец, попробуйте обновить свой код следующим образом: + <pre class="brush: js notranslate"><code>function a() { + var y = 2; + output(z); +} + +function b() { + var z = 3; + output(y); +}</code></pre> + Сохраните и перезагрузите снова и повторите попытку в консоли JavaScript:</li> + <li> + <pre class="brush: js notranslate"><code>a(); +b();</code></pre> + </li> +</ol> + +<p>На этот раз вызовы <code>a()</code> и <code>b()</code> возвратят эту раздражающую ошибку "<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: z is not defined</a>" - это потому, что вызовы <code>output()</code> и переменные, которые они пытаются распечатать, не определены внутри одних и тех же областей функций - переменные эффективно невидимы для этих вызовов функций.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Те же правила определения не применяются к циклу (например, <code>for() { ... }</code>) и условным блокам (например, <code>if() { ... }</code>) - они выглядят очень похожими, но это не одно и то же! Старайтесь не путать их.</p> +</div> + +<div class="note"> +<p><strong>Примечание:</strong> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: "x" is not defined</a>. Ошибка - это одна из наиболее распространенных проблем, с которой вы столкнетесь. Если вы получите эту ошибку, и вы уверены, что определили эту переменную, проверьте, в какой области она находится.</p> +</div> + +<ul> +</ul> + +<h3 id="Функции_внутри_функций">Функции внутри функций</h3> + +<p>Имейте в виду, что вы можете вызывать функцию из любого места, даже если она внутри другой функции. Это часто используется как способ поддержания чистоты кода. Если у вас есть большая сложная функция, ее легче понять, если разбить ее на несколько подфункций:</p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue; + + subFunction1(); + subFunction2(); + subFunction3(); +} + +function subFunction1() { + console.log(myValue); +} + +function subFunction2() { + console.log(myValue); +} + +function subFunction3() { + console.log(myValue); +} +</pre> + +<p>Просто убедитесь, что значения, используемые внутри функции, находятся в области видимости. В приведенном выше примере выдается ошибка <code>ReferenceError: MyValue is not defined</code>, поскольку хотя переменная <code>myValue</code> определена в той же области, что и вызовы функций, она не определена в определениях функций - фактический код, который запускается при вызове функций. Чтобы это работало, вам нужно передать значение в функцию в качестве параметра, например так:</p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue = 1; + + subFunction1(myValue); + subFunction2(myValue); + subFunction3(myValue); +} + +function subFunction1(value) { + console.log(value); +} + +function subFunction2(value) { + console.log(value); +} + +function subFunction3(value) { + console.log(value); +}</pre> + +<h2 id="Заключение">Заключение</h2> + +<p>В этой статье были рассмотрены основные понятия, лежащие в основе функций, позволяющие освоить следующий материал, в котором мы получим практические навыки, и научимся создавать собственные функции.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="/ru/docs/Web/JavaScript/Guide/Functions">Детальное руководство по функциям</a> — описание некоторых дополнительных функций, не описанных в этой статье.</li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Functions">Описание функций</a></li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Functions/Default_parameters">Параметры по умолчанию</a>, <a href="/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions">Стрелочные функции</a> — продвинутая документация</li> +</ul> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</p> diff --git a/files/ru/learn/javascript/building_blocks/image_gallery/index.html b/files/ru/learn/javascript/building_blocks/image_gallery/index.html new file mode 100644 index 0000000000..a0e1e48cd5 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/image_gallery/index.html @@ -0,0 +1,146 @@ +--- +title: Фотогалерея +slug: Learn/JavaScript/Building_blocks/Image_gallery +tags: + - Обработчик событий + - Оценка + - начальный уровень + - события + - циклы +translation_of: Learn/JavaScript/Building_blocks/Image_gallery +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Теперь, после изучения основ JavaScript, мы проверим ваши знания циклов, функций, условных операторов и событий предложив вам написать популярный элемент который вы увидите на многих сайтах - галерея на JavaScript.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Перед выполнением этого задания вы должны проработать все статьи в этом модуле.</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Проверить понимание циклов, функций, условных операторов и событий в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Отправная_точка">Отправная точка</h2> + +<p>Для начала скачайте <a href="https://github.com/ConstantineZz/learning-area/raw/master/javascript/building-blocks/gallery/gallery-start-rv.zip">ZIP файл</a> для примера и распакуйте его содержимое у себя на компьютере.</p> + +<div class="note"> +<p><strong>Замечание</strong>: Вы также можете использовать такие сайты как <a class="external external-icon" href="http://jsbin.com/">JSBin</a> или <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a> для выполнения задания. Вы можте скопировать HTML, CSS и JavaScript в один из этих редакторов. Если онлайн редактор, который вы выбрали, не имеет отдельных панелей для JavaScript/CSS, вы можете выставить код в теги <code><script></code>/<code><style></code> расположенные на самой HTML странице.</p> +</div> + +<h2 id="Обзор_проекта">Обзор проекта</h2> + +<p>В примере вы увидите несколько файлов HTML, CSS и изображений и несколько строк JavaScript кода. Вам нужно написать недостающий JavaScript код для того чтобы галерея заработала. Каркас HTML страницы выглядит так:</p> + +<pre class="brush: html"><h1>Пример фотогалереи</h1> + +<div class="full-img"> + <img class="displayed-img" src="images/pic1.jpg"> + <div class="overlay"></div> + <button class="dark">Темнее</button> +</div> + +<div class="thumb-bar"> + +</div></pre> + +<p>Результат выглядит следующим образом:</p> + +<p><img alt="" src="https://github.com/ConstantineZz/javaScript/blob/master/gallery.png?raw=true" style="height: 639px; width: 827px;"></p> + +<ul> +</ul> + +<p>Наиболее интересные части CSS файла из примера:</p> + +<ul> + <li>Абсолютно позиционированы три элемента внутри <code><div class="full-img"></code>: <code><img></code>, в котором отображается полноразмерное изображение, пустой <code><div class="overlay"></code>, размер которого имеет тот же размер, что и <code><img></code> помещается прямо над предыдущим div-ом (это используется для нанесения эффекта затемнения на изображение через полупрозрачный цвет фона) и <code><button></code>, который используется для управления эффектом затемнения.</li> + <li>Задана ширина любых изображений внутри <code><div class="thumb-bar"></code> (так называемые «уменьшенные изображения») до 20% и размещены слева так, чтобы они следовали друг за другом на линии.</li> +</ul> + +<p>Ваш JavaScript должен:</p> + +<ul> + <li>Переберите все изображения, и для каждого вставьте элемент <code><img></code> внутри <code>thumb-bar <div></code>, который будет вставлять это изображение на страницу.</li> + <li>Прикрепите обработчик <code>onclick</code> к каждому <code><img></code> внутри <code>thumb-bar <div></code>, чтобы при нажатии на них соответствующее изображение отображалось в элементе <code>display-img <img></code>.</li> + <li>Прикрепите обработчик <code>onclick</code> к кнопке <code><button></code>, чтобы при нажатии на нее к полноразмерному изображению был применен эффект затемнения. При повторном нажатии эффект затемнения снова удаляется.</li> +</ul> + +<p>Чтобы лучше понять идею, посмотрите на <a href="https://mdn.github.io/learning-area/javascript/building-blocks/gallery/">готовый пример</a> (не заглядывая в исходный код!).</p> + +<h2 id="Этапы_выполнения">Этапы выполнения</h2> + +<p>В следующих разделах описывается, что вам нужно делать.</p> + +<h3 id="Зацикливание_изображений">Зацикливание изображений</h3> + +<p>В файле main.js уже предоставлены строки, в которых хранится ссылка на <code>thumb-bar <div></code> внутри переменной с именем <code>thumbBar</code>, создают новый элемент <code><img></code>, устанавливают его атрибут <code>src</code> на значение placeholder <code>xxx</code> и добавляют этот новый <code><img></code> элемент внутри <code>thumbBar</code>.</p> + +<p>Нужно сделать:</p> + +<ol> + <li>Поместите раздел кода под комментарием <code>/* Looping through images */</code> внутри цикла, который перебирает все 5 изображений - вам просто нужно перебрать пять чисел, каждое из которых представляет каждое изображение.</li> + <li>В каждой итерации цикла замените значение-заполнитель <code>xxx</code> строкой, которая будет равна пути к изображению в каждом случае. Мы устанавливаем значение атрибута <code>src</code> для этого значения в каждом случае. Имейте в виду, что в каждом случае изображение находится внутри каталога изображений, а его имя - <code>pic1.jpg</code>, <code>pic2.jpg</code> и т.д.</li> +</ol> + +<h3 id="Добавление_обработчика_onclick_к_каждому_уменьшенному_изображению">Добавление обработчика onclick к каждому уменьшенному изображению</h3> + +<p>В каждой итерации цикла вам нужно добавить обработчик <code>onclick</code> к текущему <code>newImage</code>:</p> + +<ol> + <li>Найдите значение атрибута <code>src</code> текущего изображения. Это можно сделать, запустив функцию <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute">getAttribute()</a></code> в <code><img></code> в каждом случае и передав ей параметр <code>«src»</code> в каждом случае. Но как получить изображение? Использование <code>newImage</code> не будет работать, так как цикл завершается до применения обработчиков событий; это приведет к тому, что значение <code>src</code> последнего <code><img></code> будет возвращено в каждом случае. Чтобы решить это, имейте в виду, что в случае каждого обработчика события <code><img></code> является целью обработчика. Как получить информацию от объекта события?</li> + <li>Запустите функцию, передав ей возвращаемое значение <code>src</code> в качестве параметра. Вы можете вызвать эту функцию, как хотите.</li> + <li>Эта функция обработчика событий должна установить значение атрибута <code>src</code> <code>displayed-img <img></code> равным значению <code>src</code>, переданному в качестве параметра. Мы уже предоставили вам строку, в которой хранится ссылка на соответствующий <code><img></code> в переменной с именем <code>displayedImg</code>. Обратите внимание, что здесь нам нужна определенная именованная функция.</li> +</ol> + +<h3 id="Написание_обработчика_который_запускает_кнопку_затемнения_подсветки">Написание обработчика, который запускает кнопку затемнения / подсветки</h3> + +<p>Мы уже предоставили строку, в которой хранится ссылка на <code><button></code> в переменной <code>btn</code>. Вам нужно добавить обработчик <code>onclick</code>, который:</p> + +<ol> + <li>Проверяет текущее имя класса, установленное на кнопке <code><button></code> — для этого снова можно использовать <code>getAttribute()</code>.</li> + <li>Если имя класса <code>"dark"</code>, изменяет класс <code><button></code> на <code>"light"</code> (с помощью <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute">setAttribute()</a></code>), его текстовое содержимое на "Светлее" и {{cssxref("background-color")}} наложения <code><div></code> на <code>"rgba (0,0,0,0.5)"</code>.</li> + <li>Если имя класса не «темное», изменяет класс <code><button></code> на <code>"dark"</code>, его текстовое содержимое обратно на "Темнее" и {{cssxref("background-color")}} наложения <code><div></code> на <code>"rgba(0,0,0,0)"</code>.</li> +</ol> + +<p>Следующие строки служат основой для достижения изменений, указанных в пунктах 2 и 3 выше.</p> + +<pre class="brush: js">btn.setAttribute('class', xxx); +btn.textContent = xxx; +overlay.style.backgroundColor = xxx;</pre> + +<h2 id="Советы_и_подсказки">Советы и подсказки</h2> + +<ul> + <li>Вам не нужно каким-либо образом редактировать HTML или CSS.</li> +</ul> + +<h2 id="Оценка">Оценка</h2> + +<p>Если вы проводите эту оценку в рамках организованного курса, вы должны уметь отдать свою работу своему учителю/наставнику для маркировки. Если вы самообучаетесь, то вы можете получить руководство по маркировке довольно легко, задав тему <a href="https://discourse.mozilla.org/t/image-gallery-assessment/24687">обсуждения об этом упражнении</a> или в IRC-канале <a href="irc://irc.mozilla.org/mdn">#mdn</a> в <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Сначала попробуйте упражнение - ничего не выиграть от обмана!</p> + +<p>{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</p> + +<p> </p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/conditionals">Принятие решений в Вашем коде — условные конструкции</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">Зацикливание кода</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — Переиспользуемые блоки кода</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создайте свою собственную функцию</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Return_values">Возвращаемое значение функции</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/%D0%A1%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F">Введение в события</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Image_gallery">Создание галереи</a></li> +</ul> diff --git a/files/ru/learn/javascript/building_blocks/index.html b/files/ru/learn/javascript/building_blocks/index.html new file mode 100644 index 0000000000..16b54aff16 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/index.html @@ -0,0 +1,61 @@ +--- +title: Структурные элементы JavaScript +slug: Learn/JavaScript/Building_blocks +tags: + - JavaScript + - Введение + - Гид + - Знакомство + - Модуль + - Написание кода + - НаписаниеКода + - Начинающий + - Новичок + - Оценивание + - Раздел + - Руководство + - Статья + - Условия + - Функции + - лендинг + - события + - циклы +translation_of: Learn/JavaScript/Building_blocks +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">В данном разделе мы продолжим знакомство с ключевыми основами JavaScript, обратим внимание на часто используемые приёмы программирования, такие как условные выражения, циклы, функции и события. Все они уже встречались Вам ранее в данном курсе, но только поверхностно, далее они будут рассмотрены подробнее.</p> + +<h2 id="Предварительное_условие">Предварительное условие</h2> + +<p>До начала изучения следующего раздела Вам нужно тщательно ознакомиться с основами <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML</a> и <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS</a>, так же обязательно прочтите курс "<a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8">Первые шаги в JavaScript</a>".</p> + +<div class="note"> +<p><span style="font-size: 14px;"><strong>Примечание</strong></span>: если устройство на котором Вы изучаете данный курс не позволяет создавать/сохранять файлы, в большинстве случаев примеры кода могут быть запущены в таких онлайн приложениях как <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<dl> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/conditionals">Принятие решений в Вашем коде — условные конструкции</a></dt> + <dd>В любом языке программирования необходимо принимать решения и совершать действия в зависимости от полученных в процессе исполнения программы или введённых пользователем данных. Например, игра должна завершиться, когда число жизней персонажа игрока достигает нуля. В приложении для прогноза погоды отображается картинка с восходящим солнцем, если смотреть утром, со звёздами и луной — ночью. В данной статье исследуется работа условных конструкций в JavaScript.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">Зацикливание кода</a></dt> + <dd>Иногда требуется, чтобы действие исполнялось несколько раз подряд. Например, при просмотре списка имён. В программировании для данной цели успешно применяются циклы. Здесь мы познакомимся с использованием циклов в JavaScript.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — блоки кода используемые многократно</a></dt> + <dd>Другая необходимая концепция в программировании это <strong>функции</strong>. <strong>Функции</strong> позволяют сохранить часть кода для решения определённой задачи в определённом блоке, и затем вызывать этот код, тогда, когда это тебе необходимо при помощи короткой команды — это намного лучше, чем писать один и тот же код несколько раз. В статье будут рассмотрена фундаментальная концепция функции: основной синтаксис, как вызывать и как определять функции, области видимости и параметры.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создай свою функцию</a></dt> + <dd>В отличие от большинства предыдущих статей, рассматривающих только теорию, эта статья даёт практический опыт. Здесь вы получите практику создания собственных функций. На ряду с возможностями, мы также объясним дополнительные полезные подробности, связанные с функциями.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/Return_values">Функции возвращают значения</a></dt> + <dd>Есть одно из существенных понятий для нас, представленное в этом курсе, которое достойно пристального внимания — возврат значений функции. Некоторые функции не возвращают значений после завершения, но другие делают это. Главное понять, что это за значения, как использовать их в Вашем коде, и как заставить Вашу собственную функцию возвратить необходимые значения. </dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/События">Введение в события</a></dt> + <dd>События — это действия или явления, которые происходят в системе во время программирования, о которых система сообщает, и, при желании, на которые можно ответить. Например, когда пользователь кликает на кнопку на странице, возможно Вы захотите вывести на экран блок с информацией, как ответ на это событие. В последней статье мы обсудим важные концепции, связанные с событиями, и увидим, как они работают в браузерах.</dd> +</dl> + +<h2 id="Проверка_знаний">Проверка знаний</h2> + +<p>Следующая оценка проверит Ваше понимание основ JavaScript, описанных в данном руководстве.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Фотогалерея</a></dt> + <dd>Теперь, когда мы рассмотрели основные блоки JavaScript, мы проверим твои знания о циклах, функциях, регулярных выражениях и событиях, создав довольно общий элемент, который вы увидите на многих сайтах - галерея изображений, работающей с помощью JavaScript.</dd> +</dl> diff --git a/files/ru/learn/javascript/building_blocks/looping_code/index.html b/files/ru/learn/javascript/building_blocks/looping_code/index.html new file mode 100644 index 0000000000..68f82b6d7b --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/looping_code/index.html @@ -0,0 +1,936 @@ +--- +title: Зацикливание кода +slug: Learn/JavaScript/Building_blocks/Looping_code +translation_of: Learn/JavaScript/Building_blocks/Looping_code +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Языки программирования очень полезны для быстрой реализации повторяющихся задач. От базовых числовых операций до любой другой ситуации, когда у вас есть много похожих операций, которые нужно выполнить. В этой статье мы рассмотрим структуры циклов, доступные в JavaScript, которые можно использовать для этих целей.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Базовые значения компьютерной системы и базовое понимаение HTML и CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript первые шаги</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять как работают циклы в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Циклы_в_коде">Циклы в коде</h2> + +<p>Циклы являются важной концепцией в программировании. Их использование основано на повторении одного и того же, что в программировании называется <strong>итерацией</strong>.</p> + +<p>Давайте рассмотрим работу фермера, который следит за тем, чтобы у него было достаточно еды, чтобы кормить всю свою семью в течении недели. Его работу можно представить в виде цикла:</p> + +<p><br> + <img alt="" src="https://mdn.mozillademos.org/files/13755/loop_js-02-farm.png" style="display: block; margin: 0 auto;"></p> + +<p>Цикл обычно составляет одну или несколько из следующих функций:</p> + +<ul> + <li> <strong>Счетчик</strong>, который инициализируется с определенного значения — начальной точки цикла (На рисунке выше первый этап: "у меня нет еды (i have no food)")</li> + <li><strong>Условие выхода </strong>— критерией, при котором цикл останавливается, — обычно наступает, когда цикл достигает определенного значения. Это иллюстрируется выше словами "Достаточно ли у меня еды? (Do I have enough food?)". Предположим, фермеру нужно 10 порций еды, чтобы прокормить семью.</li> + <li><strong>Итератор </strong>постепенно увеличивает счетчик на некоторое значение на каждом шаге цикла, пока не достигнуто условия выхода. Мы явно не показали это в изображении, но если предположить что фермер собирает две порции еды в час, то после каждого часа, количество еды, которое у него имеется, увеличивается на две порции, и он проверяет достаточно ли у него еды сейчас. Если у него собралось 10 порций (условие выхода), он может остановить сбор и вернуться домой.</li> +</ul> + +<p>В <a href="/ru/docs/Словарь/Pseudocode">псевдокоде</a> это будет выглядеть следующим образом:</p> + +<pre class="notranslate">loop(food = 0; foodNeeded = 10) { + if (food = foodNeeded) { + exit loop; + // У нас достаточно еды, пора домой + } else { + food += 2; // Прошел час, количество еды увеличилось на 2 + // переход на следующую итерацию цикла. + } +}</pre> + +<p>Таким образом, необходимое количество еды устанавливается равным 10, а изначально фермер не имеет ни одной порции, т.е. начало равно 0. На каждой итерации цикла проверяем, соответствует ли собранное количество еды, с тем количеством, которое ему необходимо. Если это так, можно выйти из цикла, если нет, фермер собирает еще 2 порции и снова переходит к проверке.</p> + +<h3 id="Зачем_это_нужно">Зачем это нужно?</h3> + +<p>Итак вы разобрались, как работают циклы. Но, вероятно, думаете: "Хорошо, но как это мне поможет писать код на JavaScript". Как мы писали ранее, <strong>циклы постоянно повторяют одно и тоже действие</strong>, что отлично подходит для <strong>быстрого выполнения повторяющихся задач</strong>.</p> + +<p>Часто код будет немного отличаться на каждой последующей итерации цикла. Это означает, что вы можете выполнять задачи, которые похожи, но у них есть некоторые различия. Например, если вам нужно выполнить много вычислений, немного отличающихся на каждой итерации.</p> + +<p>На следующем примере попробуем показать, почему циклы так полезны. Предположим мы хотели нарисовать 100 случайных кругов на элементе {{htmlelement("canvas")}}. Нажмите кнопку "Обновить", чтобы снова и снова запускать пример и увидеть, что круги рисуются случайным образом.</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Random canvas circles</title> + <style> + html { + width: 100%; + height: inherit; + background: #ddd; + } + + canvas { + display: block; + } + + body { + margin: 0; + } + + button { + position: absolute; + top: 5px; + left: 5px; + } + </style> + </head> + <body> + + <button>Обновить</button> + + <canvas></canvas> + + + <script> + var btn = document.querySelector('button'); + var canvas = document.querySelector('canvas'); + var ctx = canvas.getContext('2d'); + + var WIDTH = document.documentElement.clientWidth; + var HEIGHT = document.documentElement.clientHeight; + + canvas.width = WIDTH; + canvas.height = HEIGHT; + + function random(number) { + return Math.floor(Math.random()*number); + } + + function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } + } + + btn.addEventListener('click',draw); + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 400) }}</p> + +<p>Вам необязательно понимать все части кода, но давайте посмотрим на место, где рисуются 100 кругов.</p> + +<pre class="brush: js notranslate">for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); +}</pre> + +<ul> + <li><code>random()</code>, описанная в коде, возвращает случайное число между <code>0</code> и <code>x-1</code>.</li> + <li><code>WIDTH</code> и <code>HEIGHT</code> — это высота и ширина окна браузера.</li> +</ul> + +<p>Вы должны понять основную идею: мы используем цикл для запуска 100 итераций этого кода, каждая из которых рисует круг в случайном месте в окне. Количество кода было бы одинаковым, если бы нам нужно было нарисовать 10, 100 или 1000 кругов, поменяется лишь одно число.</p> + +<p>Если бы мы не использовали циклы, нам бы пришлось повторить следующий код, для отрисовки каждого круга:</p> + +<pre class="brush: js notranslate">ctx.beginPath(); +ctx.fillStyle = 'rgba(255,0,0,0.5)'; +ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); +ctx.fill();</pre> + +<p>Это множество лишнего кода очень усложнило бы подержку кода в будущем, т.к. если бы вам захотелось что-то изменить, в каждой итерации цикла, пришлось бы изменять все части кода по отдельности. А ещё это усложнаяет поиск ошибок, т.к. если вдруг вы совершите логическую ошибку при описании одной из итераций, придется потратить много времени на ее поиски.</p> + +<h2 id="Правила_записи_цикла">Правила записи цикла</h2> + +<p>Рассмотрим некоторые конкретные конструкции циклов. Первый вариант, который вы будете использовать чаще всего, это цикл <a href="/ru/docs/Web/JavaScript/Reference/Statements/for">for</a>. Он имеет следующий синтаксис:</p> + +<pre class="notranslate">for (initializer; exit-condition; final-expression) { + // код для выполнения +}</pre> + +<p>Тут имеем:</p> + +<ol> + <li>Ключевое слово <a href="ru/docs/Web/JavaScript/Reference/Statements/for">for</a>, за которым следуют круглые скобки.</li> + <li>В круглых скобках у нас есть три части, разделенные точой с запятой: + <ol> + <li><strong>Инициализатор</strong> — обычно это переменная численного типа, которая увеличивается каждую итерацию, чтобы посчитать количество шагов цикла. Ее также называет <strong>счетчиком</strong>.</li> + <li><strong>Условие выхода</strong> — как упоминалось ранее, определяет, когда цикл должен остановиться. Обычно это выражение с оператором сравнения проверяющим, выполнено ли условие выхода.</li> + <li><strong>Окончательное выражение</strong> — вычисляется (или выполняется) каждый раз, когда цикл проходит полную итерацию. Обычно оно служит для увеличения (или уменьшения) переменной <strong>счетчика</strong>, чтобы приблизить ее значение к условию выхода.</li> + </ol> + </li> + <li>Фигурные скобки, содержащие блок кода. Этот код будет запускаться на каждой итерации цикла.</li> +</ol> + +<p>Посмотрим на пример, чтобы разобраться в этом более детально.</p> + +<pre class="brush: js notranslate">var cats = ['Билл', 'Макс', 'Пикси', 'Алиса', 'Жасмин']; +var info = 'Моих кошек зовут '; +var para = document.querySelector('p'); + +for (var i = 0; i < cats.length; i++) { + info += cats[i] + ', '; +} + +para.textContent = info;</pre> + +<p>Этот блок кода будет иметь следующий результат:</p> + +<div class="hidden"> +<h6 id="Hidden_code_2">Hidden code 2</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Пример цикла For</title> + <style> + + </style> + </head> + <body> + + <p></p> + + + <script> + var cats = ['Билл', 'Макс', 'Пикси', 'Алиса', 'Жасмин']; + var info = 'Моих кошек зовут: '; + var para = document.querySelector('p'); + + for (var i = 0; i < cats.length; i++) { + info += cats[i] + ', '; + } + + para.textContent = info; + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_2', '100%', 60) }}</p> + +<div class="note"> +<p><strong>Заметка</strong>: Вы можете найти этот <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for.html">пример на GitHub</a> или <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for.html">посмотреть онлайн</a>.</p> +</div> + +<p>Здесь показан цикл, используемый для перебора элементов в массиве и выполнения определенных действий с каждым из них — очень распространенный шаблон в JavaScript<br> + Подробнее:</p> + +<ol> + <li>Итератор, <code>i</code>, начинается с <code>0</code> (<code>var i = 0</code>).</li> + <li>Цикл запускается, пока значение итератора не будет больше длины массива кошек. Это важно - условие выхода показывает когда именно цикл должен работать, а когда нужно выйти из цикла. Поэтому в случае, пока <code>i < cats.lenght</code> по-прежнему возвращает <code>true</code>, цикл будет работать.</li> + <li>Внутри тела цикла мы соединяем текущий элемент цикла (<code>cats[i]</code> это <code>cats</code>[независимо от того, чем <code>i</code> является в данный момент]) с запятой и пробелом. Итак: + <ol> + <li>В начале, <code>i = 0</code>, поэтому <code>cats[0] + ', '</code> соеденятся в ("Билл, ").</li> + <li>На втором шаге, <code>i = 1</code>, поэтому <code>cats[1] + ', '</code> соединятся в ("Макс, ")</li> + <li>И так далее. В конце каждого цикла <code>i</code> увеличится на 1 (<font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">i++</span></font>) , и процесс будет начинаться заново.</li> + </ol> + </li> + <li>Когда <code>i</code> достигнет величины <code>cats.length</code> цикл остановится и браузер перейдет к следующему фрагменту кода после цикла.</li> +</ol> + +<div class="note"> +<p><strong>Заметка</strong>: Мы добавили условия выхода <code>i < cats.length</code>, а не <code>i <= cats.length</code>, потому что компьютеры считают с 0, а не с 1 — в начале <code>i = 0</code> и увеличивается до <code>i = 4</code> (индекс последнего элемента массива). <code>cats.length</code> возвращает 5, т.к. в массиве 5 элементов, но нам не нужно увеличивать до <code>i = 5</code>, т.к. <code>cats[5] </code>вернет <code>undefined</code> (в массиве нет элемента с индексом 5). Таким образом мы хотим придти к результату на 1 меньше, поэтому <code>i < cats.length</code>, не одно и тоже что <code>i <= cats.length</code>.</p> +</div> + +<div class="note"> +<p><strong>Заметка</strong>: Стандартной ошибкой с условием выхода является использование условия "равный" (<code>===</code>) ,а не "меньше или равно" (<code><=</code>). Если нам нужно увеличить счетчик до <code>i = 5</code>, условие выхода должно быть <code>i <= cats.length</code>. Если мы установим <code>i === cats.length</code>, цикл не начнется, т.к. <code>i</code> не равно <code>5</code> на самой первой итерации, поэтому цикл остановится сразу.</p> +</div> + +<p>Остается одна небольшая проблема: выходная строка сформирована не совсем корректно:</p> + +<blockquote> +<p>Моих кошек зовут Билл, Макс, Пикси, Алиса, Жасмин,</p> +</blockquote> + +<p>В идеале мы хотим изменить конкатенацию на последней итерации цикла так, чтобы у нас не было запятой в конце предложения. Для этого нужно добавить условное выражение внутрь цикла <code>for</code> для обработки этого особого случая:</p> + +<pre class="brush: js notranslate">for (var i = 0; i < cats.length; i++) { + if (i === cats.length - 1) { + info += 'и ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } +}</pre> + +<div class="note"> +<p><strong>Заметка</strong>: Вы можете найти этот <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for-improved.html">пример на GitHub</a> или <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for-improved.html">посмотреть онлайн</a>.</p> +</div> + +<div class="warning"> +<p><strong>Важно</strong>: С цкилом <strong>for</strong>, также как и сдругими циклами, вы должны убедиться что инициализатор (счетчик) и окончательное выражение построены так, что они достигнут условия выхода. Если этого не произойдет, то цикл будет продолжаться вечно. В итоге браузер или заставит его остановиться, или выдаст ошибку. Это называется <strong>бесконечным циклом</strong>.</p> +</div> + +<h2 id="Выход_из_цикла_с_помощью_break">Выход из цикла с помощью break</h2> + +<p>Если вы хотите выйти из цикла до завершения всех итераций, вы можете использовать оператор <a href="/ru/docs/Web/JavaScript/Reference/Statements/break">break</a> . Мы уже встречались с ним в предыдущей статье, когда рассматривали оператор <a href="/ru/docs/Learn/JavaScript/Building_blocks/conditionals#Оператор_switch">switch</a>: когда происходит событие, соответствующее условию, прописанному ключевым словом <code>case</code> внутри оператора <code>switch</code>, условие break моментально выходит из конструкции <code>switch</code> и запускает следующий после нее код.</p> + +<p>Тоже самое и с циклами — условие <code>break</code> моментально закончит цикл и заставит браузер запустить следующий после цикла код.</p> + +<p>Предположим, в массиве данных мы хотим найти имена контактов и телефонные номера, а вернуть только номер, который мы нашли.<br> + Начнем с разметки HTML: поле {{htmlelement("input")}} позволяет нам ввести имя для поиска, элемент (кнопка) {{htmlelement("button")}} для подтверждения поиска, и элемент {{htmlelement("p")}} для отображения результата:</p> + +<pre class="brush: html notranslate"><label for="search">Поиск по имени: </label> +<input id="search" type="text"> +<button>Поиск</button> + +<p></p></pre> + +<p>Теперь в JavaScript:</p> + +<pre class="brush: js notranslate">var contacts = ['Григорий:2232322', 'Марина:3453456', 'Василий:7654322', 'Наталья:9998769', 'Диана:9384975']; +var para = document.querySelector('p'); +var input = document.querySelector('input'); +var btn = document.querySelector('button'); + +btn.addEventListener('click', function() { + var searchName = input.value; + input.value = ''; + input.focus(); + for (var i = 0; i < contacts.length; i++) { + var splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + ', тел.: ' + splitContact[1] + '.'; + break; + } else { + para.textContent = 'Контакт не найден.'; + } + } +});</pre> + +<div class="hidden"> +<h6 id="Hidden_code_3">Hidden code 3</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Simple contact search example</title> + <style> + + </style> + </head> + <body> + + <label for="search">Найти имя контакта: </label> + <input id="search" type="text"> + <button>Поиск</button> + + <p></p> + + + <script> + var contacts = ['Григорий:2232322', 'Марина:3453456', 'Василий:7654322', 'Наталья:9998769', 'Диана:9384975']; + var para = document.querySelector('p'); + var input = document.querySelector('input'); + var btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + var searchName = input.value; + input.value = ''; + input.focus(); + for (var i = 0; i < contacts.length; i++) { + var splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + ', тел.: ' + splitContact[1] + '.'; + break; + } else if (i === contacts.length-1) + para.textContent = 'Контакт не найден.'; + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_3', '100%', 100) }}</p> + +<ol> + <li>Прежде всего у нас определены некоторые переменные: у нас есть массив с контактной информацией, каждый элемент которого это строка, содержащая в себе имя и номер телефона, которые разделенны двоеточием.</li> + <li>Далее мы применяем обработчик события для кнопки (<code>btn</code>), чтобы при её нажатии запускался код для поиска и отображения результатов.</li> + <li>Мы сохраняем значение, введенное в текстовое поле, в переменную <code>searchName</code>, затем очищаем введеный текст и снова фокусируемся на текстовом поле для нового поиска.</li> + <li>Теперь перейдем к интересующей нас части — к циклу <code>for</code>: + <ol> + <li>Мы начали счетчик с <code>0</code>, запускаем цикл до тех пор, пока счетчик всё ещё меньше, чем contacts.length, а инкремент <code>i</code> увеличиваем на 1 после каждой иттерации цикла.</li> + <li>Внутри цикла мы сначала разделяем текущий контакт (<code>contacts[i]</code>) на символе двоеточия, и сохраняем полученные два значения в массиве с названием <code>splitContact</code>.</li> + <li>Затем мы используем условный оператор, чтобы проверить, равно ли <code>splitContact[0]</code> (имя контакта) введеному <code>searchName</code>. Если это так, мы выводим строку в абзац, чтобы сообщить, каков номер контакта, и используем <code>break</code> для завершения цикла.</li> + </ol> + </li> + <li> + <p>После <a href="https://ru.wikipedia.org/wiki/%D0%98%D1%82%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F_(%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F)">итерации</a> <code>(contacts.length-1)</code>, если имя контакта не совпадает с введенным именем в поисковом запросе, для текста абзаца устанавливается: «Контакт не найден.», и цикл продолжает повторяться.</p> + </li> +</ol> + +<div class="note"> +<p>Заметка: Вы можете посмотреть исходный код на <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/contact-search.html">GitHub</a> или запустить его (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/contact-search.html">see it running live</a>).</p> +</div> + +<h2 id="Пропуск_итераций_с_продолжением">Пропуск итераций с продолжением</h2> + +<p>Оператор <a href="/ru/docs/Web/JavaScript/Reference/Statements/continue">continue</a> работает аналогичным образом, как и <code>break</code>, но вместо полного выхода из цикла он переходит к следующей итерации цикла.</p> + +<p>Рассмотрим другой пример, в котором в качестве вводных данных принимается число, а возвращаются только числа, которые являются квадратами целых чисел.</p> + +<p>Код HTML в основном такой же, как и в предыдущем примере — простой ввод текста и абзац для вывода. JavaScript в основном такой же, хотя сам цикл немного другой:</p> + +<pre class="brush: js notranslate">var num = input.value; + +for (var i = 1; i <= num; i++) { + var sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; +}</pre> + +<p>Вывод:</p> + +<div class="hidden"> +<h6 id="Hidden_code_4">Hidden code 4</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Генератор целочисленных квадратов</title> + <style> + + </style> + </head> + <body> + + <label for="number">Введите число: </label> + <input id="number" type="text"> + <button>Генерация целочисленных квадратов</button> + + <p>Результат: </p> + + + <script> + var para = document.querySelector('p'); + var input = document.querySelector('input'); + var btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + var num = input.value; + input.value = ''; + input.focus(); + para.textContent = 'Вы ввели: ' + num + '. Результат: '; + for (var i = 1; i <= num; i++) { + var sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_4', '100%', 100) }}</p> + +<ol> + <li>В этом случае на входе должно быть число (<code>num</code>). Циклу <code>for</code> присваивается счетчик, начинающийся с 1 (поскольку в данном случае нас не интересует 0), условие выхода, которое говорит, что цикл остановится, когда счетчик станет больше входного <code>num</code>, а итератор добавляет 1 к счетчику каждый раз.</li> + <li>Внутри цикла мы находим квадратный корень каждого числа с помощью <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt">Math.sqrt(i)</a>, а затем проверяем, является ли квадратный корень целым числом, проверяя, совпадает ли он с самим собой, когда он был округлен до ближайшего целого числа (это то, что <code>Math.floor ()</code> делает с числом, которое передает).</li> + <li>Если квадратный корень и округленный вниз квадратный корень не равны друг другу <code>(! ==)</code>, значит квадратный корень не является целым числом, поэтому нас он не интересует. В таком случае мы используем оператор <code>continue</code>, чтобы перейти к следующей итерации цикла без записи этого числа.</li> + <li>Если квадратный корень <em>является целым числом</em>, мы пропускаем блок <code>if</code> полностью, поэтому оператор <code>continue</code> не выполняется; вместо этого объединяется текущее значение <code>i</code> с пробелом в конце содержимого абзаца.</li> +</ol> + +<div class="note"> +<p><strong>Примечание. </strong>Вы также можете просмотреть полный исходный код на<strong> </strong><a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/integer-squares.html"> GitHub</a> (так же смотри <a href="https://mdn.github.io/learning-area/javascript/building-blocks/loops/integer-squares.html">этот код вживую</a>).</p> +</div> + +<h2 id="Циклы_while_и_do...while">Циклы <code>while</code> и <code>do...while</code></h2> + +<p><code><strong>for</strong> </code>— <code>не единственный тип цикла, доступный в JavaScript.</code> На самом деле существует множество других типов циклов. И хотя сейчас не обязательно знать их все, стоит взглянуть на структуру нескольких других, чтобы вы могли распознать те же функции, но в работе немного по-другому.</p> + +<p>Рассмотрим цикл <a href="/ru/docs/Web/JavaScript/Reference/Statements/while">while</a>. Синтаксис этого цикла выглядит так:</p> + +<pre class="notranslate">initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p>Его действие очень похоже на цикл <code>for</code>, но переменная инициализатора устанавливается перед циклом, а заключительное выражение включается в цикл после запуска кода. Напомним, у цикла <code>for</code> эти два элемента заключены в круглых скобках. Здесь же после ключевого слова <code>while в круглых скобках заключено условие выхода из цикла.</code></p> + +<p>Здесь присутствуют те же три элемента и в том же порядке, что и в цикле <code>for</code>. Это важно, так как вам нужно определить инициализатор, прежде чем получится проверить, достиг ли цикл условия выхода.</p> + +<p>Окончательное условие выполняется после выполнения кода внутри цикла (итерация завершена), и оно выполняется только в том случае, если условие выхода еще не достигнуто.</p> + +<p>Посмотрим еще раз пример со списком кошек с кодом переписанным под использование цикла <code>while:</code></p> + +<pre class="brush: js notranslate">var i = 0; + +while (i < cats.length) { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +}</pre> + +<div class="note"> +<p><strong>Примечание: </strong>цикл все еще работает так же, как и ожидалось - посмотрите, <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/while.html">как он работает на GitHub</a> (также посмотрите <a href="https://github.com/ConstantineZz/javaScript/blob/master/while.html">полный исходный код</a>).</p> +</div> + +<p>Цикл<strong> <a href="/ru/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a></strong> представляет собой вариацию структуры цикла <code>while</code>:</p> + +<pre class="notranslate">initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p>В этом случае инициализатор снова указывается прежде, чем цикл запускается. Ключевое слово <code>do</code> непосредственно предшествует фигурным скобкам, содержащим код для запуска и конечное выражение.</p> + +<p>Различие состоит в том, что условие выхода идет после всего остального, заключенное в скобки после ключевого слова <code>while</code>. В цикле <code>do...while</code> код внутри фигурных скобок всегда запускается один раз, прежде чем выполняется проверка, чтобы увидеть, должна ли она быть выполнена снова (в <code>while</code> и <code>for</code> проверка идет первой, поэтому код может быть не выполнен).</p> + +<p>Перепишем наш пример с кошками, чтобы использовать цикл <code>do...while</code>:</p> + +<pre class="brush: js notranslate">var i = 0; + +do { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +} while (i < cats.length);</pre> + +<div class="note"> +<p><strong>Примечание: </strong>И снова это работает так же, как и ожидалось - посмотрите, как он работает <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/do-while.html">на GitHub</a> (также посмотрите полный <a href="https://github.com/ConstantineZz/javaScript/blob/master/do-while.html">исходный код</a>).</p> +</div> + +<div class="warning"> +<p><strong>Замечание</strong>: Применяя циклы <code>while</code> and <code>do...while</code> , как и все циклы, убедитесь, что инициализатор повторяется так, чтобы он в конце концов достиг условия выхода. Если это не так, цикл будет продолжаться вечно, и либо браузер заставит его остановиться, либо произойдет сбой. Это называется <em><s>доктор Стрэндж и Дормамму</s></em> <strong>бесконечным циклом</strong>. </p> +</div> + +<h2 id="Практическое_упражнение_запускаем_обратный_отсчет!">Практическое упражнение: запускаем обратный отсчет!</h2> + +<p>В этом упражнении мы хотим, чтобы вы написали простой отсчет времени запуска до поля вывода, от 10 до "Пуск!" В частности, мы хотим, чтобы вы:</p> + +<ul> + <li>Цикл от 10 до 0. Мы предоставляем вам инициализатор: <code>var i = 10;</code>.</li> + <li>Для каждой итерации создайте новый абзац и добавьте его к выходному элементу <code><div></code>, который мы выбрали, используя <code>var output = document.querySelector ('.output');</code>. В комментариях мы предоставили вам три строки кода, которые необходимо использовать где-то внутри цикла: + <ul> + <li><code>var para = document.createElement('p');</code> — создать новый абзац.</li> + <li><code>output.appendChild(para);</code> — добавляет абзац к выводу <code><div></code>.</li> + <li><code>para.textContent =</code> — делает текст внутри абзаца равным значению, которое вы расположили справа, после знака равенства.</li> + </ul> + </li> + <li>Разные номера итераций требуют, чтобы в абзаце для каждой итерации помещался свой текст (вам понадобится условный оператор и несколько<code> para.textContent = lines</code><br> + ): + <ul> + <li>Если число равно 10, выведите в абзаце «Обратный отсчет 10».</li> + <li>Если число равно 0, выведите в абзаце «Пуск!»</li> + <li>Для любого другого числа выведите в абзаце только число.</li> + </ul> + </li> + <li>Не забудьте включить итератор! Однако в этом примере мы ведем обратный отсчет после каждой итерации, а не вверх, поэтому вам <strong>не</strong> нужен <code>i ++</code>. Как выполнить итерацию вниз?</li> +</ul> + +<p>Если вы допустили ошибку, вы всегда можете сбросить пример с помощью кнопки «Сброс» (Reset). Если у вас совсем ничего не получается, нажмите «Show solution», чтобы увидеть решение.</p> + +<div class="hidden"> +<h6 id="Active_learning">Active learning</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 410px;overflow: auto;"> + +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> +<textarea id="code" class="playable-code" style="height: 300px;width: 95%"> +var output = document.querySelector('.output'); +output.innerHTML = ''; + +// var i = 10; + +// var para = document.createElement('p'); +// para.textContent = ; +// output.appendChild(para); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var output = document.querySelector(\'.output\');\noutput.innerHTML = \'\';\n\nvar i = 10;\n\nwhile(i >= 0) {\n var para = document.createElement(\'p\');\n if(i === 10) {\n para.textContent = \'Countdown \' + i;\n } else if(i === 0) {\n para.textContent = \'Blast off!\';\n } else {\n para.textContent = i;\n }\n\n output.appendChild(para);\n\n i--;\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> + +<p class="brush: js"></p> +</div> + +<p>{{ EmbedLiveSample('Active_learning', '100%', 880, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Практическое_упражнение_Заполнение_списка_гостей">Практическое упражнение: Заполнение списка гостей</h2> + +<p>Возьмите список имен, хранящихся в массиве, и поместите их в список гостей. Тут не всё так просто: мы не хотим приглашать Фила и Лолу, потому что они наглые и всё сожрут! У нас есть два списка. Один для тех, кого мы хотим пригласить, второй для тех, кого приглашать не нужно.</p> + +<p>Для этого нужно сделать следующее:</p> + +<ul> + <li>Напишите цикл, который будет повторяться от 0 до длины массива <code>people</code>.<br> + Вам нужно начать с инициализатора <code>var i = 0;</code> , но какое нужно использовать условие выхода?</li> + <li>Во время каждой итерации цикла нужно проверять, соответствует ли текущий элемент массива именам "Фил" или "Лола", используя условный оператор: + <ul> + <li>Если это так, привяжите этот элемент массива в конец <code>textContent</code> абзаца <code>refused</code>, за которым следуют запятая и пробел. </li> + <li>Если это не так, привяжите этот элемент массива в конец <code>textContent</code> абзаца <code>admitted</code>, за которым следуют запятая и пробел.</li> + </ul> + </li> +</ul> + +<p>Мы уже предоставили вам:</p> + +<ul> + <li><code>var i = 0;</code> — Ваш инициализатор.</li> + <li><code>refused.textContent +=</code> — начало строки, которая объединит что-то до конца <code>refused.textContent</code>.</li> + <li><code>admitted.textContent +=</code> — начало строки, которая объединит что-то до конца <code>admitted.textContent</code>.</li> +</ul> + +<p>Дополнительный бонусный вопрос - после успешного выполнения вышеупомянутых задач у вас останется два списка имен, разделенных запятыми, но они будут составлены некорректно: в конце каждого списка будет запятая. Сможете ли вы составить эти списки так, чтобы в конце каждой строки вместо запятой была точка. За помощью можно обратиться к статье «<a href="/ru/docs/Learn/JavaScript/Первые_шаги/Useful_string_methods">Полезные строковые методы</a>».</p> + +<p>Если вы допустили ошибку, вы всегда можете сбросить пример с помощью кнопки «Сброс» (Reset). Если у вас совсем ничего не получается, нажмите «Показать решение», чтобы увидеть решение.</p> + +<div class="hidden"> +<h6 id="Active_learning_2">Active learning 2</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 100px;overflow: auto;"> + <p class="admitted">Пригласить: </p> + <p class="refused">Не приглашать(!): </p> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> +<textarea id="code" class="playable-code" style="height: 400px;width: 95%"> +var people = ['Крис', 'Анна', 'Колин', 'Терри', 'Фил', 'Лола', 'Сем', 'Кай', 'Брюс']; + +var admitted = document.querySelector('.admitted'); +var refused = document.querySelector('.refused'); +admitted.textContent = 'Пригласить: '; +refused.textContent = 'Не приглашать(!): ' + +// var i = 0; + +// refused.textContent += ; +// admitted.textContent += ; + +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сброс"> + <input id="solution" type="button" value="Показать решение"> +</div> +</pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Скрыть решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var jsSolution = 'var people = [\'Крис\', \'Анна\', \'Колин\', \'Терри\', \'Фил\', \'Лола\', \'Сем\', \'Кай\', \'Брюс\'];\n\nvar admitted = document.querySelector(\'.admitted\');\nvar refused = document.querySelector(\'.refused\');\n\nadmitted.textContent = \'Пригласить: \';\nrefused.textContent = \'Не приглашать(!): \'\nvar i = 0;\n\ndo {\n if(people[i] === \'Фил\' || people[i] === \'Лола\') {\n refused.textContent += people[i] + \', \';\n } else {\n admitted.textContent += people[i] + \', \';\n }\n i++;\n} while(i < people.length);\n\nrefused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + \'.\';\nadmitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + \'.\';'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Active_learning_2', '100%', 680) }}</p> + +<h2 id="Так_какой_тип_цикла_использовать">Так какой тип цикла использовать?</h2> + +<p>В основном, используют <code>for</code>, <code>while</code> и <code>do...while</code> циклы, и они во многом взаимозаменяемы. Все они могут быть использованы для выполнения одних и тех же задач и какой из них вы будете использовать, во многом зависит от ваших личных предпочтений. Используйте тот, который вам проще всего запомнить или наиболее интуитивно понятен. Давайте вспомним каждый из них.</p> + +<p><strong><code>For</code></strong>:</p> + +<pre class="notranslate">for (initializer; exit-condition; final-expression) { + // code to run +}</pre> + +<p><strong><code>while</code></strong>:</p> + +<pre class="notranslate">initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p><strong><code>do...while</code></strong>:</p> + +<pre class="notranslate">initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p>Для начала мы бы порекомендовали <code>for</code>, так как его проще запомнить: инициализатор, условие выхода и конечное выражение аккуратно заключено в скобки, поэтому их легко отследить, чтобы их не пропускать.</p> + +<div class="note"> +<p><strong>Примечание. </strong>Существуют и другие типы и функции цикла, которые полезны в сложных или специализированных ситуациях и выходят за рамки данной статьи. Если вы хотите подробнее изучить тему циклов, прочитайте наше расширенное<a href="/ru/docs/Web/JavaScript/Guide/Циклы_и_итерации"> руководство по циклам и итерациям.</a> </p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>Эта статья раскрывает основные концепции и различные опции, доступные при циклическом кодировании в JavaScript. Теперь вам должно быть понятно, почему циклы являются хорошим механизмом для работы с повторяющимся кодом. Старайтесь использовать их в своих собственных примерах!</p> + +<p>Если вы чего-то не поняли, пробуйте читать статью снова или <a href="/ru/docs/Learn#Связаться_с_нами">свяжитесь с нами</a>, мы поможем разобраться.</p> + +<h2 id="Дополнительная_информация">Дополнительная информация</h2> + +<ul> + <li><a href="/ru/docs/Web/JavaScript/Guide/Циклы_и_итерации">Циклы и итерации</a></li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Statements/for">for свойства и характеристики</a></li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Statements/while">while</a> и <a href="/ru/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> описание</li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Statements/break">break</a> и <a href="/ru/docs/Web/JavaScript/Reference/Statements/continue">continue</a> описание</li> + <li> + <p class="entry-title"><a href="https://www.impressivewebs.com/javascript-for-loop/">What’s the Best Way to Write a JavaScript For Loop?</a> — статья о практическом применении циклов</p> + </li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/conditionals">Принятие решений в Вашем коде — условные конструкции</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">Зацикливание кода</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — Переиспользуемые блоки кода</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создайте свою собственную функцию</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Return_values">Возвращаемое значение функции</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/События">Введение в события</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Image_gallery">Создание галереи</a></li> +</ul> diff --git a/files/ru/learn/javascript/building_blocks/return_values/index.html b/files/ru/learn/javascript/building_blocks/return_values/index.html new file mode 100644 index 0000000000..016321c969 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/return_values/index.html @@ -0,0 +1,172 @@ +--- +title: Возвращаемое значение функции +slug: Learn/JavaScript/Building_blocks/Return_values +translation_of: Learn/JavaScript/Building_blocks/Return_values +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/События", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Для нас в этом курсе имеется еще один важный момент. Посмотрим внимательнее на возвращаемое значение функций. Некоторые функции не возвращают существенное значение после завершения, но некоторые возвращают, и важно понимать что это за значение и как использовать его в своем коде и как сделать так чтобы ваши собственные функции возвращали полезные значения. Мы объясним всё это ниже. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td> + <p>Базовая компьютерная грамотность, знание основ HTML и CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a>.</p> + </td> + </tr> + <tr> + <th scope="row">Цели:</th> + <td>Понять что такое возвращаямое значение функции и как его использовать.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_из_себя_представляют_возвращаемые_значения">Что из себя представляют возвращаемые значения?</h2> + +<p><strong>Возвращаемые значения </strong>- это на самом деле просто значения, которые функция возвращает после своего завершения. Вы уже неоднократно встречали возвращаемые значения, хотя, возможно, и не осознавали этого. Напишем небольшой код: </p> + +<pre class="brush: js">var myText = 'I am a string'; +var newString = myText.replace('string', 'sausage'); +console.log(newString); +// функция replace() принимает строку, +// заменяет одну подстроку другой и возвращает +// новую строку со сделанными заменами</pre> + +<p>Мы уже видели этот блок кода в нашей первой статье про функции. Мы вызываем функцию <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a> на строке <code>myText</code> и передаем ей 2 параметра — заменяемую подстроку и подстроку, которой будем заменять. Когда функция завершит выполнение, она вернет значение, которым является новая строка со сделанными в ней заменами. В коде выше мы сохраняем это возвращаемое значение как значение переменной <code>newString</code>.</p> + +<p>Если Вы посмотрите на функцию replace() на MDN reference page, вы увидите секцию под названием <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Return_value">Return value</a>. Очень важно знать и понимать какие значения возвращаются функциями, так что мы пытаемся включать эту информацию везде, где это возможно.</p> + +<p>Некоторые функции не возвращают значения( на наших reference pages, возвращаемое значение обозначено как <code>void</code> или <code>undefined</code> в таких случаях). Например, в функции <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html#L50">displayMessage()</a> которую мы сделали в прошлой статье, в результате выполнения функции не возвращается никакого значения. Функция всего лишь отображает что-то где-то на экране.</p> + +<p>В основном, возвращаемое значение используется там, где функция является чем-то вроде вспомогательного звена при вычислениях. Вы хотите получить результат, который включает в себя некоторые значения. Эти значения вычисляются функцией, которая возвращает результат так, что он может быть использован в следующих стадиях вычисления.</p> + +<h3 id="Использование_возвращаемых_значений_в_ваших_собственных_функциях">Использование возвращаемых значений в ваших собственных функциях</h3> + +<p>Чтобы вернуть значение своей функции, вы должны использовать ключевое слово <a href="/en-US/docs/Web/JavaScript/Reference/Statements/return">return</a>. Мы видели это в действии недавно - в нашем примере <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html">random-canvas-circles.html</a>. Наша функция<code>draw()</code>отрисовывает где-то на экране 100 случайных кружков. </p> + +<p>{{htmlelement("canvas")}}:</p> + +<pre class="brush: js">function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } +}</pre> + +<p>Внутри каждой итерации есть 3 вызова функции <code>random()</code>. Это сделано чтобы сгенерировать случайное значение для текущей координаты x, y и для радиуса. Функция <code>random()</code> принимает 1 параметр (целое число) и возвращает случайное число в диапазоне от 0 до этого числа. Выглядит это вот так: </p> + +<pre class="brush: js">function random(number) { + return Math.floor(Math.random()*number); +}</pre> + +<p>Тоже самое может быть написано вот так:</p> + +<pre class="brush: js">function random(number) { + var result = Math.floor(Math.random()*number); + return result; +}</pre> + +<p>Но первую версию написать быстрее и она более компактна.</p> + +<p>Мы возвращаем результат вычисления <code>Math.floor(Math.random()*number)</code> каждый раз когда функция вызывается. Это возвращаемое значение появляется в момент вызова функции и код продолжается. Так, например, если мы выполним следующую строчку:</p> + +<pre class="brush: js">ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);</pre> + +<p>и 3 вызова <code>random()</code> вернут значения 500, 200 и 35, соответственно, строчка будет выполнена как если бы она была такой:</p> + +<pre class="brush: js">ctx.arc(500, 200, 35, 0, 2 * Math.PI); +</pre> + +<p>Сначала выполняются вызовы функции <code>random()</code>, на место которых подставляются возвращаемые ей значения, а затем выполнятся сама строка.</p> + +<h2 id="Активное_обучение_наша_собственная_возвращающая_значение_функция">Активное обучение: наша собственная, возвращающая значение функция</h2> + +<p>Теперь напишем нашу собственную возвращающую значение функцию.</p> + +<ol> + <li>Первым делом, сделайте локальную копию файла <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-library.html">function-library.html</a> из GitHub. Это простая HTML страничка, содержащая текстовое поле {{htmlelement("input")}} и параграф Также там есть элемент {{htmlelement("script")}} в котором мы храним в 2ух переменных ссылки на оба HTML элемента. Это маленькая страничка позволит Вам ввести число в text box и отобразит различные, относящиеся к нему числа в параграфе ниже.</li> + <li>Теперь добавим несколько полезных функций в элемент <code><script></code> . Ниже двух существующих строчек JavaScript, добавьте следующие описания функций: + <pre class="brush: js">function squared(num) { + return num * num; +} + +function cubed(num) { + return num * num * num; +} + +function factorial(num) { + var x = num; + while (x > 1) { + num *= x-1; + x--; + } + return num; +}</pre> + <code>Ф</code>ункции <code>squared()</code> и <code>cubed()</code> довольно очевидны— они возвразают квадрат или куб переданного как параметр числа. Функция <code>factorial()</code> возвращает <a href="https://en.wikipedia.org/wiki/Factorial">factorial</a> переданного числа.</li> + <li>Далее мы добавим способ выводить нашу информацию введенным в text input числе. Добавьте обработчик событий ниже существующих функций: + <pre class="brush: js">input.onchange = function() { + var num = input.value; + if (isNaN(num)) { + para.textContent = 'You need to enter a number!'; + } else { + para.textContent = num + ' squared is ' + squared(num) + '. ' + + num + ' cubed is ' + cubed(num) + '. ' + + num + ' factorial is ' + factorial(num) + '.'; + } +}</pre> + + <p>Здесь мы создаем обработчик событий <code>onchange</code> который срабатывает когда меняется когда новое значение вводится в text input и подтверждается (введите значение и, например, нажмите tab). Когда анонимная функция срабатывает, введенное в input значение сохраняется в переменной <code>num</code> .</p> + </li> + <li> + <p>Далее мы делаем условный тест — если введенное значение не является чилом, мы выводим в параграф сообщение об ошибке . Тест смотрит возвращает ли выражение <code>isNaN(num)</code> true. Мы используем функцию <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN">isNaN()</a> чтобы проверить что значение переменной num не число — если так то функция возвращает<code>true</code>, если нет- <code>false</code>.</p> + </li> + <li> + <p>Если тест возвращает <code>false</code>, значение переменной <code>num</code>число, и поэтому мы выводим сообщение внутри параграфа о значениях квадрата, куба и факториала числа. Предложение вызывает функции <code>squared()</code>, <code>cubed()<font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;"> и</span></font></code><code>factorial()</code> чтобы получить нужные значения. Сохраните Ваш код, загрузите его в браузере и посмотрите на то что получилось.</p> + </li> +</ol> + +<div class="note"> +<p><strong>Замечание</strong>: Если у вас проблемы с работой данного примера, не стесняйтесь сверить ваш код с работающей версией <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-library-finished.html">finished version on GitHub</a> (или <a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/function-library-finished.html">смотрите живой пример</a>), или спросите нас.</p> +</div> + +<p>К этому моменту мы хотели бы чтобы вы написали парочку собственных функций и добавили их в библиотеку. Как на счет квадратного или кубического корня числа или длины окружности круга с длиной радиуса равной числу <code>num</code>?</p> + +<p>Это упражнение привнесло парочку важных понятий в изучении того, как использовать ключевое слово <code>return</code> . В дополнение:</p> + +<ul> + <li>Приведите другой пример написание обработчика ошибок. Это довольно хорошая идея проверять что важные параметры предоставлены в правильном типе и если они опциональны то предусматривать для них значения по умолчанию. В таком случая Ваша программа с меньшей вероятность подвержена ошибкам. </li> + <li>Поразмышляйте о идее создания библиотеки функций. Чем дальше Вы будите расти в профессиональном плане, тем больше будете сталкиваться с однотипными вещами. Это хорошая идея начать собирать свою собственную библиотеку функций, которые Вы часто используюте — в таком случае Вы сможете просто скопировать их в Ваш новый код или просто добавить их в любую HTML страничку, где это требуется.</li> +</ul> + +<h2 id="Заключение">Заключение</h2> + +<p>Функции очень полезны и не смотря на то, что об их синтаксисе и функциональности можно говорить долго, у нас есть довольно понятные статьи для дальнейшего обучения.</p> + +<p>Если в статье есть что-то что вы не поняли, не стесняйтесь перечитать статью еще раз или <a href="/en-US/Learn#Contact_us">свяжитесь с нами</a> для получения помощи.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions">Функции более подробно</a> — подробное руководство, охватывающее более продвинутую информацию, связанную с функциями.</li> + <li><a href="https://www.impressivewebs.com/callback-functions-javascript/">Функции обратного вызова в JavaScript</a> — распространенный паттерн JavaScript для передачи функции в другую функцию как аргумент, который затем вызывается внутри первой функици.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ru/learn/javascript/building_blocks/test_your_skills_colon__functions/index.html b/files/ru/learn/javascript/building_blocks/test_your_skills_colon__functions/index.html new file mode 100644 index 0000000000..62e1951fdc --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/test_your_skills_colon__functions/index.html @@ -0,0 +1,99 @@ +--- +title: 'Проверь свои навыки: Функции' +slug: 'Learn/JavaScript/Building_blocks/Test_your_skills:_Functions' +tags: + - JavaScript + - Изучение + - Новичек + - Функции +translation_of: 'Learn/JavaScript/Building_blocks/Test_your_skills:_Functions' +--- +<div>{{learnsidebar}}</div> + +<p>Целью данного теста навыков является оценка понимания таких статей, как: <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Функций — многократное использование блоков кода</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Построение своих собственных функций</a> и <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Возвращаемые значения функции</a>.</p> + +<div class="blockIndicator note"> +<p>Примечание: Вы можете проверить решения в интерактивных редакторах ниже, однако может быть полезно загрузить код и использовать онлайн-инструменты, такие как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a> или <a href="https://glitch.com/">Glitch</a> для работы над задачами.<br> + <br> + Если у вас возникла проблема, то попросите нас о помощи - см. раздел {{anch("Анализ или дальнейшая помощь")}} внизу этой страницы.</p> +</div> + +<div class="blockIndicator note"> +<p>Примечание: В примерах ниже, если в вашем коде есть ошибка, она будет выведена на панель результатов этой страницы, чтобы помочь вам попытаться выяснить ответ (или в JavaScript консоли браузера, в случае загружаемой версии).</p> +</div> + +<h2 id="Управление_структурой_DOM_рекомендуется">Управление структурой DOM: рекомендуется</h2> + +<p>Некоторые из вопросов, приведенных ниже, требуют написания кода для управления структурой <a href="/en-US/docs/Glossary/DOM">DOM</a> для их решения - например, создание новых HTML-элементов, установка их текстового содержимого в соответствие с определенными значениями строк, и вложение их внутри существующих элементов на странице - и все это с помощью JavaScript.</p> + +<p>Мы еще не обучали этому прямо в курсе, но вы увидите некоторые примеры, которые используют данную структуру, и мы хотели бы, чтобы вы провели некоторые исследования в отношении того, какие DOM API вам нужны, чтобы успешно ответить на эти вопросы. Хорошим началом будет наше учебное пособие <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Управление документами</a>.</p> + +<h2 id="Функции_1">Функции 1</h2> + +<p>Для решения первой задачи вам нужно создать простую функцию — <code>chooseName()</code>, которая выполнит выборку случайного имени из данного массива (<code>names</code>) и выведет его в предоставленный параграф (<code>para</code>). А затем необходимо запустить эту функцию один раз.</p> + +<p>Попробуйте обновить рабочий код ниже, чтобы воссоздать готовый пример:</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/building-blocks/tasks/functions/functions1.html", '100%', 400)}}</p> + +<div class="blockIndicator note"> +<p><a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/tasks/functions/functions1-download.html">Загрузите файл с исходным кодом для этой задачи</a> для работы в собственном редакторе или в онлайн-редакторе.</p> +</div> + +<h2 id="Функции_2">Функции 2</h2> + +<p>Для решения второй задачи, связанной с функциями, необходимо создать функцию, которая рисует прямоугольник на заданном элементе <code><canvas></code> (исходная переменная <code>canvas</code>, контекст доступен в <code>ctx</code>), основанном на пяти предоставленных входящих значениях:</p> + +<ul> + <li><code>x</code> — x координата прямоугольника.</li> + <li><code>y</code> — y координата прямоугольника.</li> + <li><code>width</code> — ширина прямоугольника.</li> + <li><code>height</code> — высота прямоугольника.</li> + <li><code>color</code> — цвет прямоугольника.</li> +</ul> + +<p>Перед рисованием вам нужно будет очистить содержимое элемента canvas , чтобы при обновлении кода в случае с рабочей версией, вы не получили много прямоугольников, находящихся друг на друге.</p> + +<p>Попробуйте обновить рабочий код ниже, чтобы воссоздать готовый пример:</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/building-blocks/tasks/functions/functions2.html", '100%', 400)}}</p> + +<div class="blockIndicator note"> +<p><a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/tasks/functions/functions2-download.html">Загрузите файл с исходным кодом для этой задачи</a> для работы в собственном редакторе или в онлайн-редакторе.</p> +</div> + +<h2 id="Функции_3">Функции 3</h2> + +<p>В этой задаче вы возвращаетесь к проблеме, поставленной в Задаче 1, с целью ее улучшения. Мы хотим, чтобы вы сделали три улучшения:</p> + +<ol> + <li>Выполните рефакторинг (реорганизацию) кода, который отвечает за генерацию случайного числа в отдельную функцию <code>random()</code>, которая принимает в качестве параметров две общие границы, между которыми должно находиться случайное число и возвращает результат.</li> + <li>Обновите функцию <code>chooseName()</code> таким образом, чтобы она использовала функцию случайных чисел, принимала массив для выбора в качестве параметра (что делает его более гибким) и возвращала результат.</li> + <li>Вывести возвращаемый результат в параграф (<code>para</code>) с помощью свойства <code>textContent</code>. </li> +</ol> + +<p>Попробуйте обновить рабочий код ниже, чтобы воссоздать готовый пример:</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/building-blocks/tasks/functions/functions3.html", '100%', 400)}}</p> + +<div class="blockIndicator note"> +<p><a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/tasks/functions/functions3-download.html">Загрузите файл с исходным кодом для этой задачи</a> для работы в собственном редакторе или в онлайн-редакторе.</p> +</div> + +<h2 id="Анализ_или_дальнейшая_помощь">Анализ или дальнейшая помощь</h2> + +<p>Вы можете попрактиковаться на этих примерах в интерактивных редакторах выше.</p> + +<p>Если же вы хотите, чтобы вашу работу проанализировали, или у вас проблема и вы хотите попросить о помощи:</p> + +<ol> + <li>Поместите свой код в онлайн-редактор <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a> или <a href="https://glitch.com/">Glitch</a> с возможностью совместного использования. Вы можете написать код самостоятельно или использовать файлы с исходным кодом, ссылки на которые приведены в вышеприведенных разделах.</li> + <li>Напишите сообщение с просьбой о проведении анализа и/или помощи в категории <a href="https://discourse.mozilla.org/c/mdn/learn">MDN Discourse forum Learning category</a>. Ваше сообщение должно включать в себя следующие пункты: + <ul> + <li>Описательный заголовок, например "Анализ для теста навыков: Функции 1".</li> + <li>Детали того, что вы уже пробовали, и что бы вы хотели, чтобы мы сделали, например, если вы застряли и нуждаетесь в помощи, или хотите получить анализ проблемы.</li> + <li>Ссылка на пример, который вы хотели бы рассмотреть или с которым вам нужна помощь, в онлайн-редакторе, доступном для совместного использования (как упоминалось в шаге 1 выше). Это хорошая практика - очень сложно помочь кому-то с проблемой, если вы не видите его код.</li> + <li>Ссылка на фактическую задачу или страницу рассмотрения проблемы, чтобы мы могли найти вопрос, по которому вам нужна помощь.</li> + </ul> + </li> +</ol> diff --git a/files/ru/learn/javascript/building_blocks/события/index.html b/files/ru/learn/javascript/building_blocks/события/index.html new file mode 100644 index 0000000000..db13cec676 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/события/index.html @@ -0,0 +1,606 @@ +--- +title: Введение в события +slug: Learn/JavaScript/Building_blocks/События +tags: + - Изучение + - Обработчик событий + - Руководство + - события +translation_of: Learn/JavaScript/Building_blocks/Events +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">События — это действия или случаи, возникающие в программируемой вами системе, о которых система сообщает вам для того, чтобы вы могли с ними взаимодействовать. Например, если пользователь нажимает кнопку на веб-странице, вы можете ответить на это действие, отобразив информационное окно. В этой статье мы обсудим некоторые важные концепции, связанные с событиями, и посмотрим, как они работают в браузерах. Эта статья не является исчерпывающим источником по этой теме — здесь только то, что вам нужно знать на этом этапе.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS, <a href="/ru/docs/Learn/JavaScript/Первые_шаги">Первые шаги в JavaScript</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Понять фундаментальную теорию событий, как они работают в браузерах и как события могут различаться в разных средах программирования.</td> + </tr> + </tbody> +</table> + +<h2 id="Серия_удачных_событий">Серия удачных событий</h2> + +<p>При возникновении <strong>события</strong> система генерирует сигнал, а также предоставляет механизм, с помощью которого можно автоматически предпринимать какие-либо действия (например, выполнить определенный код), когда происходит событие. Например, в аэропорту, когда взлетно-посадочная полоса свободна для взлета самолета, сигнал передается пилоту, и в результате они приступают к взлету.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/17376/MDN-mozilla-events-runway.png" style="height: 443px; width: 700px;"></p> + +<p>В Web события запускаются внутри окна браузера и, как правило, прикрепляются к конкретному элементу, который в нем находится. Это может быть один элемент, набор элементов, документ HTML, загруженный на текущей вкладке, или все окно браузера. Существует множество различных видов событий, которые могут произойти, например:</p> + +<ul> + <li>Пользователь кликает мышью или наводит курсор на определенный элемент.</li> + <li>Пользователь нажимает клавишу на клавиатуре.</li> + <li>Пользователь изменяет размер или закрывает окно браузера.</li> + <li>Завершение загрузки веб-страницы.</li> + <li>Отправка данных через формы.</li> + <li>Воспроизведение видео, пауза или завершение воспроизведения.</li> + <li>Произошла ошибка.</li> +</ul> + +<p>Подробнее о событиях можно посмотреть в <a href="/ru/docs/Web/Events">Справочнике по событиям</a>.</p> + +<p><span>Каждое доступное событие имеет </span><strong>обработчик событий<strong> </strong></strong>—<span> блок кода (обычно это функция JavaScript, вводимая вами в качестве разработчика), который будет запускаться при срабатывании события. Когда такой блок кода определен на запуск в ответ на возникновение события, мы говорим, что мы </span><strong>регистрируем обработчик событий</strong><span>. Обратите внимание, что обработчики событий иногда называют </span><strong>прослушивателями событий (event listeners).</strong><span> Они в значительной степени взаимозаменяемы для наших целей, хотя, строго говоря, они работают вместе. Прослушиватель отслеживает событие, а обработчик </span>— <span>это код, который запускается в ответ на событие.</span></p> + +<div class="note"> +<p><strong>Примечание:</strong> Важно отметить, что веб-события не являются частью основного языка JavaScript. Они определены как часть JavaScript-API, встроенных в браузер.</p> +</div> + +<h3 id="Простой_пример">Простой пример</h3> + +<p>Рассмотрим простой пример. Вы уже видели события и обработчики событий во многих примерах в этом курсе, но давайте повторим для закрепления информации. В этом примере у нас есть кнопка {{htmlelement ("button")}}, при нажатии которой цвет фона изменяется случайным образом:</p> + +<pre class="brush: html notranslate"><button>Change color</button></pre> + +<div class="hidden"> +<pre class="brush: css notranslate">button { margin: 10px };</pre> +</div> + +<p>JavaScript выглядит так:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function random(number) { + return Math.floor(Math.random() * (number+1)); +} + +btn.onclick = function() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<p>В этом коде мы сохраняем ссылку на кнопку внутри переменной <code>btn</code> типа <code>const</code>, используя функцию {{domxref ("Document.querySelector()")}}. Мы также определяем функцию, которая возвращает случайное число. Третья часть кода — <a href="#Свойства_обработчика_событий">обработчик события</a>. Переменная <code>btn</code> указывает на элемент <code><button></code> — для этого типа объекта существуют возникающие при определенном взаимодействии с ним события, а значит, возможно использование обработчиков событий. Мы отслеживаем момент возникновения события при щелчке мышью, связывая свойство обработчика события <code>onclick</code> с анонимной функцией, генерирующей случайный цвет RGB и устанавливающей его в качестве цвета фона элемента <code><body></code>.</p> + +<p>Этот код теперь будет запускаться всякий раз, когда возникает событие при нажатии на элемент <code><button></code> — всякий раз, когда пользователь щелкает по нему.</p> + +<p>Пример вывода выглядит следующим образом:</p> + +<p>{{ EmbedLiveSample('Простой_пример', '100%', 200, "") }}</p> + +<h3 id="События_не_только_для_веб-страниц">События не только для веб-страниц</h3> + +<p>События, как понятие, относятся не только к JavaScript — большинство языков программирования имеют модель событий, способ работы которой часто отличается от модели в JavaScript. Фактически, даже модель событий в JavaScript для веб-страниц отличается от модели событий для просто JavaScript, поскольку используются они в разных средах.</p> + +<p>Например, <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs">Node.js</a> — очень популярная среда исполнения JavaScript, которая позволяет разработчикам использовать JavaScript для создания сетевых и серверных приложений. <a href="https://nodejs.org/docs/latest-v5.x/api/events.html">Модель событий Node.js</a> основана на том, что существуют прослушиватели, отслеживающие события, и эмиттеры (передатчики), которые периодически генерируют события. В общем-то, это похоже на модель событий в JavaScript для веб-страниц, но код совсем другой. В этой модели используется функция <code>on()</code> для регистрации прослушивателей событий, и функция <code>once()</code> для регистрации прослушивателя событий, который отключается после первого срабтывания. Хорошим примером использования являются протоколы событий <a href="https://nodejs.org/docs/latest-v8.x/api/http.html#http_event_connect">HTTP connect event docs</a>.</p> + +<p>Вы также можете использовать JavaScript для создания кросс-браузерных расширений — улучшения функциональности браузера с помощью технологии <a href="https://developer.mozilla.org/ru/docs/Mozilla/Add-ons/WebExtensions">WebExtensions</a>. В отличии от модели веб-событий здесь свойства прослушивателей событий пишутся в так называемом регистре <a href="https://ru.wikipedia.org/wiki/CamelCase">CamelCase</a> (например, <code>onMessage</code>, а не <code>onmessage</code>) и должны сочетаться с функцией <code>addListener</code>. См. <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/onMessage#Examples">runtime.onMessage page</a> для примера.</p> + +<p>На данном этапе обучения вам не нужно особо разбираться в различных средах программирования, однако важно понимать, что принцип работы <em>событий</em> в них отличается.</p> + +<h2 id="Способы_использования_веб-событий">Способы использования веб-событий</h2> + +<p>Существует множество различных способов добавления кода прослушивателя событий на веб-страницы так, чтобы он срабатывал при возникновении соответствующего события. В этом разделе мы рассмотрим различные механизмы и обсудим, какие из них следует использовать.</p> + +<h3 id="Свойства_обработчика_событий">Свойства обработчика событий</h3> + +<p>В этом курсе вы уже сталкивались со свойствами, связываемыми с алгоритмом работы обработчика событий. Вернемся к приведенному выше примеру:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +btn.onclick = function() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<p>В данной ситауции свойство <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick">onclick</a></code> — это свойство обработчика события. В принципе это обычное свойство кнопки как элемента (наравне с <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent">btn.textContent</a></code> или <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style">btn.style</a></code>), но оно относится к особому типу. Если вы установите его равным какому-нибудь коду, этот код будет запущен при возникновении события (при нажатии на кнопку).</p> + +<p>Для получения того же результата, Вы также можете присвоить свойству обработчика имя уже описанной функции (как мы видели в статье <a href="/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создайте свою функцию</a>):</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +} + +btn.onclick = bgChange;</pre> + +<p>Давайте теперь поэкспериментируем с другими свойствами обработчика событий.</p> + +<p>Создайте локальную копию файла <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventhandlerproperty.html">random-color-eventhandlerproperty.html</a> и откройте ее в своем браузере. Это всего лишь копия простого примера про случайные цвета, который мы уже разобрали в этой статье. Теперь попробуйте изменить <code>btn.onclick</code> на следующие значения и понаблюдайте за результатами:</p> + +<ul> + <li><code><a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onfocus">btn.onfocus</a></code> и <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onblur">btn.onblur</a></code> — Цвет изменится, когда кнопка будет сфокусирована или не сфокусирована (попробуйте нажать Tab, чтобы выбрать кнопку или убрать выбор). Эти свойства часто применяются для отображения информации о том, как заполнить поля формы, когда они сфокусированы, или отобразить сообщение об ошибке, если поле формы было заполнено с неправильным значением.</li> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/ondblclick">btn.ondblclick</a></code> — Цвет будет изменяться только при двойном щелчке.</li> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onkeypress">window.onkeypress</a></code>, <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onkeydown">window.onkeydown</a></code>, <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onkeyup">window.onkeyup</a></code> — Цвет будет меняться при нажатии клавиши на клавиатуре, причём <code>keypress</code> ссылается на обычное нажатие (нажатие кнопки и последующее её отпускание <em>как одно целое</em>), в то время как <code>keydown</code> и <code>keyup</code> <em>разделяют</em> действия на нажатие клавиши и отпускание, и ссылаются на них соответственно. Обратите внимание, что это не работает, если вы попытаетесь зарегистрировать этот обработчик событий на самой кнопке - его нужно зарегистрировать на объекте <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window">window</a>, который представляет все окно браузера.</li> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onmouseover">btn.onmouseover</a></code> и <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onmouseout">btn.onmouseout</a></code> — Цвет будет меняться при наведении указателя мыши на кнопку или когда указатель будет отводиться от кнопки соответственно.</li> +</ul> + +<p>Некоторые события очень общие и доступны практически в любом месте (например, обработчик <code>onclick</code> может быть зарегистрирован практически для любого элемента), тогда как некоторые из них более конкретны и полезны только в определенных ситуациях (например, имеет смысл использовать <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/GlobalEventHandlers.onplay">onplay</a> только для определенных элементов, таких как {{htmlelement ("video")}}).</p> + +<h3 id="Встроенные_обработчики_событий_-_не_используйте_их">Встроенные обработчики событий - не используйте их</h3> + +<p>Самый ранний из введенных в сеть Web методов регистрации <em>обработчиков событий</em> базируется на <strong>HTML атрибутах </strong>(<strong>встроенные обработчики событий</strong>):</p> + +<pre class="brush: html notranslate"><button onclick="bgChange()">Press me</button> +</pre> + +<pre class="brush: js notranslate">function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventhandlerattributes.html">полный исходник кода</a> из этого примера на GitHub (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-eventhandlerattributes.html">взгляните на его выполнение</a>).</p> +</div> + +<p>Значение атрибута — это буквально код JavaScript, который вы хотите запустить при возникновении события. В приведенном выше примере вызывается функция, определенная внутри элемента {{htmlelement ("script")}} на той же странице, но вы также можете вставить JavaScript непосредственно внутри атрибута, например:</p> + +<pre class="brush: html notranslate"><button onclick="alert('Hello, this is my old-fashioned event handler!');">Press me</button></pre> + +<p>Для многих свойств обработчика событий существуют эквиваленты в виде атрибутов HTML. Однако, не рекомендуется их использовать — это считается плохой практикой. Использование атрибутов для регистрации обработчика событий кажется простым и быстрым методом, но такое описание обработчиков также скоро становится неудобным и неэффективным.</p> + +<p>Более того, не рекомендуется смешивать HTML и JavaScript файлы, так как в дальнейшем такой код становится сложнее с точки зрения обработки (парсинга). Лучше держать весь JavaScript в одном месте. Также, если он находится в отдельном файле, вы можете применить его к нескольким документам HTML.</p> + +<p>Даже при работе только в одном файле использование встроенных обработчиков не является хорошей идеей. Ладно, если у Вас одна кнопка, но что, если у вас их 100? Вам нужно добавить в файл 100 атрибутов; обслуживание такого кода очень быстро превратится в кошмар. С помощью JavaScript вы можете легко добавить функцию обработчика событий ко всем кнопкам на странице независимо от того, сколько их было.</p> + +<p>Например:</p> + +<pre class="brush: js notranslate">const buttons = document.querySelectorAll('button'); + +for (var i = 0; i < buttons.length; i++) { + buttons[i].onclick = bgChange; +}</pre> + +<p class="brush: js">Обратите внимание, что для перебора всех элементов, которые содержит объект <code><a href="/en-US/docs/Web/API/NodeList">NodeList</a></code>, можно воспользоваться встроенным методом <code><a href="/en-US/docs/Web/API/NodeList/forEach">forEach()</a></code>:</p> + +<pre class="brush: js notranslate">buttons.forEach(function(button) { + button.onclick = bgChange; +});</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Разделение логики Вашей программы и Вашего контента также делает Ваш сайт более дружественным к поисковым системам.</p> +</div> + +<h3 id="Функции_addEventListener_и_removeEventListener">Функции addEventListener() и removeEventListener()</h3> + +<p>Новый тип механизма событий определен в спецификации <a href="https://www.w3.org/TR/DOM-Level-2-Events/">Document Object Model (DOM) Level 2 Events</a>, которая предоставляет браузеру новую функцию — <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>. Работает она аналогично свойствам обработчика событий, но синтаксис совсем другой. Наш пример со случайным цветом мог бы выглядеть и так:</p> + +<pre class="brush: js notranslate">var btn = document.querySelector('button'); + +function bgChange() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +} + +btn.addEventListener('click', bgChange);</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-addeventlistener.html">исходный код</a> из этого примера на GitHub (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-addeventlistener.html">взгляните на его выполнение</a>).</p> +</div> + +<p>Внутри функции <code>addEventListener()</code> мы указываем два параметра — имя события, для которого мы хотим зарегистрировать этот обработчик, и код, содержащий функцию обработчика, которую мы хотим запустить в ответ. Обратите внимание, что будет целесообразно поместить весь код внутри функции <code>addEventListener()</code> в анонимную функцию, например:</p> + +<pre class="brush: js notranslate">btn.addEventListener('click', function() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +});</pre> + +<p>Этот механизм имеет некоторые преимущества по сравнению с более старыми механизмами, рассмотренными ранее. Например, существует аналогичная функция <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener">removeEventListener()</a></code>, которая удаляет ранее добавленный прослушиватель. Это приведет к удалению набора слушателей в первом блоке кода в этом разделе:</p> + +<pre class="brush: js notranslate">btn.removeEventListener('click', bgChange);</pre> + +<p>Это не важно для простых небольших программ, но для более крупных и более сложных программ он может повысить эффективность очистки старых неиспользуемых обработчиков событий. Кроме того, это позволяет вам иметь одну и ту же кнопку, выполняющую различные действия в разных обстоятельствах — все, что вам нужно сделать, это добавить/удалить обработчики событий, если это необходимо.</p> + +<p>Также, вы можете зарегистрировать несколько обработчиков для одного и того же прослушивателя. Следующие два обработчика не будут применяться:</p> + +<pre class="brush: js notranslate">myElement.onclick = functionA; +myElement.onclick = functionB;</pre> + +<p>Поскольку вторая строка будет перезаписывать значение <code>onclick</code>, установленное первой. Однако, если:</p> + +<pre class="brush: js notranslate">myElement.addEventListener('click', functionA); +myElement.addEventListener('click', functionB);</pre> + +<p>Обе функции будут выполняться при щелчке элемента.</p> + +<p>Кроме того, в этом механизме событий имеется ряд других мощных функций и опций. Эта тема выходит за рамки данной статьи, но если вы хотите изучить подробнее, переходите по ссылкам: <a href="/ru/docs/Web/API/EventTarget/addEventListener">Метод EventTarget.addEventListener()</a> и <a href="/ru/docs/Web/API/EventTarget/removeEventListener">Метод EventTarget.removeEventListener()</a>.</p> + +<h3 id="Какой_механизм_мне_использовать">Какой механизм мне использовать?</h3> + +<p>Из трех механизмов определенно не нужно использовать атрибуты событий HTML. Как упоминалось выше, это устаревшая и плохая практика.</p> + +<p>Остальные два являются относительно взаимозаменяемыми, по крайней мере для простых целей</p> + +<ul> + <li>Свойства обработчика событий имеют меньшую мощность и параметры, но лучше совместимость между браузерами (поддерживается еще в Internet Explorer 8). Вероятно, вам следует начать с них, когда вы учитесь.</li> + <li>События уровня 2 DOM (<code>addEventListener()</code> и т. д.) являются более мощными, но также могут стать более сложными и хуже поддерживаться (поддерживается еще в Internet Explorer 9). Вам также стоит поэкспериментировать с ними и стремиться использовать их там, где это возможно.</li> +</ul> + +<p>Основные преимущества третьего механизма заключаются в том, что при необходимости можно удалить код обработчика событий, используя <code>removeEventListener()</code>, и так же можно добавить несколько элементов-слушателей того же типа к элементам. Например, вы можете вызвать <code>addEventListener('click', function() {...})</code> для элемента несколько раз, с разными функциями, указанными во втором аргументе. Это невозможно при использовании свойств обработчика событий, поскольку любые последующие попытки установить свойство будут перезаписывать более ранние, например:</p> + +<pre class="brush: js notranslate">element.onclick = function1; +element.onclick = function2; +etc.</pre> + +<div class="note"> +<p><strong>Примечание:</strong> Если вам требуется поддержка браузеров старше Internet Explorer 8 в вашем проекте, вы можете столкнуться с трудностями, так как такие старые браузеры используют старые модели событий из более новых браузеров. Но не бойтесь, большинство библиотек JavaScript (например, <code>jQuery</code>) имеют встроенные функции, которые абстрагируют различия между браузерами. Не беспокойтесь об этом слишком много на этапе вашего учебного путешествия.</p> +</div> + +<h2 id="Другие_концепции_событий">Другие концепции событий</h2> + +<p>Рассмотрим некоторые современные концепции, имеющие отношение к событиям. На данный момент не обязательно понимать их полностью, но предстывление о них поможет лучше понять некоторые модели кода, с которыми вы, вероятно, столкнетесь.</p> + +<h3 id="Объекты_событий"> Объекты событий</h3> + +<p>Иногда внутри функции обработчика событий вы можете увидеть параметр, заданный с таким именем, как <code>event</code>, <code>evt</code> или просто <code>e</code>. Называется он <strong>объектом события</strong> и он автоматически передается обработчикам событий для предоставления дополнительных функций и информации. Например, давайте немного перепишем наш прмер со случайным цветом:</p> + +<pre class="brush: js notranslate">function bgChange(e) { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + e.target.style.backgroundColor = rndCol; + console.log(e); +} + +btn.addEventListener('click', bgChange);</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventobject.html">исходник кода</a> для этого примера на GitHub (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-eventobject.html">взгляните на его выполнение</a>).</p> +</div> + +<p>Итак в коде выше мы включаем объект события <strong><code>e</code></strong> в функцию, а в функции — настройку стиля фона для <code>e.target</code>, который является кнопкой. Свойство объекта события <code>target</code> всегда является ссылкой на элемент, с которым только что произошло событие. Поэтому в этом примере мы устанавливаем случайный цвет фона на кнопке, а не на странице.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Вместо <code>e</code>/<code>evt</code>/<code>event</code> можно использовать любое имя для объекта события, которое затем можно использовать для ссылки на него в функции обработчика событий. <code>e</code>/<code>evt</code>/<code>event</code> чаще всего используются разработчиками, потому что они короткие и легко запоминаются. И хорошо придерживаться стандарта.</p> +</div> + +<p><code>e.target</code> применяют, когда нужно установить один и тот же обработчик событий на несколько элементов и, когда на них происходит событие, применить определенное действие к ним ко всем. Например, у вас может быть набор из 16 плиток, которые исчезают при нажатии. Полезно всегда иметь возможность просто указать, чтобы объект исчез, как <code>e.target</code>, вместо того, чтобы выбирать его более сложным способом. В следующем примере (см. исходный код на <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/useful-eventtarget.html">useful-eventtarget.html</a>,а как он работает можно посмотреть <a href="https://mdn.github.io/learning-area/javascript/building-blocks/events/useful-eventtarget.html">здесь</a>), мы создаем 16 элементов {{htmlelement ("div")}} с использованием JavaScript. Затем мы выберем все из них, используя {{domxref ("document.querySelectorAll()")}}, и с помощью цикла <code>for</code> выберем каждый из них, добавив обработчик <code>onclick</code> к каждому так, чтобы случайный цвет применялся к каждому клику:</p> + +<pre class="brush: js notranslate">var divs = document.querySelectorAll('div'); + +for (var i = 0; i < divs.length; i++) { + divs[i].onclick = function(e) { + e.target.style.backgroundColor = bgChange(); + } +}</pre> + +<p>Результат выглядит следующим образом (попробуйте щелкнуть по нему):</p> + +<div class="hidden"> +<h6 id="Hidden_example">Hidden example</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Useful event target example</title> + <style> + div { + background-color: #ff6600; + height: 100px; + width: 25%; + float: left; + } + </style> + </head> + <body> + <script> + for (var i = 1; i <= 16; i++) { + var myDiv = document.createElement('div'); + document.body.appendChild(myDiv); + } + + function random(number) { + return Math.floor(Math.random()*number); + } + + function bgChange() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + return rndCol; + } + + var divs = document.querySelectorAll('div'); + + for (var i = 0; i < divs.length; i++) { + divs[i].onclick = function(e) { + e.target.style.backgroundColor = bgChange(); + } + } + </script> + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_example', '100%', 400) }}</p> + +<p>Большинство обработчиков событий, с которыми вы столкнулись, имеют только стандартный набор свойств и функций (методов), доступных для объекта события (см. {{domxref("Event")}} для ссылки на полный список). Однако некоторые более продвинутые обработчики добавляют специальные свойства, содержащие дополнительные данные, которые им необходимо выполнять. Например, <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder_API">Media Recorder API</a> имеет событие, доступное для данных, которое срабатывает, когда записано какое-либо аудио или видео и доступно для выполнения чего-либо (например, для сохранения или воспроизведения). Соответствующий объект события <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/ondataavailable">ondataavailable</a> handler имеет свойство данных, содержащее записанные аудио- или видеоданные, чтобы вы могли получить к нему доступ и что-то сделать с ним.</p> + +<h3 id="Предотвращение_поведения_по_умолчанию"> Предотвращение поведения по умолчанию</h3> + +<p>Иногда бывают ситуации, когда нужно остановить событие, выполняющее то, что оно делает по умолчанию. Наиболее распространенным примером является веб-форма, например, пользовательская форма регистрации. Когда вы вводите данные и нажимаете кнопку отправки, естественное поведение заключается в том, что данные должны быть отправлены на указанную страницу на сервере для обработки, а браузер перенаправлется на страницу с сообщением об успехе (или остаться на той же странице, если другое не указано).</p> + +<p>Но если пользователь отправил данные не правильно, как разработчик, вы хотите остановить отправку на сервер и выдать сообщение об ошибке с информацией о том, что не так и что нужно сделать. Некоторые браузеры поддерживают функции автоматической проверки данных формы, но, поскольку многие этого не делают, вам не следует полагаться на них и выполнять свои собственные проверки валидации. Давайте посмотрим на простой пример.</p> + +<p>Простая форма HTML, в которой требуется ввести ваше имя и фамилию:</p> + +<pre class="brush: html notranslate"><form> + <div> + <label for="fname">Имя: </label> + <input id="fname" type="text"> + </div> + <div> + <label for="lname">Фамилия: </label> + <input id="lname" type="text"> + </div> + <div> + <input id="submit" type="submit"> + </div> +</form> +<p></p></pre> + +<div class="hidden"> +<pre class="brush: css notranslate">div { + margin-bottom: 10px; +} +</pre> +</div> + +<p>В JavaScript мы реализуем очень простую проверку внутри обработчика события <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onsubmit">onsubmit</a> (событие "отправить" запускается в форме, когда оно отправлено), который проверяет, пусты ли текстовые поля. Если они пусты, мы вызываем функцию <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault">preventDefault()</a></code> объекта события, которая останавливает отправку формы, а затем выводит сообщение об ошибке в абзаце ниже нашей формы, чтобы сообщить пользователю, что не так:</p> + +<pre class="brush: js notranslate">var form = document.querySelector('form'); +var fname = document.getElementById('fname'); +var lname = document.getElementById('lname'); +var submit = document.getElementById('submit'); +var para = document.querySelector('p'); + +form.onsubmit = function(e) { + if (fname.value === '' || lname.value === '') { + e.preventDefault(); + para.textContent = 'Оба поля должны быть заполнены!'; + } +}</pre> + +<p>Очевидно, что это довольно слабая проверка формы - это не помешает пользователю отправить форму с пробелами или цифрами, введенными в поля, но для примера подходит. Вывод выглядит следующим образом:</p> + +<p>{{ EmbedLiveSample('Предотвращение_поведения_по_умолчанию', '100%', 140) }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: чтобы увидеть исходный код, откройте <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/preventdefault-validation.html">preventdefault-validation.html</a> (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/preventdefault-validation.html">запустите</a> здесь).</p> +</div> + +<h3 id="Всплытие_и_перехват_событий">Всплытие и перехват событий</h3> + +<p>Последним предметом для рассмотрения в этой теме является то, с чем вы не часто будете сталкиваться, но это может стать настоящей головной болью, если вы не поймете, как работает следующий механизм. <em>Всплытие</em> и <em>перехват событий</em> — два механизма, описывающих, что происходит, когда два обработчика одного и того же события активируются на одном элементе. Посмотрим на пример. Чтобы сделать это проще — откройте пример <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box.html">show-video-box.html</a> в одной вкладке и <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box.html">исходный код </a>в другой вкладке. Он также представлен ниже:</p> + +<div class="hidden"> +<h6 id="Hidden_video_example">Hidden video example</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Show video box example</title> + <style> + div { + position: absolute; + top: 50%; + transform: translate(-50%,-50%); + width: 550px; + height: 420px; + border-radius: 10px; + background-color: #eee; + background-image: linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.4)); + } + + .hidden { + left: -50%; + } + + .showing { + left: 50%; + } + + div video { + display: block; + width: 400px; + margin: 50px auto; + } + + </style> + </head> + <body> + <button>Display video</button> + + <div class="hidden"> + <video> + <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.mp4" type="video/mp4"> + <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> + </video> + </div> + + <script> + + var btn = document.querySelector('button'); + var videoBox = document.querySelector('div'); + var video = document.querySelector('video'); + + btn.onclick = function() { + displayVideo(); + } + + function displayVideo() { + if(videoBox.getAttribute('class') === 'hidden') { + videoBox.setAttribute('class','showing'); + } + } + + videoBox.addEventListener('click',function() { + videoBox.setAttribute('class','hidden'); + }); + + video.addEventListener('click',function() { + video.play(); + }); + + </script> + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_video_example', '100%', 500) }}</p> + +<p>Это довольно простой пример, который показывает и скрывает {{htmlelement ("div")}} с элементом {{htmlelement ("video")}} внутри него:</p> + +<pre class="brush: html notranslate"><button>Display video</button> + +<div class="hidden"> + <video> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> + </video> +</div></pre> + +<p>При нажатии на кнопку {{htmlelement ("button")}}, изменяется атрибут класса элемента <code><div></code> с <code>hidden</code> на <code>showing</code> (CSS примера содержит эти два класса, которые размещают блок вне экрана и на экране соответственно):</p> + +<pre class="brush: css notranslate">div { + position: absolute; + top: 50%; + transform: translate(-50%,-50%); + ... + } +<font color="#6f42c1" face="SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace">.hidden { + left: -50%; + } +.showing { + left: 50%; + }</font></pre> + +<pre class="brush: js notranslate">var btn = document.querySelector('button'); +btn.onclick = function() { + videoBox.setAttribute('class', 'showing'); +}</pre> + +<p>Затем мы добавляем еще пару обработчиков событий <code>onclick.</code> Первый к <code><div></code>, а второй к <code><video></code>. Идея заключается в том, чтобы при щелчке по области <code><div></code> вне зоны видео поле снова скрылось, а при клике в области <code><video></code> видео начало воспроизводиться.</p> + +<pre class="brush: js notranslate">var videoBox = document.querySelector('div'); +var video = document.querySelector('video'); + +videoBox.onclick = function() { + videoBox.setAttribute('class', 'hidden'); +}; + +video.onclick = function() { + video.play(); +};</pre> + +<p>Но есть проблема: когда вы нажимаете на видео, оно начинает воспроизводиться, но одновременно вызывает скрытие <code><div></code>. Это связано с тем, что видео находится внутри <code><div>,</code> это часть его, поэтому нажатие на видео фактически запускает оба вышеуказанных обработчика событий.</p> + +<h4 id="Всплытие_и_перехват_событий_—_концепция_выполнения"><strong>Всплытие и перехват событий — концепция выполнения</strong></h4> + +<p>Когда событие инициируется элементом, который имеет родительские элементы (например, {{htmlelement ("video")}} в нашем случае), современные браузеры выполняют две разные фазы — фазу <strong>захвата</strong> и фазу <strong>всплытия</strong>.</p> + +<p>На стадии <strong>захвата </strong>происходит следующее:</p> + +<ul> + <li>Браузер проверяет, имеет ли самый внешний элемент ({{htmlelement ("html")}}) обработчик события <code>onclick</code>, зарегистрированный на нем на этапе захвата и запускает его, если это так.</li> + <li>Затем он переходит к следующему элементу внутри <code><html></code> и выполняет то же самое, затем следующее и так далее, пока не достигнет элемента, на который на самом деле нажали.</li> +</ul> + +<p>На стадии <strong>всплытия</strong> происходит полная противоположность:</p> + +<ul> + <li>Браузер проверяет, имеет ли элемент, который был фактически нажат, обработчик события <code>onclick</code>, зарегистрированный на нем в фазе высплытия, и запускает его, если это так.</li> + <li>Затем он переходит к следующему непосредственному родительскому элементу и выполняет то же самое, затем следующее и так далее, пока не достигнет элемента <code><html></code>.</li> +</ul> + +<p><a href="https://mdn.mozillademos.org/files/14075/bubbling-capturing.png"><img alt="" src="https://mdn.mozillademos.org/files/14075/bubbling-capturing.png" style="display: block; height: 452px; margin: 0px auto; width: 960px;"></a></p> + +<p>(Нажмите на изображение, чтобы увеличить диаграмму)</p> + +<p>В современных браузерах по умолчанию все обработчики событий регистрируются в фазе <strong><em>всплытия</em></strong>. Итак, в нашем текущем примере, когда вы нажимаете видео, событие click вызывается из элемента <code><video></code> наружу, в элемент <code><html></code>. По пути:</p> + +<ul> + <li>Он находит обработчик <code>video.onclick...</code> и запускает его, поэтому видео сначала начинает воспроизводиться.</li> + <li>Затем он находит обработчик <code>videoBox.onclick...</code> и запускает его, поэтому видео также скрывается.</li> +</ul> + +<h4 id="Исправление_проблемы_с_помощью_stopPropagation">Исправление проблемы с помощью stopPropagation()</h4> + +<p>Чтобы исправить это раздражающее поведение, стандартный объект события имеет функцию, называемую <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation">stopPropagation()</a></code>, которая при вызове в обработчике событий объекта делает так, чтобы обработчик выполнялся, но событие не всплывало дальше по цепочке, поэтому не будут запускаться другие обработчики.</p> + +<p>Поэтому мы можем исправить нашу текущую проблему, изменив вторую функцию-обработчик в предыдущем блоке кода:</p> + +<pre class="brush: js notranslate">video.onclick = function(e) { + e.stopPropagation(); + video.play(); +};</pre> + +<p>Вы можете попробовать создать локальную копию <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box.html">show-video-box.html</a> и попробовать его самостоятельно исправить или просмотреть исправленный результат в <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box-fixed.html">show-video-box-fixed.html</a> (также см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box-fixed.html">исходный код здесь</a>).</p> + +<div class="note"><strong>Примечание</strong>: Зачем беспокоиться как с захватом, так и с всплыванием? Что ж, в старые добрые времена, когда браузеры были менее совместимы, чем сейчас, Netscape использовал только захват событий, а Internet Explorer использовал только всплывающие события. Когда W3C решил попытаться стандартизировать поведение и достичь консенсуса, они в итоге получили эту систему, которая включала в себя и то, и другое, что реализовано в одном из современных браузеров.</div> + +<div class="note"> +<p><strong>Примечание</strong>: Как упоминалось выше, по умолчанию все обработчики событий регистрируются в фазе всплытия и это имеет смысл в большинстве случаев. Если вы действительно хотите зарегистрировать событие в фазе захвата, вы можете сделать это, зарегистрировав обработчик с помощью <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code> и установив для третьего дополнительного свойства значение <code>true</code>.</p> +</div> + +<h4 id="Делегирование_события"><strong>Делегирование</strong> события</h4> + +<p>Всплытие также позволяет нам использовать <strong>делегирование событий. </strong> Если у какого-либо родительского элемента есть множество дочерних элементов, и вы хотите, чтобы определенный код выполнялся при щелчке (событии) на каждом из дочерних элементов, можно установить прослушиватель событий на родительском элементе и события, происходящие на дочерних элементах будут всплывать до их родителя. При этом не нужно устанавливать прослушивателя событий на каждом дочернем элементе.</p> + +<p>Хорошим примером является серия элементов списка. Если вы хотите, чтобы каждый из них, например, отображал сообщение при нажатии, вы можете установить прослушиватель событий <code>click</code> для родительского элемента <code><ul></code> и он будет всплывать в элементах списка.</p> + +<p>Эту концепцию объясняет в своем блоге Дэвид Уолш, где приводит несколько примеров. (см. <a href="https://davidwalsh.name/event-delegate">How JavaScript Event Delegation Works</a>.)</p> + +<h2 id="Вывод">Вывод</h2> + +<p>Это все, что вам нужно знать о веб-событиях на этом этапе. Как уже упоминалось, события не являются частью основного JavaScript — они определены в веб-интерфейсах браузера (<a href="/ru/docs/Web/API">Web API</a>).</p> + +<p>Кроме того, важно понимать, что различные контексты, в которых используется JavaScript, обычно имеют разные модели событий — от веб-API до других областей, таких как браузерные WebExtensions и Node.js (серверный JavaScript). Может сейчас вы не особо в этом разбираетесь, но по мере изучения веб-разработки начнет приходить более ясное понимание тематики.</p> + +<p>Если у вас возникли вопросы, попробуйте прочесть статью снова или <a href="https://developer.mozilla.org/en-US/docs/Learn#Contact_us">обратитесь за помощью к нам</a>.</p> + +<h2 id="См._также">См. также</h2> + +<ul> + <li><a href="http://www.quirksmode.org/js/events_order.html">Event order</a> (обсуждение захвата и всплытий) — превосходно детализированная часть от Peter-Paul Koch.</li> + <li><a href="http://www.quirksmode.org/js/events_access.html">Event accessing</a> (discussing of the event object) — another excellently detailed piece by Peter-Paul Koch.</li> + <li><a href="/en-US/docs/Web/Events">Event reference</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/conditionals">Принятие решений в Вашем коде — условные конструкции</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">Зацикливание кода</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — Переиспользуемые блоки кода</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создайте свою собственную функцию</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Return_values">Возвращаемое значение функции</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/События">Введение в события</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Image_gallery">Создание галереи</a></li> +</ul> + +<div class="s3gt_translate_tooltip_mini_box" id="s3gt_translate_tooltip_mini" style="background: initial !important; border: initial !important; border-radius: initial !important; border-collapse: initial !important; direction: ltr !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; max-width: initial !important; min-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; text-align: initial !important; text-shadow: initial !important; width: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 416px; top: 2989px; opacity: 0.35;"> +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_sound" style="width: 12px; height: 12px; border-radius: 4px;" title="Прослушать"></div> + +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_copy" style="width: 12px; height: 12px; border-radius: 4px;" title="Скопировать текст в буфер обмена"></div> +</div> diff --git a/files/ru/learn/javascript/client-side_web_apis/client-side_storage/index.html b/files/ru/learn/javascript/client-side_web_apis/client-side_storage/index.html new file mode 100644 index 0000000000..114e7821a1 --- /dev/null +++ b/files/ru/learn/javascript/client-side_web_apis/client-side_storage/index.html @@ -0,0 +1,794 @@ +--- +title: Client-side storage +slug: Learn/JavaScript/Client-side_web_APIs/Client-side_storage +translation_of: Learn/JavaScript/Client-side_web_APIs/Client-side_storage +--- +<p>{{LearnSidebar}}</p> + +<div>{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</div> + +<div></div> + +<p class="summary">Современные веб-браузеры поддерживают несколько способов хранения данных из веб-сайтов на компьютере пользователя - с разрешения пользователя - чтобы потом получать их, когда это необходимо. Это позволяет долгосрочно хранить данные, сохранять сайты или документы для использования без подключения к сети, сохранять пользовательские настройки для вашего сайта и многое другое. В этой статье объясняются основы того, как это все работает.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Что нужно знать:</th> + <td>JavaScript basics (see <a href="/en-US/docs/Learn/JavaScript/First_steps">first steps</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">building blocks</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">JavaScript objects</a>), the <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">basics of Client-side APIs</a></td> + </tr> + <tr> + <th scope="row">Цель статьи:</th> + <td>To learn how to use client-side storage APIs to store application data.</td> + </tr> + </tbody> +</table> + +<h2 id="Хранение_данных_на_стороне_клиента">Хранение данных на стороне клиента?</h2> + +<p>Ранее, мы говорили о разнице между <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview#Static_sites">статическими</a> и <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview#Dynamic_sites">динамическими сайтами</a>. Большинство современных веб-сайтов являются динамическими - они хранят данные на сервере, используя какую-то базу данных (серверное хранилище), а затем запускают код <a href="/en-US/docs/Learn/Server-side">на стороне сервера</a> чтобы извлечь необходимые данные, вставить их в шаблоны статических страниц и передать полученный HTML-код клиенту для отображения в браузере пользователя.</p> + +<p>Хранилище на стороне клиента работает по схожим принципам, но используется по-другому. Оно состоит из API-интерфейсов JavaScript, которые позволяют вам хранить данные на клиенте (то есть на компьютере пользователя), а затем извлекать их при необходимости. Это имеет много разных применений, таких как:</p> + +<ul> + <li>Персонализация настроек сайта (например, отображение выбранных пользователем виджетов, цветовой схемы или размера шрифта).</li> + <li>Сохранение предыдущей активности на сайте (например, сохранение содержимого корзины покупок из предыдущего сеанса, запоминание, был ли пользователь ранее авторизован в системе).</li> + <li>Сохранение данных и ресурсов локально, так что сайт будет быстрее (и, возможно, экономичнее) загружаться или использоваться без подключения к сети.</li> + <li>Сохранение созданных веб-приложением документов локально для использования в автономном режиме.</li> +</ul> + +<p>Часто, хранилища на сторонах клиента и сервера используются совместно. К примеру, вы должны загрузить из базы данных пакет музыкальных файлов для веб-игры, или музыкальный плеер хранит их в базе данных на стороне клиента, и воспроизводит по мере необходимости.</p> + +<p>Пользователь должен будет загрузить музыкальные файлы только один раз - при последующих посещениях они будут извлечены из локальной базы данных.</p> + +<div class="note"> +<p><strong>Примечание.</strong> Существуют ограничения на объем данных, которые вы можете хранить с помощью API-интерфейсов на стороне клиента (возможно, как для отдельных API, так и в совокупности). Точный лимит варьируется в зависимости от браузера и, возможно, в зависимости от пользовательских настроек. Смотри <a href="/en-US/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria">Ограничения хранилища браузера и критерии переполнения</a> для большей информации.</p> +</div> + +<h3 id="Старый_подход_куки">Старый подход: куки</h3> + +<p>Концепция хранения на стороне клиента существует уже давно. С первых дней Интернета, использовали <a href="/en-US/docs/Web/HTTP/Cookies">cookies</a> для хранения информации, чтобы персонализировать пользовательский опыт на веб-сайтах. Это самая ранняя форма хранилища на стороне клиента, обычно используемая в Интернете.</p> + +<p>Из-за этого возраста существует ряд проблем - как технических, так и с точки зрения пользовательского опыта - связанных с файлами cookie. Эти проблемы настолько значительны, что при первом посещении сайта людям, живущим в Европе, показываются сообщения, информирующие их о том, будут ли они использовать файлы cookie для хранения данных о них. Это связано с частью законодательства Европейского Союза, известного как <a href="/en-US/docs/Web/HTTP/Cookies#EU_cookie_directive">EU Cookie directive</a>.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15734/cookies-notice.png" style="display: block; margin: 0 auto;"></p> + +<p>По этим причинам мы не будем учить вас, как использовать куки в этой статье. Они устарели, у них множество <a href="/en-US/docs/Web/HTTP/Cookies#Security">проблем с безопастностью</a>, и неспособны хранить сложные данные. При этом существуют лучшие, более современные, способы хранения более широкого спектра данных на компьютере пользователя.</p> + +<p>Единственным преимуществом файлов cookie является то, что они поддерживаются очень старыми браузерами, поэтому, если ваш проект требует, чтобы вы поддерживали устаревшие браузеры (например, Internet Explorer 8 или более ранние версии), файлы cookie могут по-прежнему быть полезными, но для большинства проектов вы не нужно больше прибегать к ним.</p> + +<div class="note"> +<p>Почему по-прежнему создаются новые сайты с использованием файлов cookie? Это происходит главным образом из-за привычек разработчиков, использования старых библиотек, которые всё ещё используют куки-файлы, и наличия множества веб-сайтов, предоставляющих устаревшие справочные и учебные материалы для обучения хранению данных.</p> +</div> + +<h3 id="Новый_подход_Web_Storage_и_IndexedDB">Новый подход: Web Storage и IndexedDB</h3> + +<p>Современные браузеры имеют гораздо более простые и эффективные API для хранения данных на стороне клиента, чем при использовании файлов cookie.</p> + +<ul> + <li>The <a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a> обеспечивает очень простой синтаксис для хранения и извлечения данных, состоящих из пар 'ключ' : 'значение'. Это полезно, когда вам просто нужно сохранить некоторые простые данные, такие как имя пользователя, вошли ли они в систему, какой цвет использовать для фона экрана и т. д.</li> + <li>The <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a> обеспечивает браузер полной базой данных для хранения сложных данных. Это может быть использовано для хранения полных наборов записей клиентов и даже до сложных типов данных, таких как аудио или видео файлы.</li> +</ul> + +<p>Вы узнаете больше об этих API ниже.</p> + +<h3 id="Что_нас_ждёт_в_будущем_Cache_API">Что нас ждёт в будущем: Cache API</h3> + +<p>Некоторые современные браузеры поддерживают новое {{domxref("Cache")}} API. Этот API предназначен для хранения HTTP-ответов на конкретные запросы и очень полезен для таких вещей, как хранение ресурсов сайта в автономном режиме, чтобы впоследствии сайт можно было использовать без сетевого подключения. Cache обычно используется в сочетании с <a href="/en-US/docs/Web/API/Service_Worker_API">Service Worker API</a>, однако это не обязательно.</p> + +<p>Использование Cache и Service Workers - сложная тема, и мы не будем подробно останавливаться на ней в этой статье, хотя приведем простой пример {{anch("Offline asset storage")}} в разделе ниже.</p> + +<h2 id="Хранение_простых_данных_—_web_storage">Хранение простых данных — web storage</h2> + +<p><a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a> очень легко использовать — вы храните простые пары данных имя/значение (только строки, цифры и т.п.) и получаете их, когда необходимо.</p> + +<h3 id="Базовый_синтаксис">Базовый синтаксис</h3> + +<p>Посмотрите:</p> + +<ol> + <li> + <p>Во-первых, посмотрите наши <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/index.html">web storage шаблоны</a> на GitHub (откройте в новой вкладке).</p> + </li> + <li> + <p>Откройте консоль инструментов JavaScript разработчика вашего браузера.</p> + </li> + <li> + <p>Все данные вашего веб-хранилища содержатся в двух объектоподобных структурах внутри браузера: {{domxref("Window.sessionStorage", "sessionStorage")}} и {{domxref("Window.localStorage", "localStorage")}}. Первый сохраняет данные до тех пор, пока браузер открыт (данные теряются при закрытии браузера), а второй сохраняет данные даже после того, как браузер закрыт, а затем снова открыт. Мы будем использовать второй в этой статье, так как он, как правило, более полезен.</p> + + <p>{{domxref("Storage.setItem()")}} метод позволяет сохранить элемент данных в хранилище - он принимает два параметра: имя элемента и его значение. Попробуйте ввести это в свою консоль JavaScript (измените значение на свое собственное имя, если хотите!):</p> + + <pre class="brush: js notranslate">localStorage.setItem('name','Chris');</pre> + </li> + <li> + <p>{{domxref("Storage.getItem()")}} метод принимает один параметр - имя элемента данных, который вы хотите получить - и возвращает значение элемента. Теперь введите эти строки в вашу консоль JavaScript:</p> + + <pre class="brush: js notranslate">var myName = localStorage.getItem('name'); +myName</pre> + + <p>После ввода во второй строке вы должны увидеть, что переменная <code>myName</code> теперь содержит значение элемента данных <code>name</code>.</p> + </li> + <li> + <p>{{domxref("Storage.removeItem()")}} метод принимает один параметр - имя элемента данных, который вы хотите удалить, - и удаляет этот элемент из веб-хранилища. Введите следующие строки в вашу консоль JavaScript:</p> + + <pre class="brush: js notranslate">localStorage.removeItem('name'); +var myName = localStorage.getItem('name'); +myName</pre> + + <p>Третья строка должна теперь возвращать ноль - элемент <code>name</code> больше не существует в веб-хранилище.</p> + </li> +</ol> + +<h3 id="Данные_сохраняются!">Данные сохраняются!</h3> + +<p>Одной из ключевых особенностей веб-хранилища является то, что данные сохраняются между загрузками страниц (и даже в случае закрытия браузера, в случае <code>localStorage</code>). Давайте посмотрим на это в действии.</p> + +<ol> + <li> + <p>Снова откройте пустой шаблон нашего веб-хранилища, но на этот раз в другом браузере, отличном от того, в котором вы открыли этот учебник! Так будет удобнее.</p> + </li> + <li> + <p>Введите эти строки в консоль JavaScript браузера:</p> + + <pre class="brush: js notranslate">localStorage.setItem('name','Chris'); +var myName = localStorage.getItem('name'); +myName</pre> + + <p>Вы должны увидеть возвращенное имя элемента.</p> + </li> + <li> + <p>Теперь закройте браузер и откройте его снова.</p> + </li> + <li> + <p>Введите следующий код:</p> + + <pre class="brush: js notranslate">var myName = localStorage.getItem('name'); +myName</pre> + + <p>Вы должны увидеть, что значение всё ещё доступно, даже после закрытия / открытия браузера.</p> + </li> +</ol> + +<h3 id="Для_каждого_домена_отдельное_хранилище">Для каждого домена отдельное хранилище</h3> + +<p>Существуют отдельные хранилища данных для каждого домена (каждый отдельный веб-адрес загружается в браузер). Вы увидите, что если вы загрузите два веб-сайта (например, google.com и amazon.com) и попытаетесь сохранить элемент на одном веб-сайте, он не будет доступен для другого веб-сайта.</p> + +<p>Это имеет смысл - вы можете представить себе проблемы безопасности, которые могут возникнуть, если веб-сайты смогут видеть данные друг друга!</p> + +<h3 id="Более_развернутый_пример">Более развернутый пример</h3> + +<p>Давайте применим эти новые знания, написав простой рабочий пример, чтобы дать вам представление о том, как можно использовать веб-хранилище. Наш пример позволит вам ввести имя, после чего страница обновится, чтобы дать вам персональное приветствие. Это состояние также будет сохраняться при перезагрузке страницы / браузера, поскольку имя хранится в веб-хранилище.</p> + +<p>Вы можете найти пример HTML на <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/web-storage/personal-greeting.html">personal-greeting.html</a> — он содержит простой веб-сайт с заголовком, контентом и нижним колонтитулом, а также форму для ввода вашего имени.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15735/web-storage-demo.png" style="display: block; margin: 0 auto;"></p> + +<p>Давайте создадим пример, чтобы вы могли понять, как он работает.</p> + +<ol> + <li> + <p>Во-первых, сделайте локальную копию нашего <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/web-storage/personal-greeting.html">personal-greeting.html</a> файла в новом каталоге на вашем компьютере.</p> + </li> + <li> + <p>Далее обратите внимание, как наш HTML ссылается на файл JavaScript с именем <code>index.js</code> (см. строку 40). Нам нужно создать его, и записать в него наш код JavaScript. Создайте файл <code>index.js</code> в том же каталоге, что и ваш HTML-файл.</p> + </li> + <li> + <p>Мы начнем с создания ссылок на все функции HTML, которыми мы должны манипулировать в этом примере - мы создадим их все как константы, поскольку эти ссылки не нужно изменять в жизненном цикле приложения. Добавьте следующие строки в ваш файл JavaScript:</p> + + <pre class="brush: js notranslate">// create needed constants +const rememberDiv = document.querySelector('.remember'); +const forgetDiv = document.querySelector('.forget'); +const form = document.querySelector('form'); +const nameInput = document.querySelector('#entername'); +const submitBtn = document.querySelector('#submitname'); +const forgetBtn = document.querySelector('#forgetname'); + +const h1 = document.querySelector('h1'); +const personalGreeting = document.querySelector('.personal-greeting');</pre> + </li> + <li> + <p>Далее нам нужно включить небольшой прослушиватель событий, чтобы форма фактически не отправляла себя при нажатии кнопки отправки, так как это не то поведение, которое нам нужно. Добавьте этот фрагмент ниже вашего предыдущего кода:</p> + + <pre class="brush: js notranslate">// Stop the form from submitting when a button is pressed +form.addEventListener('submit', function(e) { + e.preventDefault(); +});</pre> + </li> + <li> + <p>Теперь нам нужно добавить прослушиватель событий, функция-обработчик которого будет запускаться при нажатии кнопки «Say hello». В комментариях подробно объясняется, что делает каждый бит, но в сущности здесь мы берем имя, которое пользователь ввел в поле ввода текста, и сохраняем его в веб-хранилище с помощью <code>setItem()</code>, затем запускаем функцию <code>nameDisplayCheck()</code>, которая будет обрабатывать обновление фактического текста сайта. Добавьте это в конец: </p> + + <pre class="brush: js notranslate">// run function when the 'Say hello' button is clicked +submitBtn.addEventListener('click', function() { + // store the entered name in web storage + localStorage.setItem('name', nameInput.value); + // run nameDisplayCheck() to sort out displaying the + // personalized greetings and updating the form display + nameDisplayCheck(); +});</pre> + </li> + <li> + <p>На этом этапе нам также необходим прослушиватель событий для запуска функции при нажатии кнопки «Forget» — она будет отображена только после того как кнопка «Say hello» будет нажата (две формы состояния для переключения между ними). В этой функции мы удаляем переменную <code>name</code> из веб-хранилища используя <code>removeItem()</code>, затем снова запускаем <code>nameDisplayCheck()</code> для обновления. Добавьте этот код в конец:</p> + + <pre class="brush: js notranslate">// run function when the 'Forget' button is clicked +forgetBtn.addEventListener('click', function() { + // Remove the stored name from web storage + localStorage.removeItem('name'); + // run nameDisplayCheck() to sort out displaying the + // generic greeting again and updating the form display + nameDisplayCheck(); +});</pre> + </li> + <li> + <p>Самое время для определения самой функции <code>nameDisplayCheck()</code>. Здесь мы проверяем была ли переменная <code>name</code> сохранена в веб-хранилище с помощью <code>localStorage.getItem('name')</code> в качестве условия. Если переменная <code>name</code> была сохранена, то вызов вернёт - <code>true</code>; если же нет, то - <code>false</code>. Если <code>true</code>, мы показываем персональное приветствие, отображаем кнопку «Forget», и скрываем кнопку «Say hello». Если же <code>false</code>, мы отображаем общее приветствие и делаем обратное. Опять же, добавьте следующий код в конец:</p> + + <pre class="brush: js notranslate">// define the nameDisplayCheck() function +function nameDisplayCheck() { + // check whether the 'name' data item is stored in web Storage + if(localStorage.getItem('name')) { + // If it is, display personalized greeting + let name = localStorage.getItem('name'); + h1.textContent = 'Welcome, ' + name; + personalGreeting.textContent = 'Welcome to our website, ' + name + '! We hope you have fun while you are here.'; + // hide the 'remember' part of the form and show the 'forget' part + forgetDiv.style.display = 'block'; + rememberDiv.style.display = 'none'; + } else { + // if not, display generic greeting + h1.textContent = 'Welcome to our website '; + personalGreeting.textContent = 'Welcome to our website. We hope you have fun while you are here.'; + // hide the 'forget' part of the form and show the 'remember' part + forgetDiv.style.display = 'none'; + rememberDiv.style.display = 'block'; + } +}</pre> + </li> + <li> + <p>Последнее но не менее важное, нам необходимо запускать функцию <code>nameDisplayCheck()</code> при каждой загрузке страницы. Если мы не сделаем этого, персональное приветствие не будет сохранятся после перезагрузки страницы. Добавьте следующий фрагмент в конец вашего кода:</p> + + <pre class="brush: js notranslate">document.body.onload = nameDisplayCheck;</pre> + </li> +</ol> + +<p>Ваш пример закончен — отличная работа! Всё что теперь осталось это сохранить ваш код и протестировать вашу HTML страницу в браузере. Вы можете посмотреть нашу <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/personal-greeting.html">завершённую версию работающую здесь</a>.</p> + +<div class="note"> +<p>Есть и другой, немного более комплексный пример описываемый в <a href="/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API">Using the Web Storage API</a>.</p> +</div> + +<h2 id="Храним_более_сложную_информацию_в_IndexedDB">Храним более сложную информацию в IndexedDB</h2> + +<p><a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a> (иногда сокращают до IDB) это полная база данных, доступная в браузере, в которой вы можете хранить сложные связанные данные, типы которых не ограничиваются простыми значениями, такими как строки или числа.</p> + +<p>Вы можете сохранить видео, фото, и почти все остальные файлы с IndexedDB. </p> + +<p dir="ltr" id="tw-target-text">Однако это обходится дорого: IndexedDB гораздо сложнее в использовании, чем Web Storage API.</p> + +<p dir="ltr" id="tw-target-text">В этом разделе мы действительно только коснемся того, на что он способен, но мы дадим вам достаточно, чтобы начать.</p> + +<h3 dir="ltr" id="Работа_с_примером_хранения_заметок">Работа с примером хранения заметок</h3> + +<p>Here we'll run you through an example that allows you to store notes in your browser and view and delete them whenever you like, getting you to build it up for yourself and explaining the most fundamental parts of IDB as we go along.</p> + +<p>The app looks something like this:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15744/idb-demo.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>Each note has a title and some body text, each individually editable. The JavaScript code we'll go through below has detailed comments to help you understand what's going on.</p> + +<h3 id="Предустановка">Предустановка</h3> + +<ol> + <li>First of all, make local copies of our <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index.html">index.html</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/style.css">style.css</a></code>, and <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index-start.js">index-start.js</a></code> files into a new directory on your local machine.</li> + <li>Have a look at the files. You'll see that the HTML is pretty simple: a web site with a header and footer, as well as a main content area that contains a place to display notes, and a form for entering new notes into the database. The CSS provides some simple styling to make it clearer what is going on. The JavaScript file contains five declared constants containing references to the {{htmlelement("ul")}} element the notes will be displayed in, the title and body {{htmlelement("input")}} elements, the {{htmlelement("form")}} itself, and the {{htmlelement("button")}}.</li> + <li>Rename your JavaScript file to <code>index.js</code>. You are now ready to start adding code to it.</li> +</ol> + +<h3 id="Настраиваем_базу_данных">Настраиваем базу данных</h3> + +<p>Now let's look at what we have to do in the first place, to actually set up a database.</p> + +<ol> + <li> + <p>Below the constant declarations, add the following lines:</p> + + <pre class="brush: js notranslate">// Create an instance of a db object for us to store the open database in +let db;</pre> + + <p>Here we are declaring a variable called <code>db</code> — this will later be used to store an object representing our database. We will use this in a few places, so we've declared it globally here to make things easier.</p> + </li> + <li> + <p>Next, add the following to the bottom of your code:</p> + + <pre class="brush: js notranslate">window.onload = function() { + +};</pre> + + <p>We will write all of our subsequent code inside this <code>window.onload</code> event handler function, called when the window's {{event("load")}} event fires, to make sure we don't try to use IndexedDB functionality before the app has completely finished loading (it could fail if we don't).</p> + </li> + <li> + <p>Inside the <code>window.onload</code> handler, add the following:</p> + + <pre class="brush: js notranslate">// Open our database; it is created if it doesn't already exist +// (see onupgradeneeded below) +let request = window.indexedDB.open('notes', 1);</pre> + + <p>This line creates a <code>request</code> to open version <code>1</code> of a database called <code>notes</code>. If this doesn't already exist, it will be created for you by subsequent code. You will see this request pattern used very often throughout IndexedDB. Database operations take time. You don't want to hang the browser while you wait for the results, so database operations are {{Glossary("asynchronous")}}, meaning that instead of happening immediately, they will happen at some point in the future, and you get notified when they're done.</p> + + <p>To handle this in IndexedDB, you create a request object (which can be called anything you like — we called it <code>request</code> so it is obvious what it is for). You then use event handlers to run code when the request completes, fails, etc., which you'll see in use below.</p> + + <div class="note"> + <p><strong>Note</strong>: The version number is important. If you want to upgrade your database (for example, by changing the table structure), you have to run your code again with an increased version number, different schema specified inside the <code>onupgradeneeded</code> handler (see below), etc. We won't cover upgrading databases in this simple tutorial.</p> + </div> + </li> + <li> + <p>Now add the following event handlers just below your previous addition — again inside the <code>window.onload</code> handler:</p> + + <pre class="brush: js notranslate">// onerror handler signifies that the database didn't open successfully +request.onerror = function() { + console.log('Database failed to open'); +}; + +// onsuccess handler signifies that the database opened successfully +request.onsuccess = function() { + console.log('Database opened successfully'); + + // Store the opened database object in the db variable. This is used a lot below + db = request.result; + + // Run the displayData() function to display the notes already in the IDB + displayData(); +};</pre> + + <p>The {{domxref("IDBRequest.onerror", "request.onerror")}} handler will run if the system comes back saying that the request failed. This allows you to respond to this problem. In our simple example, we just print a message to the JavaScript console.</p> + + <p>The {{domxref("IDBRequest.onsuccess", "request.onsuccess")}} handler on the other hand will run if the request returns successfully, meaning the database was successfully opened. If this is the case, an object representing the opened database becomes available in the {{domxref("IDBRequest.result", "request.result")}} property, allowing us to manipulate the database. We store this in the <code>db</code> variable we created earlier for later use. We also run a custom function called <code>displayData()</code>, which displays the data in the database inside the {{HTMLElement("ul")}}. We run it now so that the notes already in the database are displayed as soon as the page loads. You'll see this defined later on.</p> + </li> + <li> + <p>Finally for this section, we'll add probably the most important event handler for setting up the database: {{domxref("IDBOpenDBRequest.onupgradeneeded", "request.onupdateneeded")}}. This handler runs if the database has not already been set up, or if the database is opened with a bigger version number than the existing stored database (when performing an upgrade). Add the following code, below your previous handler:</p> + + <pre class="brush: js notranslate">// Setup the database tables if this has not already been done +request.onupgradeneeded = function(e) { + // Grab a reference to the opened database + let db = e.target.result; + + // Create an objectStore to store our notes in (basically like a single table) + // including a auto-incrementing key + let objectStore = db.createObjectStore('notes', { keyPath: 'id', autoIncrement:true }); + + // Define what data items the objectStore will contain + objectStore.createIndex('title', 'title', { unique: false }); + objectStore.createIndex('body', 'body', { unique: false }); + + console.log('Database setup complete'); +};</pre> + + <p>This is where we define the schema (structure) of our database; that is, the set of columns (or fields) it contains. Here we first grab a reference to the existing database from <code>e.target.result</code> (the event target's <code>result</code> property), which is the <code>request</code> object. This is equivalent to the line <code>db = request.result;</code> inside the <code>onsuccess</code> handler, but we need to do this separately here because the <code>onupgradeneeded</code> handler (if needed) will run before the <code>onsuccess</code> handler, meaning that the <code>db</code> value wouldn't be available if we didn't do this.</p> + + <p>We then use {{domxref("IDBDatabase.createObjectStore()")}} to create a new object store inside our opened database. This is equivalent to a single table in a conventional database system. We've given it the name notes, and also specified an <code>autoIncrement</code> key field called <code>id</code> — in each new record this will automatically be given an incremented value — the developer doesn't need to set this explicitly. Being the key, the <code>id</code> field will be used to uniquely identify records, such as when deleting or displaying a record.</p> + + <p>We also create two other indexes (fields) using the {{domxref("IDBObjectStore.createIndex()")}} method: <code>title</code> (which will contain a title for each note), and <code>body</code> (which will contain the body text of the note).</p> + </li> +</ol> + +<p>So with this simple database schema set up, when we start adding records to the database each one will be represented as an object along these lines:</p> + +<pre class="brush: js notranslate"><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-object"><span class="objectLeftBrace">{ + </span><span class="nodeName">title</span><span class="objectEqual">: </span><span class="objectBox objectBox-string">"Buy milk"</span>, + <span class="nodeName">body</span><span class="objectEqual">: </span><span class="objectBox objectBox-string">"Need both cows milk and soya."</span>, + <span class="nodeName">id</span><span class="objectEqual">: </span><span class="objectBox objectBox-number">8</span></span></span></span></span><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-object"><span class="objectRightBrace"> +}</span></span></span></span></span></pre> + +<h3 id="Добавляем_данные_в_базу_данных">Добавляем данные в базу данных</h3> + +<p>Now let's look at how we can add records to the database. This will be done using the form on our page.</p> + +<p>Below your previous event handler (but still inside the <code>window.onload</code> handler), add the following line, which sets up an <code>onsubmit</code> handler that runs a function called <code>addData()</code> when the form is submitted (when the submit {{htmlelement("button")}} is pressed leading to a successful form submission):</p> + +<pre class="brush: js notranslate">// Create an onsubmit handler so that when the form is submitted the addData() function is run +form.onsubmit = addData;</pre> + +<p>Now let's define the <code>addData()</code> function. Add this below your previous line:</p> + +<pre class="brush: js notranslate">// Define the addData() function +function addData(e) { + // prevent default - we don't want the form to submit in the conventional way + e.preventDefault(); + + // grab the values entered into the form fields and store them in an object ready for being inserted into the DB + let newItem = { title: titleInput.value, body: bodyInput.value }; + + // open a read/write db transaction, ready for adding the data + let transaction = db.transaction(['notes'], 'readwrite'); + + // call an object store that's already been added to the database + let objectStore = transaction.objectStore('notes'); + + // Make a request to add our newItem object to the object store + var request = objectStore.add(newItem); + request.onsuccess = function() { + // Clear the form, ready for adding the next entry + titleInput.value = ''; + bodyInput.value = ''; + }; + + // Report on the success of the transaction completing, when everything is done + transaction.oncomplete = function() { + console.log('Transaction completed: database modification finished.'); + + // update the display of data to show the newly added item, by running displayData() again. + displayData(); + }; + + transaction.onerror = function() { + console.log('Transaction not opened due to error'); + }; +}</pre> + +<p>This is quite complex; breaking it down, we:</p> + +<ul> + <li>Run {{domxref("Event.preventDefault()")}} on the event object to stop the form actually submitting in the conventional manner (this would cause a page refresh and spoil the experience).</li> + <li>Create an object representing a record to enter into the database, populating it with values from the form inputs. note that we don't have to explicitly include an <code>id</code> value — as we expained early, this is auto-populated.</li> + <li>Open a <code>readwrite</code> transaction against the <code>notes</code> object store using the {{domxref("IDBDatabase.transaction()")}} method. This transaction object allows us to access the object store so we can do something to it, e.g. add a new record.</li> + <li>Access the object store using the {{domxref("IDBTransaction.objectStore")}} property, saving it in the <code>objectStore</code> variable.</li> + <li>Add the new record to the database using {{domxref("IDBObjectStore.add()")}}. This creates a request object, in the same fashion as we've seen before.</li> + <li>Add a bunch of event handlers to the <code>request</code> and the <code>transaction</code> to run code at critical points in the lifecycle. Once the request has succeeded, we clear the form inputs ready for entering the next note. Once the transaction has completed, we run the <code>displayData()</code> function again to update the display of notes on the page.</li> +</ul> + +<h3 id="Отображаем_данные">Отображаем данные</h3> + +<p>We've referenced <code>displayData()</code> twice in our code already, so we'd probably better define it. Add this to your code, below the previous function definition:</p> + +<pre class="brush: js notranslate">// Define the displayData() function +function displayData() { + // Here we empty the contents of the list element each time the display is updated + // If you ddn't do this, you'd get duplicates listed each time a new note is added + while (list.firstChild) { + list.removeChild(list.firstChild); + } + + // Open our object store and then get a cursor - which iterates through all the + // different data items in the store + let objectStore = db.transaction('notes').objectStore('notes'); + objectStore.openCursor().onsuccess = function(e) { + // Get a reference to the cursor + let cursor = e.target.result; + + // If there is still another data item to iterate through, keep running this code + if(cursor) { + // Create a list item, h3, and p to put each data item inside when displaying it + // structure the HTML fragment, and append it inside the list + let listItem = document.createElement('li'); + let h3 = document.createElement('h3'); + let para = document.createElement('p'); + + listItem.appendChild(h3); + listItem.appendChild(para); + list.appendChild(listItem); + + // Put the data from the cursor inside the h3 and para + h3.textContent = cursor.value.title; + para.textContent = cursor.value.body; + + // Store the ID of the data item inside an attribute on the listItem, so we know + // which item it corresponds to. This will be useful later when we want to delete items + listItem.setAttribute('data-note-id', cursor.value.id); + + // Create a button and place it inside each listItem + let deleteBtn = document.createElement('button'); + listItem.appendChild(deleteBtn); + deleteBtn.textContent = 'Delete'; + + // Set an event handler so that when the button is clicked, the deleteItem() + // function is run + deleteBtn.onclick = function(e) { + deleteItem(e); + }; + + // Iterate to the next item in the cursor + cursor.continue(); + } else { + // Again, if list item is empty, display a 'No notes stored' message + if(!list.firstChild) { + let listItem = document.createElement('li'); + listItem.textContent = 'No notes stored.' + list.appendChild(listItem); + } + // if there are no more cursor items to iterate through, say so + console.log('Notes all displayed'); + } + }; +}</pre> + +<p>Again, let's break this down:</p> + +<ul> + <li>First we empty out the {{htmlelement("ul")}} element's content, before then filling it with the updated content. If you didn't do this, you'd end up with a huge list of duplicated content being added to with each update.</li> + <li>Next, we get a reference to the <code>notes</code> object store using {{domxref("IDBDatabase.transaction()")}} and {{domxref("IDBTransaction.objectStore")}} like we did in <code>addData()</code>, except here we are chaining them together in one line.</li> + <li>The next step is to use {{domxref("IDBObjectStore.openCursor()")}} method to open a request for a cursor — this is a construct that can be used to iterate over the records in an object store. We chain an <code>onsuccess</code> handler on to the end of this line to make the code more concise — when the cursor is successfully returned, the handler is run.</li> + <li>We get a reference to the cursor itself (an {{domxref("IDBCursor")}} object) using let <code>cursor = e.target.result</code>.</li> + <li>Next, we check to see if the cursor contains a record from the datastore (<code>if(cursor){ ... }</code>) — if so, we create a DOM fragment, populate it with the data from the record, and insert it into the page (inside the <code><ul></code> element). We also include a delete button that, when clicked, will delete that note by running the <code>deleteItem()</code> function, which we will look at in the next section.</li> + <li>At the end of the <code>if</code> block, we use the {{domxref("IDBCursor.continue()")}} method to advance the cursor to the next record in the datastore, and run the content of the <code>if</code> block again. If there is another record to iterate to, this causes it to be inserted into the page, and then <code>continue()</code> is run again, and so on.</li> + <li>When there are no more records to iterate over, <code>cursor</code> will return <code>undefined</code>, and therefore the <code>else</code> block will run instead of the <code>if</code> block. This block checks whether any notes were inserted into the <code><ul></code> — if not, it inserts a message to say no note was stored.</li> +</ul> + +<h3 id="Удаляем_данные">Удаляем данные</h3> + +<p>As stated above, when a note's delete button is pressed, the note is deleted. This is achieved by the <code>deleteItem()</code> function, which looks like so:</p> + +<pre class="brush: js notranslate">// Define the deleteItem() function +function deleteItem(e) { + // retrieve the name of the task we want to delete. We need + // to convert it to a number before trying it use it with IDB; IDB key + // values are type-sensitive. + let noteId = Number(e.target.parentNode.getAttribute('data-note-id')); + + // open a database transaction and delete the task, finding it using the id we retrieved above + let transaction = db.transaction(['notes'], 'readwrite'); + let objectStore = transaction.objectStore('notes'); + let request = objectStore.delete(noteId); + + // report that the data item has been deleted + transaction.oncomplete = function() { + // delete the parent of the button + // which is the list item, so it is no longer displayed + e.target.parentNode.parentNode.removeChild(e.target.parentNode); + console.log('Note ' + noteId + ' deleted.'); + + // Again, if list item is empty, display a 'No notes stored' message + if(!list.firstChild) { + let listItem = document.createElement('li'); + listItem.textContent = 'No notes stored.'; + list.appendChild(listItem); + } + }; +}</pre> + +<ul> + <li>The first part of this could use some explaining — we retrieve the ID of the record to be deleted using <code>Number(e.target.parentNode.getAttribute('data-note-id'))</code> — recall that the ID of the record was saved in a <code>data-note-id</code> attribute on the <code><li></code> when it was first displayed. We do however need to pass the attribute through the global built-in <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">Number()</a> object, as it is currently a string, and otherwise won't be recognized by the database.</li> + <li>We then get a reference to the object store using the same pattern we've seen previously, and use the {{domxref("IDBObjectStore.delete()")}} method to delete the record from the database, passing it the ID.</li> + <li>When the database transaction is complete, we delete the note's <code><li></code> from the DOM, and again do the check to see if the <code><ul></code> is now empty, inserting a note as appropriate.</li> +</ul> + +<p>So that's it! Your example should now work.</p> + +<p>If you are having trouble with it, feel free to <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/notes/">check it against our live example</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index.js">source code</a> also).</p> + +<h3 id="Храним_сложные_данные_через_IndexedDB">Храним сложные данные через IndexedDB</h3> + +<p>As we mentioned above, IndexedDB can be used to store more than just simple text strings. You can store just about anything you want, including complex objects such as video or image blobs. And it isn't much more difficult to achieve than any other type of data.</p> + +<p>To demonstrate how to do it, we've written another example called <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/client-side-storage/indexeddb/video-store">IndexedDB video store</a> (see it <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/video-store/">running live here also</a>). When you first run the example, it downloads all the videos from the network, stores them in an IndexedDB database, and then displays the videos in the UI inside {{htmlelement("video")}} elements. The second time you run it, it finds the videos in the database and gets them from there instead befoire displaying them — this makes subsequent loads much quicker and less bandwidth-hungry.</p> + +<p>Let's walk through the most interesting parts of the example. We won't look at it all — a lot of it is similar to the previous example, and the code is well-commented.</p> + +<ol> + <li> + <p>For this simple example, we've stored the names of the videos to fetch in an array of objects:</p> + + <pre class="brush: js notranslate">const videos = [ + { 'name' : 'crystal' }, + { 'name' : 'elf' }, + { 'name' : 'frog' }, + { 'name' : 'monster' }, + { 'name' : 'pig' }, + { 'name' : 'rabbit' } +];</pre> + </li> + <li> + <p>To start with, once the database is successfully opened we run an <code>init()</code> function. This loops through the different video names, trying to load a record identified by each name from the <code>videos</code> database.</p> + + <p>If each video is found in the database (easily checked by seeing whether <code>request.result</code> evaluates to <code>true</code> — if the record is not present, it will be <code>undefined</code>), its video files (stored as blobs) and the video name are passed straight to the <code>displayVideo()</code> function to place them in the UI. If not, the video name is passed to the <code>fetchVideoFromNetwork()</code> function to ... you guessed it — fetch the video from the network.</p> + + <pre class="brush: js notranslate">function init() { + // Loop through the video names one by one + for(let i = 0; i < videos.length; i++) { + // Open transaction, get object store, and get() each video by name + let objectStore = db.transaction('videos').objectStore('videos'); + let request = objectStore.get(videos[i].name); + request.onsuccess = function() { + // If the result exists in the database (is not undefined) + if(request.result) { + // Grab the videos from IDB and display them using displayVideo() + console.log('taking videos from IDB'); + displayVideo(request.result.mp4, request.result.webm, request.result.name); + } else { + // Fetch the videos from the network + fetchVideoFromNetwork(videos[i]); + } + }; + } +}</pre> + </li> + <li> + <p>The following snippet is taken from inside <code>fetchVideoFromNetwork()</code> — here we fetch MP4 and WebM versions of the video using two separate {{domxref("fetch()", "WindowOrWorkerGlobalScope.fetch()")}} requests. We then use the {{domxref("blob()", "Body.blob()")}} method to extract each response's body as a blob, giving us an object representation of the videos that can be stored and displayed later on.</p> + + <p>We have a problem here though — these two requests are both asynchronous, but we only want to try to display or store the video when both promises have fulfilled. Fortunately there is a built-in method that handles such a problem — {{jsxref("Promise.all()")}}. This takes one argument — references to all the individual promises you want to check for fulfillment placed in an array — and is itself promise-based.</p> + + <p>When all those promises have fulfilled, the <code>all()</code> promise fulfills with an array containing all the individual fulfillment values. Inside the <code>all()</code> block, you can see that we then call the <code>displayVideo()</code> function like we did before to display the videos in the UI, then we also call the <code>storeVideo()</code> function to store those videos inside the database.</p> + + <pre class="brush: js notranslate">let mp4Blob = fetch('videos/' + video.name + '.mp4').then(response => + response.blob() +); +let webmBlob = fetch('videos/' + video.name + '.webm').then(response => + response.blob() +);; + +// Only run the next code when both promises have fulfilled +Promise.all([mp4Blob, webmBlob]).then(function(values) { + // display the video fetched from the network with displayVideo() + displayVideo(values[0], values[1], video.name); + // store it in the IDB using storeVideo() + storeVideo(values[0], values[1], video.name); +});</pre> + </li> + <li> + <p>Let's look at <code>storeVideo()</code> first. This is very similar to the pattern you saw in the previous example for adding data to the database — we open a <code>readwrite</code> transaction and get an object store reference our <code>videos</code>, create an object representing the record to add to the database, then simply add it using {{domxref("IDBObjectStore.add()")}}.</p> + + <pre class="brush: js notranslate">function storeVideo(mp4Blob, webmBlob, name) { + // Open transaction, get object store; make it a readwrite so we can write to the IDB + let objectStore = db.transaction(['videos'], 'readwrite').objectStore('videos'); + // Create a record to add to the IDB + let record = { + mp4 : mp4Blob, + webm : webmBlob, + name : name + } + + // Add the record to the IDB using add() + let request = objectStore.add(record); + + ... + +};</pre> + </li> + <li> + <p>Last but not least, we have <code>displayVideo()</code>, which creates the DOM elements needed to insert the video in the UI and then appends them to the page. The most interesting parts of this are those shown below — to actually display our video blobs in a <code><video></code> element, we need to create object URLs (internal URLs that point to the video blobs stored in memory) using the {{domxref("URL.createObjectURL()")}} method. Once that is done, we can set the object URLs to be the vaues of our {{htmlelement("source")}} element's <code>src</code> attributes, and it works fine.</p> + + <pre class="brush: js notranslate">function displayVideo(mp4Blob, webmBlob, title) { + // Create object URLs out of the blobs + let mp4URL = URL.createObjectURL(mp4Blob); + let webmURL = URL.createObjectURL(webmBlob); + + ... + + let video = document.createElement('video'); + video.controls = true; + let source1 = document.createElement('source'); + source1.src = mp4URL; + source1.type = 'video/mp4'; + let source2 = document.createElement('source'); + source2.src = webmURL; + source2.type = 'video/webm'; + + ... +}</pre> + </li> +</ol> + +<h2 id="Оффлайн_хранение_данных">Оффлайн хранение данных</h2> + +<p>Пример ниже показывает, как создать приложение, которое будет хранить данные большого объема в хранилище IndexedDB, избегая необходимости скачивать их повторно. Это важное улучшение пользовательского опыта, но есть одно замечание — основной HTML, CSS, и файлы JavaScript все еще нужно загружать каждый раз при запросе сайта, это значит, что данный пример не будет работать при отсутствии сетевого соединения.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15759/ff-offline.png" style="border-style: solid; border-width: 1px; display: block; height: 307px; margin: 0px auto; width: 765px;"></p> + +<p>Это тот случай, когда <a href="/en-US/docs/Web/API/Service_Worker_API">Service workers</a> и <a href="/en-US/docs/Web/API/Cache">Cache API</a> приходят на помощь.</p> + +<p>Сервис-воркер это файл JavaScript, который регистрируется на конкретном источнике (веб-сайте или части сайта на конкретном домене) при обращении браузером. После регистрации, он может управлять страницами на этом источнике. Воркер находится между загруженной страницей и сетевым соединением, перехватывая сетевые запросы источника.</p> + +<p>Когда worker перехватывает запрос, он может делать многие вещи (смотри <a href="/en-US/docs/Web/API/Service_Worker_API#Other_use_case_ideas">идеи для использования сервис-воркеров</a>), но классический пример это сохранение сетевых ответов и затем доступ к ним при запросе, вместо запросов по сети. В результате, это позволяет сделать веб-сайт полностью работающим в офлайне.</p> + +<p><a href="/en-US/docs/Web/API/Cache">Cache API</a> это еще один механизм хранения данных на клиенте с небольшим отличием — он разработан для хранения HTTP ответов, и прекрасно работает с сервис-воркерами.</p> + +<div class="note"> +<p><strong>Note</strong>: Service workers и Cache доступны в большинстве современных браузеров. В момент написания статьи, Safari еще не имел реализации, но скоро должна быть.</p> +</div> + +<h3 id="Пример_сервис_воркера">Пример сервис воркера</h3> + +<p>Давайте взглянем на пример, чтобы дать вам немного мыслей о том, что из этого может выйти. Мы создали другую версию примера хранения видео, который использовался в предыдущей секции — эта функциональность идентична, за исключением того, что этот пример также сохраняет HTML, CSS, и JavaScript в Cache API посредством сервис-воркеров, что позволяет приложению работать полностью в офлайне!</p> + +<p>Смотри пример <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/">хранилище видео с IndexedDB и сервис-воркером</a>, и его <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/client-side-storage/cache-sw/video-store-offline">исходный код</a>.</p> + +<h4 id="Регистрируем_сервис_воркер">Регистрируем сервис воркер</h4> + +<p>Первое, что нужно заметить, это дополнительный кусок кода, расположенный в основном JavaScript файле (см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js">index.js</a>). Первое,что мы делаем, это проверка на то, что <code>serviceWorker</code> доступен в объекте {{domxref("Navigator")}}. Если этот так, тогда мы знаем, что как минимум, базовые функции сервис-воркера доступны. Внутри проверки мы используем метод {{domxref("ServiceWorkerContainer.register()")}} для регистрации сервис-воркера, находящегося в файле <code>sw.js</code> на текущем источнике, таким образом, он может управлять страницами в текущей или внутренних директориях. Когда обещание выполнится, сервис-воркер считается зарегистрированным.</p> + +<pre class="brush: js notranslate"> // Регистрация сервис-воркера для обеспечения оффлайн доступности сайта + + if('serviceWorker' in navigator) { + navigator.serviceWorker + .register('/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js') + .then(function() { console.log('Service Worker зарегистрирован'); }); + }</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Путь к файлу <code>sw.js</code> указан относительно корня сайта, а не JavaScript файла, содержащего основной код. Полный путь - <code>https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. Корень - <code>https://mdn.github.io</code>, и следовательно указываемый путь должен быть <code>/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. Если вы хотите использовать данный пример на своем сервере, вы также должны изменить путь к скрипту. Это довольно запутанно, но обязано так работать по причинам безопасности.</p> +</div> + +<h4 id="Устанавливаем_сервис_воркер">Устанавливаем сервис воркер</h4> + +<p>В следующий раз, когда страница с сервис-воркером будет запрошена (например когда страница будет перезагружена), сервис-воркер запустится на этой странице и начнет контролировать её. Когда это произойдет, событие <code>install</code> будет вызвано в сервис-воркере; вы можете написать код внутри сервис-воркера, который будет вызван в процессе установки.</p> + +<p>Давайте взглянем на файл сервис-воркера <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js">sw.js</a>. Вы можете видеть, что слушатель события <code>install</code> зарегистрирован на <code>self</code>. Ключевое слово <code>self</code> это способ ссылки на глобальную область видимости сервис-воркера из файла с сервис-воркером.</p> + +<p>Внутри обработчика <code>install</code> мы используем метод {{domxref("ExtendableEvent.waitUntil()")}}, доступном в объекте события, чтобы сигнализировать, что работа продолжается, и браузер не должен завершать установку, пока все задачи внутри блока не будут выполнены.</p> + +<p>Здесь мы видим Cache API в действии. Мы используем метод {{domxref("CacheStorage.open()")}} для открытия нового объекта кэша, в котором ответы могут быть сохранены (похоже на объект хранилища IndexedDB). Обещание выполнится с объектом {{domxref("Cache")}}, представляющим собой кэш <code>video-store</code> . Затем мы используем метод {{domxref("Cache.addAll()")}} для получения ресурсов и добавления ответов в кэш.</p> + +<pre class="brush: js notranslate">self.addEventListener('install', function(e) { + e.waitUntil( + caches.open('video-store').then(function(cache) { + return cache.addAll([ + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/', + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.html', + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js', + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/style.css' + ]); + }) + ); +});</pre> + +<p>На этом установка завершена.</p> + +<h4 id="Отвечаем_на_последующие_запросы">Отвечаем на последующие запросы</h4> + +<p>Когда сервис-воркер зарегистрирован и установлен на странице HTML и сопутствующие ресурсы добавлены в кэш, все практически готово. Нужно сделать еще одну вещь - написать код для ответа на дальнейшие сетевые запросы.</p> + +<p>Это то, что делает вторая часть кода файла <code>sw.js</code>. Мы добавили еще один слушатель к сервис-воркеру в глобальной области видимости, который запускает функцию-обработчик при событии <code>fetch</code>. Это происходит всякий раз, когда браузер делает запрос ресурса в директорию, где зарегистрирован сервис-воркер.</p> + +<p>Внутри обработчика, мы сначала выводим в консоль URL запрашиваемого ресурса. Затем отдаем особый ответ на запрос, используя метод {{domxref("FetchEvent.respondWith()")}}.</p> + +<p>Внутри блока мы используем {{domxref("CacheStorage.match()")}} чтобы проверить, можно ли найти соответствующий запрос (т.е. совпадение по URL) в кэше. Обещание возвращает найденный ответ или <code>undefined</code>, если ничего не нашлось.</p> + +<p>Если совпадение нашлось, то просто возвращаем его как особый ответ. В противном случае, используем <a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a> для запроса ресурса из сети.</p> + +<pre class="brush: js notranslate">self.addEventListener('fetch', function(e) { + console.log(e.request.url); + e.respondWith( + caches.match(e.request).then(function(response) { + return response || fetch(e.request); + }) + ); +});</pre> + +<p>На этом все для нашего простого сервис-воркера. Используя подобный метод, вы можете сделать гораздо больше вещей — для получения доп. информации смотрите <a href="https://serviceworke.rs/">рецепты использования сервис-воркеров</a>. Спасибо Paul Kinlan за его статью <a href="https://developers.google.com/web/fundamentals/codelabs/offline/">Adding a Service Worker and Offline into your Web App</a>, которая вдохновила на написание данного примера.</p> + +<h4 id="Тестируем_наш_пример_оффлайн">Тестируем наш пример оффлайн</h4> + +<p>Для тестирования <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/">примера</a>, вам нужно загрузить его несколько раз, чтобы быть уверенным, что сервис-воркер точно установлен. Когда это сделано, вы можете:</p> + +<ul> + <li>отключиться от сетевого соединения.</li> + <li>нажмите <em>Файл > Перейти в офлайн, </em>если вы используете<em> </em>Firefox.</li> + <li>перейдите в инструменты разработчика, выберите <em>Application > Service Workers</em>, нажмите галочку <em>Offline</em>, если используете Chrome.</li> +</ul> + +<p>Если обновите страницу с примером снова, вы увидите, что все работает как обычно. Все данные хранятся в офлайн хранилище — ресурсы страницы в кэше, а видео в базе данных IndexedDB.</p> + +<h2 id="Итого">Итого</h2> + +<p>Это всё, пока что. Мы надеемся наш краткий обзор <code>client-side storage</code> окажется полезным для вас.</p> + +<h2 id="Также_стоит_почитать">Также стоит почитать</h2> + +<ul> + <li><a href="/en-US/docs/Web/API/Web_Storage_API">Web storage API</a></li> + <li><a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a></li> + <li><a href="/en-US/docs/Web/HTTP/Cookies">Cookies</a></li> + <li><a href="/en-US/docs/Web/API/Service_Worker_API">Service worker API</a></li> +</ul> + +<p>{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li> +</ul> diff --git a/files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html b/files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html new file mode 100644 index 0000000000..63d9010aab --- /dev/null +++ b/files/ru/learn/javascript/client-side_web_apis/fetching_data/index.html @@ -0,0 +1,379 @@ +--- +title: Получение данных с сервера +slug: Learn/JavaScript/Client-side_web_APIs/Fetching_data +tags: + - AJAX + - API + - Fetch + - JavaScript + - XHR + - Новичку +translation_of: Learn/JavaScript/Client-side_web_APIs/Fetching_data +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs/Third_party_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</div> + +<p class="summary"><span lang="ru">Другой очень распространенной задачей в современных веб-сайтах и приложениях является получение отдельных элементов данных с сервера для обновления разделов веб-страницы без необходимости загрузки всей новой страницы. Эта, казалось бы, небольшая деталь оказала огромное влияние на производительность и поведение сайтов, поэтому в этой статье мы объясним концепцию и рассмотрим технологии, которые делают это возможным, например XMLHttpRequest и API Fetch.</span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Основы JavaScript (см. <a href="/en-US/docs/Learn/JavaScript/First_steps">первые шаги</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">структурные элементы</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">объекты JavaScript</a>), <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">основы клиентских API</a></td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Узнать, как извлекать данные с сервера и использовать их для обновления содержимого веб-страницы.</td> + </tr> + </tbody> +</table> + +<h2 id="В_чем_проблема">В чем проблема?</h2> + +<p>Первоначальная загрузка страницы в Интернете была простой - вы отправляли запрос на сервер web-сайта, и если всё работает, как и должно, то вся необходимая информация о странице будет загружена и отображена на вашем компьютере.</p> + +<p><img alt="A basic representation of a web site architecture" src="https://mdn.mozillademos.org/files/6475/web-site-architechture@2x.png" style="display: block; height: 134px; margin: 0px auto; width: 484px;"></p> + +<p>Проблема с этой моделью заключается в том, что всякий раз, когда вы хотите обновить любую часть страницы, например, чтобы отобразить новый набор продуктов или загрузить новую страницу, вам нужно снова загрузить всю страницу. Это очень расточительно и приводит к плохому пользовательскому опыту, особенно по мере того, как страницы становятся все более сложными.</p> + +<h3 id="Появление_Ajax">Появление Ajax</h3> + +<p>Это привело к созданию технологий, позволяющих веб-страницам запрашивать небольшие фрагменты данных (например, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML">HTML</a>, {{glossary("XML")}}, <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON">JSON</a> или обычный текст) и отображать их только при необходимости, помогая решать проблему, описанную выше.</p> + +<p>Это достигается с помощью таких API, как {{domxref("XMLHttpRequest")}} или - более новой - <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>. Эти технологии позволяют веб-страницам напрямую обрабатывать запросы <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP">HTTP</a> для определенных ресурсов, доступных на сервере, и форматировать результирующие данные по мере необходимости перед их отображением.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вначале эта общая техника была известна как Асинхронный JavaScript и XML (Ajax), поскольку она, как правило, использовала {{domxref("XMLHttpRequest")}} для запроса данных XML. В наши дни это обычно не так (вы, скорее всего, будете использовать <code>XMLHttpRequest</code> или Fetch для запроса JSON), но результат все тот же, и термин «Ajax» по-прежнему часто используется для описания этой техники.</p> +</div> + +<p><img alt="A simple modern architecture for web sites" src="https://mdn.mozillademos.org/files/6477/moderne-web-site-architechture@2x.png" style="display: block; height: 235px; margin: 0px auto; width: 559px;"></p> + +<p>Модель Ajax предполагает использование веб-API в качестве прокси для более разумного запроса данных, а не просто для того, чтобы браузер перезагружал всю страницу. Давайте подумаем о значении этого:</p> + +<ol> + <li>Перейдите на один из ваших любимых сайтов, богатых информацией, таких как Amazon, YouTube, CNN и т.д., и загрузите его.</li> + <li>Теперь найдите что-нибудь, например, новый продукт. Основной контент изменится, но большая часть информации, подобной заголовку, нижнему колонтитулу, навигационному меню и т. д., останется неизменной.</li> +</ol> + +<p>Это действительно хорошо, потому что:</p> + +<ul> + <li>Обновления страницы намного быстрее, и вам не нужно ждать перезагрузки страницы, а это означает, что сайт работает быстрее и воспринимается более отзывчивым.</li> + <li>Меньше данных загружается при каждом обновлении, что означает меньшее потребление пропускной способности. Это не может быть такой большой проблемой на рабочем столе в широкополосном подключении, но это серьезная проблема на мобильных устройствах и в развивающихся странах, которые не имеют повсеместного быстрого интернет-сервиса.</li> +</ul> + +<p>Чтобы ускорить работу, некоторые сайты также сохраняют необходимые файлы и данные на компьютере пользователя при первом обращении к сайту, а это означает, что при последующих посещениях они используют локальные версии вместо загрузки свежих копий, как при первой загрузке страницы. Содержимое загружается с сервера только при его обновлении.</p> + +<p><img alt="A basic web app data flow architecture" src="https://mdn.mozillademos.org/files/6479/web-app-architecture@2x.png" style="display: block; height: 383px; margin: 0px auto; width: 562px;"></p> + +<h2 id="Основной_запрос_Ajax">Основной запрос Ajax</h2> + +<p>Давайте посмотрим, как обрабатывается такой запрос, используя как {{domxref ("XMLHttpRequest")}}, так и <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch</a>. В этих примерах мы будем запрашивать данные из нескольких текстовых файлов и использовать их для заполнения области содержимого.</p> + +<p>Этот набор файлов будет действовать как наша поддельная база данных; в реальном приложении мы с большей вероятностью будем использовать серверный язык, такой как PHP, Python или Node, чтобы запрашивать наши данные из базы данных. Здесь, однако, мы хотим сохранить его простым и сосредоточиться на стороне клиента.</p> + +<h3 id="XMLHttpRequest">XMLHttpRequest</h3> + +<p><code>XMLHttpRequest</code> (который часто сокращается до XHR) является довольно старой технологией сейчас - он был изобретен Microsoft в конце 1990-х годов и уже довольно долго стандартизирован в браузерах.</p> + +<ol> + <li> + <p>Чтобы начать этот пример, создайте локальную копию <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/ajax-start.html">ajax-start.html</a> и четырех текстовых файлов - <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse1.txt">verse1.txt</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse2.txt">verse2.txt</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse3.txt">verse3.txt</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse4.txt">verse4.txt</a> - в новом каталоге на вашем компьютере. В этом примере мы загрузим другое стихотворение (который вы вполне можете распознать) через XHR, когда он будет выбран в выпадающем меню.</p> + </li> + <li> + <p>Внутри элемента {{htmlelement("script")}} добавьте следующий код. В нем хранится ссылка на элементы {{htmlelement("select")}} и {{htmlelement("pre")}} в переменных и определяется {{domxref ("GlobalEventHandlers.onchange", "onchange")}} обработчика событий, так что, когда значение select изменяется, его значение передается вызываемой функции <code>updateDisplay()</code> в качестве параметра.</p> + + <pre class="brush: js">var verseChoose = document.querySelector('select'); +var poemDisplay = document.querySelector('pre'); + +verseChoose.onchange = function() { + var verse = verseChoose.value; + updateDisplay(verse); +};</pre> + </li> + <li> + <p>Давайте определим нашу функцию <code>updateDisplay()</code>. Прежде всего, поставьте следующее ниже своего предыдущего блока кода - это пустая оболочка функции:</p> + + <pre class="brush: js">function updateDisplay(verse) { + +};</pre> + </li> + <li> + <p>Мы начнем нашу функцию с создания относительного URL-адреса, указывающего на текстовый файл, который мы хотим загрузить и который понадобится нам позже. Значение элемента {{htmlelement("select")}} в любой момент совпадает с текстом внутри выбранного {{htmlelement("option")}} (если вы не укажете другое значение в атрибуте value) - например, «Verse 1». Соответствующий текстовый файл стиха является «verse1.txt» и находится в том же каталоге, что и файл HTML, поэтому будет использоваться только имя файла.</p> + + <p>Тем не менее, веб-серверы, как правило, чувствительны к регистру, и имя файла не имеет символа "пробела". Чтобы преобразовать «Verse 1» в «verse1.txt», нам нужно преобразовать V в нижний регистр, удалить пробел и добавить .txt в конец. Это можно сделать с помощью {{jsxref("String.replace", "replace ()")}}, {{jsxref("String.toLowerCase", "toLowerCase ()")}} и простой <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Strings#Concatenating_strings">конкатенации строк</a>. Добавьте следующие строки внутри функции <code>updateDisplay()</code>:</p> + + <pre class="brush: js">verse = verse.replace(" ", ""); +verse = verse.toLowerCase(); +var url = verse + '.txt';</pre> + </li> + <li> + <p>Чтобы начать создание запроса XHR, вам нужно создать новый объект запроса, используя конструктор {{domxref("XMLHttpRequest()")}}. Вы можете назвать этот объект так, как вам нравится, но мы будем называть его <code>request</code> (запросом), чтобы все было просто. Добавьте следующие ниже строки:</p> + + <pre class="brush: js">var request = new XMLHttpRequest();</pre> + </li> + <li> + <p>Затем вам нужно использовать метод {{domxref("XMLHttpRequest.open", "open()")}}, чтобы указать, какой <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">HTTP request method</a> использовать для запроса ресурса из сети и какой его URL-адрес. Мы просто используем метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET">GET</a></code> здесь и задаем URL как нашу переменную <code>url</code>. Добавьте это ниже вашей предыдущей строки:</p> + + <pre class="brush: js">request.open('GET', url);</pre> + </li> + <li> + <p>Затем мы зададим тип ожидаемого ответа, который определяется как свойство {{domxref("XMLHttpRequest.responseType", "responseType")}} - как <code>text</code>. Здесь это не является абсолютно необходимым - XHR возвращает текст по умолчанию - но это хорошая идея, чтобы привыкнуть к настройке этого, если вы хотите получить другие типы данных в будущем. Добавьте следующее:</p> + + <pre class="brush: js">request.responseType = 'text';</pre> + </li> + <li> + <p>Получение ресурса из сети - это {{glossary("asynchronous")}} операция, означающая, что вам нужно дождаться завершения этой операции (например, ресурс возвращается из сети), прежде чем вы сможете сделать что-либо с этим ответом, иначе будет выброшена ошибка. XHR позволяет вам обрабатывать это, используя обработчик события {{domxref("XMLHttpRequest.onload", "onload")}} - он запускается при возникновении события {{event("load")}} (когда ответ вернулся). Когда это произойдет, данные ответа будут доступны в свойстве <code>response</code> (ответ) объекта запроса XHR.</p> + + <p>Добавьте следующее ниже вашего последнего дополнения. Вы увидите, что внутри обработчика события <code>onload</code> мы устанавливаем textContent <code>poemDisplay</code> (элемент {{htmlelement("pre")}}) в значение {{domxref("XMLHttpRequest.response", "request. response ")}}.</p> + + <pre class="brush: js">request.onload = function() { + poemDisplay.textContent = request.response; +};</pre> + </li> + <li> + <p>Вышеприведенная конфигурация запроса XHR фактически не будет выполняться до тех пор, пока мы не вызовем метод {{domxref("XMLHttpRequest.send", "send()")}}. Добавьте следующее ниже вашего предыдущего дополнения для вызова функции:</p> + + <pre class="brush: js">request.send();</pre> + </li> + <li> + <p>Одна из проблем с примером заключается в том, что он не покажет ни одного стихотворения, когда он впервые загружается. Чтобы исправить это, добавьте следующие две строки внизу вашего кода (чуть выше закрывающего тега <code></script></code>), чтобы загрузить стих 1 по умолчанию и убедитесь, что элемент {{htmlelement("select")}} всегда показывает правильное значение:</p> + + <pre class="brush: js">updateDisplay('Verse 1'); +verseChoose.value = 'Verse 1';</pre> + </li> +</ol> + +<h3 id="Обслуживание_вашего_примера_с_сервера">Обслуживание вашего примера с сервера</h3> + +<p>Некоторые браузеры (включая Chrome) не будут запускать запросы XHR, если вы просто запускаете пример из локального файла. Это связано с ограничениями безопасности (для получения дополнительной информации о безопасности в Интернете, ознакомьтесь с <a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a>).</p> + +<p>Чтобы обойти это, нам нужно протестировать пример, запустив его через локальный веб-сервер. Чтобы узнать, как это сделать, прочитайте <a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">Как настроить локальный тестовый сервер?</a></p> + +<h3 id="Fetch">Fetch</h3> + +<p>API-интерфейс Fetch - это, в основном, современная замена XHR - недавно он был представлен в браузерах для упрощения асинхронных HTTP-запросов в JavaScript, как для разработчиков, так и для других API, которые строятся поверх Fetch.</p> + +<p>Давайте преобразуем последний пример, чтобы использовать Fetch!</p> + +<ol> + <li> + <p>Сделайте копию своего предыдущего готового каталога примеров. (Если вы не работали над предыдущим упражнением, создайте новый каталог и внутри него создайте копии <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/xhr-basic.html">xhr-basic.html</a> и четырех текстовых файлов — <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse1.txt">verse1.txt</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse2.txt">verse2.txt</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse3.txt">verse3.txt</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/verse4.txt">verse4.txt</a>.)</p> + </li> + <li> + <p>Внутри функции <code>updateDisplay()</code> найдите код XHR:</p> + + <pre class="brush: js">var request = new XMLHttpRequest(); +request.open('GET', url); +request.responseType = 'text'; + +request.onload = function() { + poemDisplay.textContent = request.response; +}; + +request.send();</pre> + </li> + <li> + <p>Замените весь XHR-код следующим:</p> + + <pre class="brush: js">fetch(url).then(function(response) { + response.text().then(function(text) { + poemDisplay.textContent = text; + }); +});</pre> + </li> + <li> + <p>Загрузите пример в свой браузер (запустите его через веб-сервер), и он должен работать так же, как и версия XHR, при условии, что вы используете современный браузер.</p> + </li> +</ol> + +<h4 id="Итак_что_происходит_в_коде_Fetch">Итак, что происходит в коде Fetch?</h4> + +<p>Прежде всего, мы вызываем метод {{domxref("WorkerOrWindowGlobalScope.fetch()", "fetch()")}}, передавая ему URL-адрес ресурса, который мы хотим получить. Это современный эквивалент {{domxref("XMLHttpRequest.open", "request.open()")}} в XHR, плюс вам не нужен эквивалент <code>.send()</code>.</p> + +<p>После этого вы можете увидеть метод {{jsxref("Promise.then", ".then()")}}, прикреплённый в конец <code>fetch()</code> - этот метод является частью {{jsxref("Promise","Promises")}} - современная функция JavaScript для выполнения асинхронных операций. <code>fetch()</code> возвращает обещание, которое разрешает ответ, отправленный обратно с сервера, - мы используем <code>.then()</code> для запуска некоторого последующего кода после того, как обещание будет разрешено, что является функцией, которую мы определили внутри нее. Это эквивалент обработчика события <code>onload</code> в XHR-версии.</p> + +<p>Эта функция автоматически передает ответ от сервера в качестве параметра, когда обещает <code>fetch()</code>. Внутри функции мы берем ответ и запускаем его метод {{domxref("Body.text", "text()")}}, который в основном возвращает ответ как необработанный текст. Это эквивалент <code>request.responseType = 'text'</code> в версии XHR.</p> + +<p>Вы увидите, что <code>text()</code>также возвращает обещание, поэтому мы привязываем к нему другой <code>.then()</code>, внутри которого мы определяем функцию для получения необработанного текста, который обещает решение <code>text()</code>.</p> + +<p>Внутри функции внутреннего обещания мы делаем то же самое, что и в версии XHR, - устанавливаем текстовое содержимое {{htmlelement("pre")}} в текстовое значение.</p> + +<h3 id="Помимо_обещаний">Помимо обещаний</h3> + +<p>Обещания немного запутывают первый раз, когда вы их встречаете, но не беспокойтесь об этом слишком долго. Через некоторое время вы привыкнете к ним, особенно, когда вы узнаете больше о современных JavaScript-API. Большинство из них в большей степени основаны на обещаниях.</p> + +<p>Давайте посмотрим на структуру обещаний сверху, чтобы увидеть, можем ли мы еще немного понять это:</p> + +<pre class="brush: js">fetch(url).then(function(response) { + response.text().then(function(text) { + poemDisplay.textContent = text; + }); +});</pre> + +<p>В первой строке говорится: «Получить ресурс, расположенный по адресу url» <code>(fetch(url)</code>) и «затем запустить указанную функцию, когда обещание будет разрешено» (<code>.then(function() { ... })</code>). «Resolve» означает «завершить выполнение указанной операции в какой-то момент в будущем». Указанная операция в этом случае заключается в извлечении ресурса с указанного URL (с использованием HTTP-запроса) и возврата ответа для нас, чтобы что-то сделать.</p> + +<p>Фактически, функция, переданная в <code>then()</code>, представляет собой кусок кода, который не запускается немедленно - вместо этого он будет работать в какой-то момент в будущем, когда ответ будет возвращен. Обратите внимание, что вы также можете сохранить свое обещание в переменной и цепочку {{jsxref("Promise.then", ".then()")}} вместо этого. Ниже код будет делать то же самое:</p> + +<pre class="brush: js">var myFetch = fetch(url); + +myFetch.then(function(response) { + response.text().then(function(text) { + poemDisplay.textContent = text; + }); +});</pre> + +<p>Поскольку метод <code>fetch()</code> возвращает обещание, которое разрешает HTTP-ответ, любая функция, которую вы определяете внутри <code>.then()</code>, прикованная к концу, будет автоматически передаваться как параметр. Вы можете вызвать параметр, который вам нравится - приведенный ниже пример будет работать:</p> + +<pre class="brush: js">fetch(url).then(function(dogBiscuits) { + dogBiscuits.text().then(function(text) { + poemDisplay.textContent = text; + }); +});</pre> + +<p>Но имеет смысл называть параметр тем, что описывает его содержимое!</p> + +<p>Теперь давайте сосредоточимся только на функции:</p> + +<pre class="brush: js">function(response) { + response.text().then(function(text) { + poemDisplay.textContent = text; + }); +}</pre> + +<p>Объект ответа имеет метод {{domxref("Body.text", "text()")}}, который берет необработанные данные, содержащиеся в теле ответа, и превращает его в обычный текст, который является форматом, который мы хотим в нем А также возвращает обещание (которое разрешает полученную текстовую строку), поэтому здесь мы используем другой {{jsxref("Promise.then", ".then()")}}, внутри которого мы определяем другую функцию, которая диктует что мы хотим сделать с этой текстовой строкой. Мы просто устанавливаем свойство <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent">textContent</a></code> элемента {{htmlelement("pre")}} нашего стихотворения равным текстовой строке, так что это получается довольно просто.</p> + +<p>Также стоит отметить, что вы можете напрямую связывать несколько блоков обещаний (<code>.then()</code>, но есть и другие типы) на конце друг друга, передавая результат каждого блока следующему блоку по мере продвижения по цепочке , Это делает обещания очень мощными.</p> + +<p>Следующий блок делает то же самое, что и наш оригинальный пример, но написан в другом стиле:</p> + +<pre class="brush: js">fetch(url).then(function(response) { + return response.text() +}).then(function(text) { + poemDisplay.textContent = text; +});</pre> + +<p>Многие разработчики любят этот стиль больше, поскольку он более плоский и, возможно, легче читать для более длинных цепочек обещаний - каждое последующее обещание приходит после предыдущего, а не внутри предыдущего (что может стать громоздким). Единственное отличие состоит в том, что мы должны были включить оператор <code><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">return</a></code> перед <code>response.text()</code>, чтобы заставить его передать результат в следующую ссылку в цепочке.</p> + +<h3 id="Какой_механизм_следует_использовать">Какой механизм следует использовать?</h3> + +<p>Это действительно зависит от того, над каким проектом вы работаете. XHR существует уже давно и имеет отличную кросс-браузерную поддержку. Fetch and Promises, с другой стороны, являются более поздним дополнением к веб-платформе, хотя они хорошо поддерживаются в браузере, за исключением Internet Explorer и Safari (которые на момент написания Fetch были доступны в своем предварительный просмотр технологии).</p> + +<p>Если вам необходимо поддерживать старые браузеры, тогда может быть предпочтительным решение XHR. Если, однако, вы работаете над более прогрессивным проектом и не так обеспокоены старыми браузерами, то Fetch может быть хорошим выбором.</p> + +<p>Вам действительно нужно учиться - Fetch станет более популярным, так как Internet Explorer отказывается от использования (IE больше не разрабатывается, в пользу нового браузера Microsoft Edge), но вам может понадобиться XHR еще некоторое время.</p> + +<h2 id="Более_сложный_пример">Более сложный пример</h2> + +<p>Чтобы завершить статью, мы рассмотрим несколько более сложный пример, который показывает более интересные применения Fetch. Мы создали образец сайта под названием The Can Store - это вымышленный супермаркет, который продает только консервы. Вы можете найти этот пример <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/">в прямом эфире на GitHub</a> и <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/fetching-data/can-store">посмотреть исходный код</a>.</p> + +<p><img alt="A fake ecommerce site showing search options in the left hand column, and product search results in the right hand column." src="https://mdn.mozillademos.org/files/14779/can-store.png" style="display: block; margin: 0 auto;"></p> + +<p>По умолчанию на сайте отображаются все продукты, но вы можете использовать элементы управления формы в столбце слева, чтобы отфильтровать их по категориям, поисковому запросу или и тому и другому.</p> + +<p>Существует довольно много сложного кода, который включает фильтрацию продуктов по категориям и поисковым запросам, манипулирование строками, чтобы данные отображались правильно в пользовательском интерфейсе и т.д. Мы не будем обсуждать все это в статье, но вы можете найти обширные комментарии в коде (см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store/can-script.js">can-script.js</a>).</p> + +<p>Однако мы объясним код Fetch.</p> + +<p>Первый блок, который использует Fetch, можно найти в начале JavaScript:</p> + +<pre class="brush: js">fetch('products.json').then(function(response) { + if(response.ok) { + response.json().then(function(json) { + products = json; + initialize(); + }); + } else { + console.log('Network request for products.json failed with response ' + response.status + ': ' + response.statusText); + } +});</pre> + +<p>Это похоже на то, что мы видели раньше, за исключением того, что второе обещание находится в условном выражении. В этом случае мы проверяем, был ли возвращенный ответ успешным - свойство {{domxref("response.ok")}} содержит логическое значение, которое <code>true</code>, если ответ был в порядке (например, <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200">200 meaning "OK"</a>) или <code>false</code>, если он не увенчался успехом.</p> + +<p>Если ответ был успешным, мы выполняем второе обещание - на этот раз мы используем {{domxref("Body.json", "json()")}}, а не {{domxref("Body.text", "text()")}}, так как мы хотим вернуть наш ответ как структурированные данные JSON, а не обычный текст.</p> + +<p>Если ответ не увенчался успехом, мы выводим сообщение об ошибке в консоль, в котором сообщается о сбое сетевого запроса, который сообщает о статусе сети и описательном сообщении ответа (содержащемся в {{domxref("response.status")}} и {{domxref("response.statusText")}}, соответственно). Конечно, полный веб-сайт будет обрабатывать эту ошибку более грациозно, отображая сообщение на экране пользователя и, возможно, предлагая варианты для исправления ситуации.</p> + +<p>Вы можете проверить сам случай отказа:</p> + +<ol> + <li>Создание локальной копии файлов примеров (загрузка и распаковка <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store/can-store.zip?raw=true">the can-store ZIP file</a>)</li> + <li>Запустите код через веб-сервер (как описано выше, в {{anch("Serving your example from a server")}})</li> + <li>Измените путь к извлеченному файлу, например, «product.json» (т.е. убедитесь, что он написан неправильно)</li> + <li>Теперь загрузите индексный файл в свой браузер (например, через <code>localhost:8000</code>) и посмотрите в консоли разработчика браузера. Вы увидите сообщение в строке «Запрос сети для продуктов.json не удалось с ответом 404: Файл не найден»</li> +</ol> + +<p>Второй блок Fetch можно найти внутри функции <code>fetchBlob()</code>:</p> + +<pre class="brush: js">fetch(url).then(function(response) { + if(response.ok) { + response.blob().then(function(blob) { + objectURL = URL.createObjectURL(blob); + showProduct(objectURL, product); + }); + } else { + console.log('Network request for "' + product.name + '" image failed with response ' + response.status + ': ' + response.statusText); + } +});</pre> + +<p>Это работает во многом так же, как и предыдущий, за исключением того, что вместо использования {{domxref("Body.json", "json()")}} мы используем {{domxref("Body.blob", "blob()")}} - в этом случае мы хотим вернуть наш ответ в виде файла изображения, а формат данных, который мы используем для этого - <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a> - этот термин является аббревиатурой от« Binary Large Object »и может в основном использоваться для представляют собой большие файловые объекты, такие как изображения или видеофайлы.</p> + +<p>После того как мы успешно получили наш blob, мы создаем URL-адрес объекта, используя {{domxref("URL.createObjectURL()", "createObjectURL()")}}. Это возвращает временный внутренний URL-адрес, указывающий на объект, указанный в браузере. Они не очень читаемы, но вы можете видеть, как выглядит, открывая приложение Can Store, Ctrl-/щелкнуть правой кнопкой мыши по изображению и выбрать опцию «Просмотр изображения» (которая может немного отличаться в зависимости от того, какой браузер вы ). URL-адрес объекта будет отображаться внутри адресной строки и должен выглядеть примерно так:</p> + +<pre>blob:http://localhost:7800/9b75250e-5279-e249-884f-d03eb1fd84f4</pre> + +<h3 id="Вызов_XHR_версия_the_Can_Store">Вызов: XHR версия the Can Store</h3> + +<p>Мы хотели бы, чтобы вы решили преобразовать версию приложения Fetch для использования XHR в качестве полезной части практики. Возьмите <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store/can-store.zip?raw=true">копию ZIP файла</a> и попробуйте изменить JavaScript, если это необходимо.</p> + +<p>Некоторые полезные советы:</p> + +<ul> + <li>Вы можете найти полезный справочный материал {{domxref("XMLHttpRequest")}}.</li> + <li>Вам в основном нужно использовать тот же шаблон, что и раньше, в примере <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/xhr-basic.html">XHR-basic.html</a>.</li> + <li>Однако вам нужно будет добавить обработку ошибок, которые мы показали вам в версии Fetch Can Store: + <ul> + <li>Ответ найден в <code>request.response</code> после того, как событие <code>load</code> запущено, а не в обещании <code>then()</code>.</li> + <li>О наилучшем эквиваленте Fetch's <code>response.ok</code> в XHR следует проверить, является ли {{domxref("XMLHttpRequest.status","request.status")}} равным 200 или если {{domxref("XMLHttpRequest.readyState","request.readyState")}} равно 4.</li> + <li>Свойства для получения статуса и сообщения состояния одинаковы, но они находятся на объекте <code>request</code> (XHR), а не в объекте <code>response</code>.</li> + </ul> + </li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Если у вас есть проблемы с этим, не стесняйтесь сравнить свой код с готовой версией на GitHub (<a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store-xhr/can-script.js">см. исходник здесь</a>, а также <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store-xhr/">см. это в действии</a>).</p> +</div> + +<h2 id="Резюме">Резюме</h2> + +<p>Это завершает нашу статью по извлечению данных с сервера. К этому моменту вы должны иметь представление о том, как начать работать как с XHR, так и с Fetch.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<p>Однако в этой статье обсуждается много разных тем, которые только поцарапали поверхность. Для получения более подробной информации по этим темам, попробуйте следующие статьи:</p> + +<ul> + <li><a href="/en-US/docs/AJAX/Getting_Started">Введение в Ajax</a></li> + <li><a href="/en-US/docs/Web/API/Fetch_API/Using_Fetch">Применение Fetch</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Работа с JSON данными</a></li> + <li><a href="/en-US/docs/Web/HTTP/Overview">Обзор HTTP</a></li> + <li><a href="/en-US/docs/Learn/Server-side">Программирование веб-сайта на стороне сервера</a></li> +</ul> + +<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs/Third_party_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</div> + +<div> +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Введение в web API</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Манипулирование документами</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Получение данных с сервера</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Сторонние API</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Рисование графики</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Видео и аудио API</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Клиентское хранилище</a></li> +</ul> +</div> diff --git a/files/ru/learn/javascript/client-side_web_apis/index.html b/files/ru/learn/javascript/client-side_web_apis/index.html new file mode 100644 index 0000000000..b5e7493f19 --- /dev/null +++ b/files/ru/learn/javascript/client-side_web_apis/index.html @@ -0,0 +1,53 @@ +--- +title: Клиентский веб API +slug: Learn/JavaScript/Client-side_web_APIs +tags: + - API + - Articles + - Beginner + - CodingScripting + - DOM + - Graphics + - JavaScript + - Landing + - Learn + - Media + - Module + - NeedsTranslation + - TopicStub + - WebAPI + - data +translation_of: Learn/JavaScript/Client-side_web_APIs +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">При написании клиентского JavaScript для приложений или веб-сайтов Вам не приходится слишком сильно углубляться, пока Вы не начнете использовать API — интерфейсы управления различными аспектами браузера или операционной системы на которой этот сайт работает, или же с данными с других веб-сайтов или сервисов. В этом модуле мы рассмотрим что API из себя представляет и как использовать самые распространенные из них, с которыми Вы можете столкнуться в разработке.</p> + +<h2 id="Прежде_чем_начать">Прежде чем начать</h2> + +<p>Убедитесь, что вы прочли и хорошо разбираетесь в следующих модулях (<a href="https://wiki.developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8">Первые шаги</a>, <a href="https://wiki.developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks">Структурные элементы</a>, и <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects">Введение в объекты</a>). Эти модули включали в себя простое использование API, так как зачастую без них сложно писать примеры клиентского кода JavaScript. В данном модуле мы предполагаем, что вы хорошо знакомы с основами JavaScript, и немного подробнее рассмотрим общие веб-API.</p> + +<p>Естественно знание <a href="/en-US/docs/Learn/HTML">HTML</a> и <a href="/en-US/docs/Learn/CSS">CSS</a> здесь также необходимо.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Если вы работаете на устройстве, где у вас нет возможности создавать свои собственные файлы, вы можете проверить большинство примеров кода в онлайн-программах вроде <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Введение в различные web API</a></dt> + <dd>Прежде всего, мы начнем изучение API с основ - что это такое, как это работает, как вы используете их в своем коде и как они структурированы? Мы также рассмотрим, что представляют собой различные основные классы API, и как их можно использовать.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Управление документами</a></dt> + <dd><span id="result_box" lang="ru"><span>При написании веб-страниц и приложений Вы чаще всего </span></span><span lang="ru"><span>будете управлять каким-либо образом веб-документами. </span></span> <span id="result_box" lang="ru"><span>Обычно это делается с помощью Document Object Model (DOM), набора API-интерфейсов для управления HTML-разметкой и стилями, которые используют объект {{domxref ("Document")}}. </span></span><span id="result_box" lang="ru"><span>В этой статье мы рассмотрим, как использовать DOM, а также некоторые интересные API, которые могут изменить рабочую среду интересными способами.</span></span></dd> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Получение данных с сервера</a></dt> + <dd>Другой очень распространенной задачей в современных веб-сайтах и приложениях является получение отдельных элементов данных с сервера для обновления разделов веб-страницы без необходимости загрузки абсолютно новой страницы. Эта, казалось бы, небольшая деталь оказала огромное влияние на производительность и поведение сайтов, поэтому в этой статье мы объясним концепцию и рассмотрим технологии, которые позволяют это, например {{domxref("XMLHttpRequest")}} и <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Сторонние API</a></dt> + <dd>API, которые мы рассматривали до сих пор, встроены в браузер, но не все API встроены в браузер. Многие крупные веб-сайты и сервисы, такие как Google Maps, Twitter, Facebook, PayPal и т.д. предоставляют API-интерфейсы, позволяющие разработчикам использовать свои данные (например, показывать ваш Twitter-поток в вашем блоге) или сервисы (например, отображение пользовательских карт Google на вашем сайте, или с помощью входа в систему Facebook для входа в систему пользователей). В этой статье рассматривается различие между API браузера и сторонними API и показано типичное использование последнего.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Рисование графики</a></dt> + <dd>В браузере содержатся очень мощные инструменты графического программирования, начиная с языка Scalable Vector Graphics (<a href="https://developer.mozilla.org/en-US/docs/Web/SVG">SVG</a>) и заканчивая API для рисования элементов HTML {{htmlelement("canvas")}} (см. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">The Canvas API</a> и <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL</a>). В статье содержится введение в Canvas API и дополнительные ресурсы, чтобы вы могли узнать больше.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Видео и аудио API</a></dt> + <dd>HTML5 поставляется с элементами для размещения мультимедийных материалов в документах - {{htmlelement("video")}} и {{htmlelement("audio")}} - которые, в свою очередь, имеют свои собственные API для управления воспроизведением, поиском и т. д. В статье показано, как выполнять общие задачи, такие как создание пользовательских элементов управления воспроизведением.</dd> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Клиентское хранилище</a></dt> + <dd>Современные веб-браузеры имеют ряд различных технологий, которые позволяют хранить данные, связанные с веб-сайтами, и извлекать их, когда это необходимо, что позволяет вам сохранять данные в долгосрочной перспективе, сохранять сайты в автономном режиме и многое другое. В этой статье объясняются самые основы того, как они работают.</dd> +</dl> diff --git a/files/ru/learn/javascript/client-side_web_apis/introduction/index.html b/files/ru/learn/javascript/client-side_web_apis/introduction/index.html new file mode 100644 index 0000000000..bc710c0d37 --- /dev/null +++ b/files/ru/learn/javascript/client-side_web_apis/introduction/index.html @@ -0,0 +1,277 @@ +--- +title: Введение в web APIs +slug: Learn/JavaScript/Client-side_web_APIs/Introduction +translation_of: Learn/JavaScript/Client-side_web_APIs/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs")}}</div> + +<p class="summary">Начнём с рассмотрения того что представляют собой API на высоком уровне и выясним, как они работают, как их использовать в своих программах и как они структурированы. Также рассмотрим основные виды API и их применение.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, понимание основ <a href="/en-US/docs/Learn/HTML">HTML</a> и <a href="/en-US/docs/Learn/CSS">CSS</a>, основы JavaScript (см. <a href="/en-US/docs/Learn/JavaScript/First_steps">первые шаги</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">building blocks</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">объекты JavaScript</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Познакомиться с API, выяснить что они могут делать и как их использовать.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_API">Что такое API?</h2> + +<p>Интерфейс прикладного программирования (Application Programming Interfaces, APIs) - это готовые конструкции языка программирования, позволяющие разработчику строить сложный функционал с меньшими усилиями. Они "скрывают" более сложный код от программиста, обеспечивая простоту использования.</p> + +<p>Для лучшего понимания рассмотрим аналогию с домашними электросетями. Когда вы хотите использовать какой-то электроприбор, вы просто подключаете его к розетке, и всё работает. Вы не пытаетесь подключить провода напрямую к источнику тока — делать это бесполезно и, если вы не электрик, сложно и опасно.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14317/plug-socket.png" style="display: block; height: 472px; margin: 0px auto; width: 700px;"></p> + +<p><em>Image source: <a href="https://www.flickr.com/photos/easy-pics/9518184890/in/photostream/lightbox/">Overloaded plug socket</a> by <a href="https://www.flickr.com/photos/easy-pics/">The Clear Communication People</a>, on Flickr.</em></p> + +<p>Точно также, если мы хотим, например, программировать 3D графику, гораздо легче сделать это с использованием API, написанных на языках высокого уровня, таких как JavaScript или Python.</p> + +<div class="note"> +<p><strong>Note</strong>: См. также <a href="/en-US/docs/Glossary/API">API в словаре</a>.</p> +</div> + +<h3 id="API_клиентской_части_JavaScript">API клиентской части JavaScript</h3> + +<p>Для JavaScript на стороне клиента, в частности, существует множество API. Они не являются частью языка, а построены с помощью встроенных функций JavaScript для того, чтобы увеличить ваши возможности при написании кода. Их можно разделить на две категории:</p> + +<ul> + <li><strong>API браузера</strong> встроены в веб-браузер и способны использовать данные браузера и компьютерной среды для осуществления более сложных действий с этими данными. К примеру, <a href="/en-US/docs/Web/API/Geolocation/Using_geolocation">API Геолокации (Geolocation API)</a> предоставляет простые в использовании конструкции JavaScript для работы с данными местоположения, так что вы сможете, допустим, отметить свое расположение на карте Google Map. На самом деле, в браузере выполняется сложный низкоуровневый код (например, на C++) для подключения к устройству GPS (или любому другому устройству геолокации), получения данных и передачи их браузеру для обработки вашей программой, но, как было сказано выше, эти детали скрыты благодаря API.</li> + <li><strong>Сторонние API</strong> не встроены в браузер по умолчанию. Такие API и информацию о них обычно необходимо искать в интернете. Например, <a href="https://dev.twitter.com/overview/documentation">Twitter API</a> позволяет размещать последние твиты (tweets) на вашем веб-сайте. В данном API определён набор конструкций, осуществляющих запросы к сервисам Twitter и возвращающих определённые данные.</li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13508/browser.png" style="display: block; height: 511px; margin: 0px auto; width: 815px;"></p> + +<h3 id="Взаимодействие_JavaScript_API_и_других_средств_JavaScript">Взаимодействие JavaScript, API и других средств JavaScript</h3> + +<p>Итак, выше мы поговорили о том, что такое JavaScript API клиентской части и как они связаны с языком JavaScript. Давайте теперь тезисно запишем основные понятия и определим назначение других инструментов JavaScript:</p> + +<ul> + <li>JavaScript — Язык программирования сценариев высокого уровня, встроенный в браузер, позволяющий создавать функционал веб-страниц/приложений. Отметим, что JavaScript также доступен на других программных платформах, таких как <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Node</a>. Но пока не будем останавливаться на этом.</li> + <li>API браузера (Browser APIs) — конструкции, встроенные в браузер, построенные на основе языка JavaScript, предназначенные для облегчения разработки функционала.</li> + <li>Сторонние API (Third party APIs) — конструкции, встроенные в сторонние платформы (такие как Twitter, Facebook) позволяющие вам использовать часть функционала этих платформ в своих собственных веб-страницах/приложениях (например, показывать последние Твиты на вашей странице).</li> + <li>Библиотеки JavaScript — Обычно один или несколько файлов, содержащих <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Custom_functions">пользовательские (custom) функции</a> . Такие файлы можно прикрепить к веб-странице, чтобы ускорить или предоставить инструменты для написания общего функционала. Примеры: jQuery, Mootools и React.</li> + <li>JavaScript фреймворки (frameworks) — Следующий шаг в развитии разработки после библиотек. Фреймворки JavaScript (такие как Angular и Ember) стремятся к тому, чтобы быть набором HTML, CSS, JavaScript и других технологий, после установки которого можно "писать" веб-приложение с нуля. Главное различие между фреймворками и библиотеками - "Обратное направление управления" ( “Inversion of Control” ). Вызов метода из библиотеки происходит по требованию разработчика. При использовании фреймворка - наоборот, фреймворк производит вызов кода разработчика.</li> +</ul> + +<h2 id="На_что_способны_API">На что способны API?</h2> + +<p>Широкое разнообразие API в современных браузерах позволяет наделить ваше приложение большими возможностями. Достаточно посмотреть список на странице <a href="https://developer.mozilla.org/en-US/docs/Web/API">MDN APIs index page</a>.</p> + +<h3 id="Распространённые_API_браузера">Распространённые API браузера</h3> + +<p>В частности, к наиболее часто используемым категориям API (и которые мы рассмотрим далее в этом модуле) относятся :</p> + +<ul> + <li><strong>API для работы с документами</strong>, загруженными в браузер. Явный пример - <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model">DOM (Document Object Model) API</a>, позволяющий работать с HTML и CSS — создавать, удалять и изменять HTML, динамически изменять вид страницы и т.д. Любое всплывающее окно на странице или появляющееся "на ходу" содержимое - всё это благодаря DOM. Узнайте больше об этой категории API на странице <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Работа с документами</a>.</li> + <li><strong>API, принимающие данные от сервера</strong>, часто используются, чтобы обновить небольшие части веб-страницы. Эта, казалось бы, малая деталь оказывает огромное влияние на производительность и поведение сайтов, так как нет необходимости перезагружать всю страницу целиком, если вам нужно просто обновить список товаров или новых доступных историй. Это также сделает приложение или сайт более отзывчивым и "живым". Список API, благодаря которым это возможно, включает: <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest" title="XMLHttpRequest is an API that provides client functionality for transferring data between a client and a server. It provides an easy way to retrieve data from a URL without having to do a full page refresh. This enables a Web page to update just a part of the page without disrupting what the user is doing."><code>XMLHttpRequest</code></a> и <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>. Вы также могли встретить термин <strong>Ajax</strong>, описывающий эту технологию. Узнать больше об этой категории API на странице <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Получение данных от сервера</a>.</li> + <li><strong>API для работы с графикой</strong> широко поддерживаются браузерами, самые популярные: <a href="/en-US/docs/Web/API/Canvas_API">Canvas</a> и <a href="/en-US/docs/Web/API/WebGL_API">WebGL</a>, позволяющие программно изменять данные о пикселях, содержащиеся в элементе HTML {{htmlelement("canvas")}} для создания 2D и 3D изображений. Например, вы можете нарисовать фигуры, скажем, прямоугольники или круги, импортировать изображение в canvas и применить к нему фильтры, такие как сепия или оттенки серого с помощью Canvas API, или создать сложное 3D-изображение с освещением и текстурами, используя WebGL. Такие API часто используют в сочетании с API создания анимационных циклов (таких как {{domxref("window.requestAnimationFrame()")}}) и другими для создания постоянно меняющегося изображения на экране, как в мультфильмах или играх .</li> + <li><strong><a href="https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery">Аудио и Видео API</a></strong> как {{domxref("HTMLMediaElement")}}, <a href="/en-US/docs/Web/API/Web_Audio_API">Web Audio API</a>, и <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a> позволяют делать действительно интересные вещи с мультимедиа. Например, создать собственный пользовательский интерфейс (User Interface, UI) для проигрывания аудио/видео, вывод на экран субтитров, записывать видео с веб-камеры для обработки в canvas (см. выше) или для передачи на другой компьютер в видео-конференции, применять звуковые эффекты к аудио-файлам (такие как gain, distortion, panning и т.д.).</li> + <li><strong>API устройств</strong> - в основном, API для обработки и считывания данных с современных устройств удобным для работы веб-приложений образом. Мы уже говорили об API Геолокации, позволяющем считать данные о местоположении устройства. Другие примеры включают уведомление пользователя о появившемся обновлении для веб-приложения с помощью системных уведомлений (см. <a href="/en-US/docs/Web/API/Notifications_API">Notifications API</a>) или вибрации (см. <a href="/en-US/docs/Web/API/Vibration_API">Vibration API</a>).</li> + <li><strong>API хранения данных на стороне пользователя</strong> приобретают всё большее распространение в веб-браузерах — возможность хранить информацию на стороне клиента очень полезна, когда необходимо создать приложение, которое будет сохранять своё состояние между перезагрузками страницы, или даже работать, когда устройство не в сети. В данный момент доступно немало таких API. Например, простое хранилище данных в формате имя/значение (name/value) <a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a> или хранилище данных в формате таблиц <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a>.</li> +</ul> + +<h3 id="Распространённые_сторонние_API">Распространённые сторонние API</h3> + +<p>Существует множество сторонних API; некоторые из наиболее популярных, которые вы рано или поздно будете использовать, включают:</p> + +<ul> + <li><a href="https://dev.twitter.com/overview/documentation">Twitter API</a> для добавления такого функционала, как показ последних твитов на сайте.</li> + <li><a href="https://developers.google.com/maps/">Google Maps API</a> для работы с картами на веб-странице (интересно, что Google Maps также использует этот API). Теперь это целый набор API, который может справляться с широким спектром задач, как свидетельствует <a href="https://developers.google.com/maps/documentation/api-picker">Google Maps API Picker</a>.</li> + <li><a href="https://developers.facebook.com/docs/">Набор Facebook API</a> позволяет использовать различные части платформы Facebook в вашем приложении, предоставляя, например, возможность входа в систему с логином Facebook, оплаты покупок в приложении, демонстрация целевой рекламы и т.д.</li> + <li><a href="https://developers.google.com/youtube/">YouTube API</a>, предоставляющий возможность встраивать видео с YouTube на вашем сайте, производить поиск, создавать плэйлисты и т.д.</li> + <li><a href="https://www.twilio.com/">Twilio API</a> - фреймворк для встраивания функционала голосовой и видео связи в вашем приложении, отправки SMS/MMS из приложения и т.д.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: Вы можете найти информацию о гораздо большем количестве сторонних API в <a href="http://www.programmableweb.com/category/all/apis">Каталоге Web API</a>.</p> +</div> + +<h2 id="Как_работает_API">Как работает API?</h2> + +<p>Работа разных JavaScript API немного отличается, но, в основном, у них похожие функции и принцип работы.</p> + +<h3 id="Они_основаны_на_объектах">Они основаны на объектах</h3> + +<p>Взаимодействие с API в коде происходит через один или больше <a href="/en-US/docs/Learn/JavaScript/Objects">объектов JavaScript</a>, которые служат контейнерами для информации, с которой работает API (содержится в свойствах объекта), и реализуют функционал, который предоставляет API (содержится в методах объекта).</p> + +<div class="note"> +<p><strong>Note</strong>: Если вам ещё не известно как работают объекты, советуем вернуться назад и изучить модуль <a href="/en-US/docs/Learn/JavaScript/Objects">Основы объектов JavaScript</a> прежде чем продолжать.</p> +</div> + +<p>Вернёмся к примеру с API Геолокации — очень простой API, состоящий из нескольких простых объектов:</p> + +<ul> + <li>{{domxref("Geolocation")}}, содержит три метода для контроля и получения геоданных.</li> + <li>{{domxref("Position")}}, предоставляет данные о местоположении устройства в заданный момент времени — содержит {{domxref("Coordinates")}} - объект, хранящий координаты и отметку о текущем времени.</li> + <li>{{domxref("Coordinates")}}, содержит много полезной информации о расположении устройства, включая широту и долготу, высоту, скорость и направление движения и т.д.</li> +</ul> + +<p>Так как же эти объекты взаимодействуют? Если вы посмотрите на наш пример <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/introduction/maps-example.html">maps-example.html</a> (<a href="http://mdn.github.io/learning-area/javascript/apis/introduction/maps-example.html">see it live also</a>), вы увидите следующий код:</p> + +<pre class="brush: js notranslate">navigator.geolocation.getCurrentPosition(function(position) { + var latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude); + var myOptions = { + zoom: 8, + center: latlng, + mapTypeId: google.maps.MapTypeId.TERRAIN, + disableDefaultUI: true + } + var map = new google.maps.Map(document.querySelector("#map_canvas"), myOptions); +});</pre> + +<div class="note"> +<p><strong>Note</strong>: Когда вы впервые загрузите приведённый выше пример, появится диалоговое окно, запрашивающее разрешение на передачу данных о местонахождении этому приложению (см. раздел {{anch("У них есть дополнительные средства безопасности там, где это необходимо")}} далее в этой статье). Вам нужно разрешить передачу данных, чтобы иметь возможность отметить своё местоположение на карте. Если вы всё ещё не видите карту, возможно, требуется установить разрешения вручную; это делается разными способами в зависимости от вашего браузера; например, в Firefox перейдите > <em>Tools</em> > <em>Page Info</em> > <em>Permissions</em>, затем измените настройки <em>Share Location</em>; в Chrome перейдите<em> Settings</em> > <em>Privacy</em> > <em>Show advanced settings</em> > <em>Content settings</em> и измените настройки <em>Location</em>.</p> +</div> + +<p>Во-первых, мы хотим использовать метод {{domxref("Geolocation.getCurrentPosition()")}}, чтобы получить текущее положение нашего устройства. Доступ к объекту браузера {{domxref("Geolocation")}} производится с помощью свойства {{domxref("Navigator.geolocation")}}, так что мы начнём с</p> + +<pre class="brush: js notranslate">navigator.geolocation.getCurrentPosition(function(position) { ... });</pre> + +<p>Это эквивалентно следующему коду</p> + +<pre class="brush: js notranslate">var myGeo = navigator.geolocation; +myGeo.getCurrentPosition(function(position) { ... });</pre> + +<p>Но мы можем использовать точки, чтобы связать доступ к свойствам/методам объекта в одно выражение, уменьшая количество строк в программе.</p> + +<p>Метод {{domxref("Geolocation.getCurrentPosition()")}} имеет один обязательный параметр - анонимную функцию, которая запустится, когда текущее положение устройства будет успешно считано. Сама эта функция принимает параметр, являющийся объектом {{domxref("Position")}}, представляющим данные о текущем местоположении.</p> + +<div class="note"> +<p><strong>Note</strong>: Функция, которая передаётся другой функции в качестве параметра, называется <a href="/en-US/docs/Glossary/Callback_function">функцией обратного вызова (callback function)</a>.</p> +</div> + +<p>Такой подход, при котором функция вызывается только тогда, когда операция была завершена, очень распространён в JavaScript API — убедиться, что операция была завершена прежде, чем пытаться использовать данные, которые она возвращает, в другой операции. Такие операции также называют асинхронными операциями (<strong><a href="/en-US/docs/Glossary/Asynchronous">asynchronous</a> operations)</strong>. Учитывая, что получение данных геолокации производится из внешнего устройства (GPS-устройства или другого устройства геолокации), мы не можем быть уверены, что операция считывания будет завершена вовремя и мы сможем незамедлительно использовать возвращаемые ею данные. Поэтому такой код не будет работать:</p> + +<pre class="brush: js example-bad notranslate">var position = navigator.geolocation.getCurrentPosition(); +var myLatitude = position.coords.latitude;</pre> + +<p>Если первая строка ещё не вернула результат, вторая вызовет ошибку из-за того, что данные геолокации ещё не стали доступны. По этой причине, API, использующие асинхронные операции, разрабатываются с использованием {{glossary("callback function")}}, или более современной системы <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Обещаний(Promises)</a>, которая появилась в ECMAScript 6 и широко используются в новых API.</p> + +<p>Мы совмещаем API Геолокации со сторонним API - Google Maps API, который используем для того, чтобы отметить расположение, возвращаемое <code>getCurrentPosition()</code> , на Google Map. Чтобы Google Maps API стал доступен на нашей странице, мы включаем его в HTML документ:</p> + +<pre class="brush: html notranslate"><script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA"></script></pre> + +<p>Чтобы использовать этот API, во-первых создадим объект <code>LatLng</code> с помощью конструктора <code>google.maps.LatLng()</code> , принимающим данные геолокации {{domxref("Coordinates.latitude")}} и {{domxref("Coordinates.longitude")}} :</p> + +<pre class="brush: js notranslate">var latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);</pre> + +<p>Этот объект сам является значением свойства <code>center</code> объекта настроек (options), который мы назвали <code>myOptions</code>. Затем мы создаём экземпляр объекта, представляющего нашу карту, вызывая конструктор <code>google.maps.Map()</code> и передавая ему два параметра — ссылку на элемент {{htmlelement("div")}}, на котором мы хотим отрисовывать карту (с ID <code>map_canvas</code>), и объект настроек (options), который мы определили выше.</p> + +<pre class="brush: js notranslate">var myOptions = { + zoom: 8, + center: latlng, + mapTypeId: google.maps.MapTypeId.TERRAIN, + disableDefaultUI: true +} + +var map = new google.maps.Map(document.querySelector("#map_canvas"), myOptions);</pre> + +<p>Когда это сделано, наша карта отрисовывается.</p> + +<p>Последний блок кода демонстрирует два распространённых подхода, которые вы увидите во многих API:</p> + +<ul> + <li>Во-первых, объекты API обычно содержат конструкторы, которые вызываются для создания экземпляров объектов, используемых при написании программы.</li> + <li>Во-вторых, объекты API зачастую имеют несколько вариантов (options), которые можно настроить и получить именно ту среду для разработки, которую вы хотите. API конструкторы обычно принимают объекты вариантов (options) в качестве параметров, с помощью которых и происходит настройка.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: Не отчаивайтесь, если вы что-то не поняли из этого примера сразу. Мы рассмотрим использование сторонних API более подробно в следующих статьях.</p> +</div> + +<h3 id="У_них_узнаваемые_точки_входа">У них узнаваемые точки входа</h3> + +<p>При использовании API убедитесь, что вы знаете где точка входа для API. В API Геолокации это довольно просто — это свойство {{domxref("Navigator.geolocation")}}, возвращающее объект браузера {{domxref("Geolocation")}}, внутри которого доступны все полезные методы геолокации.</p> + +<p>Найти точку входа Document Object Model (DOM) API ещё проще — при применении этого API используется объект {{domxref("Document")}}, или экземпляр элемента HTML, с которым вы хотите каким-либо образом взаимодействовать, к примеру:</p> + +<pre class="brush: js notranslate">var em = document.createElement('em'); // создаёт новый элемент em +var para = document.querySelector('p'); // ссылка на существующий элемент p +em.textContent = 'Hello there!'; // присвоение текстового содержимого +para.appendChild(em); // встроить em внутрь para</pre> + +<p>Точки входа других API немного сложнее, часто подразумевается создание особого контекста, в котором будет написан код API. Например, объект контекста Canvas API создаётся получением ссылки на элемент {{htmlelement("canvas")}}, на котором вы хотите рисовать, а затем необходимо вызвать метод {{domxref("HTMLCanvasElement.getContext()")}}:</p> + +<pre class="brush: js notranslate">var canvas = document.querySelector('canvas'); +var ctx = canvas.getContext('2d');</pre> + +<p>Всё, что мы хотим сделать с canvas после этого, достигается вызовом свойств и методов объекта содержимого (content) (который является экземпляром {{domxref("CanvasRenderingContext2D")}}), например:</p> + +<pre class="brush: js notranslate">Ball.prototype.draw = function() { + ctx.beginPath(); + ctx.fillStyle = this.color; + ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI); + ctx.fill(); +};</pre> + +<div class="note"> +<p><strong>Note</strong>: Вы можете увидеть этот код в действии в нашем <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/introduction/bouncing-balls.html">bouncing balls demo</a> (see it <a href="http://mdn.github.io/learning-area/javascript/apis/introduction/bouncing-balls.html">running live</a> also).</p> +</div> + +<h3 id="Они_используют_события_для_управления_состоянием">Они используют события для управления состоянием</h3> + +<p>Мы уже обсуждали события ранее в этом курсе, в нашей статье <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a> — в этой статье детально описываются события на стороне клиента и их применение. Если вы ещё не знакомы с тем, как работают события клиентской части, рекомендуем прочитать эту статью прежде, чем продолжить.</p> + +<p>В некоторых API содержится ряд различных событий, в некоторых - событий нет. Свойства обработчика, позволяющие запускать функции при совершении какого-либо события по большей части перечислены в нашем материале отдельного раздела "Обработчики событий (Event handlers)". Как простой пример, экземпляры объекта <code><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> (каждый представляет собой HTTP-запрос к серверу на получение каких-либо ресурсов (resource)) имеют несколько доступных событий, например, событие <code>load</code> происходит, когда ответ с запрашиваемым ресурсом был успешно возвращён и доступен в данный момент.</p> + +<p>Следующий код содержит простой пример использования событий:</p> + +<pre class="brush: js notranslate">var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json'; +var request = new XMLHttpRequest(); +request.open('GET', requestURL); +request.responseType = 'json'; +request.send(); + +request.onload = function() { + var superHeroes = request.response; + populateHeader(superHeroes); + showHeroes(superHeroes); +}</pre> + +<div class="note"> +<p><strong>Note</strong>: Вы можете увидеть этот код в действии в примере <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/introduction/ajax.html">ajax.html</a> (<a href="http://mdn.github.io/learning-area/javascript/apis/introduction/ajax.html">see it live</a> also).</p> +</div> + +<p>В первых пяти строках мы задаём расположение ресурса, который хотим получить, создаём экземпляр объекта запроса с помощью конструктора <code>XMLHttpRequest()</code>, открываем HTTP-запрос <code>GET</code>, чтобы получить запрашиваемый ресурс, определяем, что мы хотим получить этот ресурс в формате json, после чего отсылаем запрос.</p> + +<p>Затем функция-обработчик <code>onload</code> определяет наши действия по обработке ответа сервера. Нам известно, что ответ успешно возвращён и доступен после наступления события load (и если не произойдёт ошибка), так что мы сохраняем ответ, содержащий возвращённый сервером объект JSON в переменной <code>superHeroes</code>, которую затем передаём двум различным функциям для дальнейшей обработки.</p> + +<h3 id="У_них_есть_дополнительные_средства_безопасности_там_где_это_необходимо">У них есть дополнительные средства безопасности там, где это необходимо</h3> + +<p>Функционал WebAPI подвержен тем же соображениям безопасности , что и JavaScript или другие веб-технологии (например, <a href="/en-US/docs/Web/Security/Same-origin_policy">same-origin policy</a>), но иногда они содержат дополнительные механизмы защиты. К примеру, некоторые из наиболее современных WebAPI работают только со страницами, обслуживаемыми через HTTPS в связи с передачей конфиденциальных данных (примеры: <a href="/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> и <a href="/en-US/docs/Web/API/Push_API">Push</a>).</p> + +<p>К тому же, некоторые WebAPI запрашивают разрешение от пользователя, как только к ним происходит вызов в коде. В качестве примера, вы, возможно, встречали такое диалоговое окно при загрузке нашего примера <a href="/en-US/docs/Web/API/Geolocation">Geolocation</a> ранее:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14313/location-permission.png" style="border-style: solid; border-width: 1px; display: block; height: 188px; margin: 0px auto; width: 413px;"></p> + +<p><a href="/en-US/docs/Web/API/Notifications_API">Notifications API</a> запрашивает разрешение подобным образом:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14315/notification-permission.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>Запросы разрешений необходимы для обеспечения безопасности пользователей — не будь их, сайты могли бы скрытно отследить ваше местоположение, не создавая множество надоедливых уведомлений.</p> + +<h2 id="Итоги">Итоги</h2> + +<p>На данном этапе, у вас должно сформироваться представление о том, что такое API, как они работают и как вы можете применить их в своём JavaScript коде. Вам наверняка не терпится начать делать по-настоящему интересные вещи с конкретными API, так вперёд! В следующий раз мы рассмотрим работу с документом с помощью Document Object Model (DOM).</p> + +<p>{{NextMenu("Learn/JavaScript/Client-side_web_APIs/Manipulating_documents", "Learn/JavaScript/Client-side_web_APIs")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Введение в web APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li> +</ul> diff --git a/files/ru/learn/javascript/client-side_web_apis/manipulating_documents/index.html b/files/ru/learn/javascript/client-side_web_apis/manipulating_documents/index.html new file mode 100644 index 0000000000..e93334902a --- /dev/null +++ b/files/ru/learn/javascript/client-side_web_apis/manipulating_documents/index.html @@ -0,0 +1,321 @@ +--- +title: Управление документами +slug: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents +tags: + - API + - DOM + - Изучение + - Навигатор + - Новичек + - Окно +translation_of: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}</div> + +<p class="summary">При написании веб-страниц и приложений вам придётся часто каким-либо образом управлять структурой документа. Обычно это делается с помощью Document Object Model (DOM), набора API для управления разметкой HTML и стилями, которая сильно использует объект {{domxref ("Document")}}. В этой статье мы подробно рассмотрим, как использовать DOM и некоторые другие интересные API, которые могут изменить вашу среду интересными способами.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML, CSS и JavaScript - включая объекты JavaScript.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Познакомиться с основными DOM API и другими API, обычно связанными с DOM, и манипулированием документами</td> + </tr> + </tbody> +</table> + +<h2 id="Важные_элементы_веб-браузера">Важные элементы веб-браузера</h2> + +<p>Веб-браузеры - очень сложные части программного обеспечения с множеством движущихся частей, многие из которых не могут управляться или управляться веб-разработчиком с использованием JavaScript. Вы можете подумать, что такие ограничения - это плохо, но браузеры заблокированы по уважительным причинам (в основном ради безопасности). Представьте себе, что веб-сайт может получить доступ к вашим сохраненным паролям или другой конфиденциальной информации и войти на веб-сайты так, как если бы это были вы?</p> + +<p>Несмотря на ограничения, Web API по-прежнему дают нам доступ к множеству функциональных возможностей, которые позволяют нам многое делать с веб-страницами. Есть несколько действительно очевидных моментов, на которые вы будете регулярно ссылаться в своем коде. Рассмотрим следующую диаграмму, которая представляет основные части браузера, непосредственно участвующие в просмотре веб-страниц:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14557/document-window-navigator.png" style="display: block; margin: 0 auto;"></p> + +<ul> + <li>Окно - это вкладка браузера, в которую загружается веб-страница; это представлено в JavaScript объектом {{domxref("Window")}}. Используя методы, доступные для этого объекта, вы можете делать такие вещи, как возврат размера окна (см. {{Domxref("Window.innerWidth")}} и {{domxref("Window.innerHeight")}}), манипулировать документом, загруженным в этот window, хранить данные, специфичные для этого документа на стороне клиента (например, используя локальную базу данных или другой механизм хранения), присоединить обработчик событий (<a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#A_series_of_fortunate_events">event handler</a>) к текущему окну и многое другое.</li> + <li>Навигатор представляет состояние и идентификатор браузера (т. е. пользовательский агент), как он существует в Интернете. В JavaScript это представлено объектом {{domxref("Navigator")}}. Вы можете использовать этот объект для извлечения таких вещей, как геолокационная информация, предпочтительный язык пользователя, медиапоток с веб-камеры пользователя и т. д.</li> + <li>Документ (представленный DOM в браузерах) представляет собой фактическую страницу, загруженную в окно, и представлен в JavaScript объектом {{domxref("Document")}}. Вы можете использовать этот объект для возврата и обработки информации о HTML и CSS, содержащей документ, например, получить ссылку на элемент в DOM, изменить его текстовый контент, применить к нему новые стили, создать новые элементы и добавить их в текущий элемент как дочерний элемент, или даже вообще удалить его.</li> +</ul> + +<p>В этой статье мы сосредоточимся главным образом на манипулировании документом, но мы покажем ещё несколько полезных моментов.</p> + +<h2 id="Объектная_модель_документа">Объектная модель документа</h2> + +<p>Документ, загруженный в каждый из ваших вкладок браузера, представлен объектной моделью документа. Это представление «древовидной структуры», созданное браузером, которое позволяет легко получить доступ к структуре HTML с помощью языков программирования - например, сам браузер использует его для применения стиля и другой информации к правильным элементам, поскольку он отображает страницу, а разработчики (как Вы) могут манипулировать DOM с JavaScript после того, как страница была отображена.</p> + +<p>Мы создали простую страницу примера в <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dom-example.html">dom-example.html</a> (<a href="https://mdn.github.io/learning-area/javascript/apis/document-manipulation/dom-example.html">см. также live</a>). Попробуйте открыть это в своем браузере - это очень простая страница, содержащая элемент {{htmlelement("section")}}, внутри которого вы можете найти изображение и абзац со ссылкой внутри. Исходный код HTML выглядит так:</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Simple DOM example</title> + </head> + <body> + <section> + <img src="dinosaur.png" alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."> + <p>Here we will add a link to the <a href="https://www.mozilla.org/">Mozilla homepage</a></p> + </section> + </body> +</html></pre> + +<p>DOM, с другой стороны, выглядит так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14559/dom-screenshot.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<div class="note"> +<p><strong>Примечание</strong>. Эта диаграмма дерева DOM была создана с использованием <a href="https://software.hixie.ch/utilities/js/live-dom-viewer/">Live DOM viewer</a> Яна Хиксона.</p> +</div> + +<p>Вы можете видеть здесь, что каждый элемент и бит текста в документе имеют свою собственную запись в дереве - каждый из них называется <strong>узлом</strong> (<strong>node)</strong>. Вы также столкнетесь с различными терминами, используемыми для описания типа узла, и их положением в дереве относительно друг друга:</p> + +<ul> + <li><strong>Element node</strong>: элемент, как он существует в DOM.</li> + <li><strong>Root node</strong>: верхний узел в дереве, который в случае <code>HTML</code> всегда является узлом HTML (другие словари разметки, такие как SVG и пользовательский XML, будут иметь разные корневые элементы)..</li> + <li><strong>Child node</strong>: узел <em>непосредственно</em> внутри другого узла. Например, <code>IMG</code> является дочерним элементом <code>SECTION</code> в приведенном выше примере.</li> + <li><strong>Descendant node</strong> (узел потомок): узел внутри дочернего элемента. Например, <code>IMG</code> является дочерним элементом <code>SECTION</code> в приведенном выше примере, и он также является потомком для родителя <code>SECTION</code>. <code>IMG</code> не является ребенком <code>BODY</code>, так как он находится на двух уровнях ниже дерева в дереве, но он является потомком <code>BODY</code>.</li> + <li><strong>Parent node</strong>: узел, в котором текущий узел. Например, <code>BODY</code> является родительским узлом <code>SECTION</code> в приведенном выше примере.</li> + <li><strong>Sibling nodes</strong> (одноуровневый узел): узлы, которые расположены на одном уровне в дереве DOM. Например, <code>IMG</code> и <code>P</code> являются братьями и сестрами в приведенном выше примере.</li> + <li><strong>Text node</strong>: узел, содержащий текстовую строку.</li> +</ul> + +<p>Полезно ознакомиться с этой терминологией перед тем, как работать с DOM, поскольку некоторые термины кода, с которыми вы столкнетесь, используют их.. Возможно, вы уже сталкивались с ними, если вы изучали CSS (например, селектор потомков, дочерний селектор).</p> + +<h2 id="Активное_обучение_основы_управления_структурой_DOM">Активное обучение: основы управления структурой DOM</h2> + +<p>Чтобы начать изучение по управлению структуры DOM, давайте начнем с практического примера.</p> + +<ol> + <li>Возьмите локальную копию страницы <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dom-example.html">dom-example.html page</a> и изображение, которое вместе с ним.</li> + <li>Добавьте элемент <code><script></script></code> чуть выше закрывающего тега <code></body></code>.</li> + <li>Чтобы управлять элементом внутри DOM, вам сначала нужно выбрать его и сохранить ссылку на него внутри переменной. Внутри вашего скриптового элемента добавьте следующую строку: + <pre class="brush: js notranslate">var link = document.querySelector('a');</pre> + </li> + <li>Теперь у нас есть ссылка на элемент, хранящаяся в переменной, мы можем начать ее манипулировать с использованием доступных ему свойств и методов (они определены на таких интерфейсах, как {{domxref("HTMLAnchorElement")}} в случае {{htmlelement ("a")}}, его более общий родительский интерфейс {{domxref ("HTMLElement")}} и {{domxref("Node")}} - который представляет все узлы в DOM). Прежде всего, давайте изменим текст внутри ссылки, обновив значение свойства {{domxref("Node.textContent")}}. Добавьте следующую строку ниже предыдущей: + <pre class="brush: js notranslate">link.textContent = 'Mozilla Developer Network';</pre> + </li> + <li>Мы также должны изменить URL-адрес, на который указывает ссылка, чтобы он не попадал в неправильное место при нажатии. Добавьте следующую строку, опять внизу: + <pre class="brush: js notranslate">link.href = 'https://developer.mozilla.org';</pre> + </li> +</ol> + +<div> +<p>Обратите внимание, что, как и во многих вещах в JavaScript, существует множество способов выбора элемента и хранения ссылки на него в переменной. {{domxref("Document.querySelector()")}} - рекомендуемый современный подход, который считается удобным, потому что он позволяет вам выбирать элементы с помощью селекторов CSS. Вышеупомянутый запрос <code>querySelector()</code> будет соответствовать первому элементу {{htmlelement("a")}}, который появляется в документе. Если вы хотите совместить и делать что-то с несколькими элементами, вы можете использовать {{domxref ("Document.querySelectorAll()")}}, который соответствует каждому элементу документа, который соответствует селектору и сохраняет ссылки на них в массиве <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Arrays">массиво</a>-подобном объекте, называемом NodeList.</p> + +<p>Существуют более старые методы для захвата ссылок на элементы, например:</p> + +<ul> + <li>{{domxref("Document.getElementById()")}}, который выбирает элемент с заданным значением атрибута <code>id</code>, например <code><p id="myId">Мой абзац</p></code>. Идентификатор передается функции как параметр, т.е. <code>var elementRef = document.getElementById('myId')</code>.</li> + <li>{{domxref("Document.getElementsByTagName()")}}, который возвращает массив, содержащий все элементы на странице данного типа, например <code><p></code>, <code><a></code> и т.д. Тип элемента передается к функции в качестве параметра, то есть <code>var elementRefArray = document.getElementsByTagName('p')</code>.</li> +</ul> + +<p>Эти два работают в более старых браузерах, чем современные методы, такие как <code>querySelector()</code>, но не так удобны. Осмотритесь и вы увидите, что ещё можно найти!</p> +</div> + +<h3 id="Создание_и_размещение_новых_узлов">Создание и размещение новых узлов</h3> + +<p>Вышесказанное дало вам немного вкуса от того, что вы можете сделать, но давайте продолжим и посмотрим, как мы можем создавать новые элементы.</p> + +<ol> + <li>Возвращаясь к текущему примеру, давайте начнем с захвата ссылки на наш элемент {{htmlelement("section")}} - добавьте следующий код внизу существующего скрипта (сделайте то же самое с другими строками): + <pre class="brush: js notranslate">var sect = document.querySelector('section');</pre> + </li> + <li>Теперь давайте создадим новый абзац, используя {{domxref("Document.createElement()")}} и передадим ему текстовое содержимое так же, как и раньше: + <pre class="brush: js notranslate">var para = document.createElement('p'); +para.textContent = 'We hope you enjoyed the ride.';</pre> + </li> + <li>Теперь вы можете добавить новый абзац в конце раздела, используя {{domxref("Node.appendChild()")}}: + <pre class="brush: js notranslate">sect.appendChild(para);</pre> + </li> + <li>Наконец, для этой части, давайте добавим текстовый узел в абзац, где находится ссылка, чтобы оформить предложение красиво. Сначала мы создадим текстовый узел, используя {{domxref("Document.createTextNode()")}}: + <pre class="brush: js notranslate">var text = document.createTextNode(' — the premier source for web development knowledge.');</pre> + </li> + <li>Теперь мы возьмем ссылку на абзац, в котором находится ссылка, и добавим к нему текстовый узел: + <pre class="brush: js notranslate">var linkPara = document.querySelector('p'); +linkPara.appendChild(text);</pre> + </li> +</ol> + +<p>Это большая часть того, что вам нужно для добавления узлов в DOM - вы будете использовать эти методы при построении динамических интерфейсов (мы рассмотрим некоторые примеры позже).</p> + +<h3 id="Перемещение_и_удаление_элементов">Перемещение и удаление элементов</h3> + +<p>Могут быть моменты, когда вы хотите переместить узлы или вообще удалить их из DOM. Это вполне возможно.</p> + +<p>Если бы мы хотели переместить абзац со ссылкой внутри него в нижней части раздела, мы могли бы просто сделать это:</p> + +<pre class="brush: js notranslate">sect.appendChild(linkPara);</pre> + +<p>Это переводит абзац вниз в нижнюю часть раздела. Вы могли подумать, что это сделает вторую копию, но это не так - <code>linkPara</code> - ссылка на единственную копию этого абзаца. Если вы хотите сделать копию и добавить ее также, вам нужно будет использовать {{domxref("Node.cloneNode()")}}.</p> + +<p>Удаление узла довольно просто, по крайней мере, когда у вас есть ссылка на удаляемый узел и его родительский элемент. В нашем случае мы просто используем {{domxref("Node.removeChild()")}}, например:</p> + +<pre class="notranslate">sect.removeChild(linkPara);</pre> + +<p>Он становится немного сложнее, если вы хотите удалить узел, основанный только на ссылке на себя, что довольно часто. Нет способа сообщить узлу удалить себя, поэтому вам нужно будет сделать следующее.</p> + +<pre class="brush: js notranslate">linkPara.parentNode.removeChild(linkPara);</pre> + +<p>Попробуйте добавить вышеуказанные строки в свой код.</p> + +<h3 id="Управление_стилями">Управление стилями</h3> + +<p>Можно управлять стилями CSS с помощью JavaScript различными способами.</p> + +<p>Для начала вы можете получить список всех таблиц стилей, прикрепленных к документу, с помощью {{domxref("Document.stylesheets")}}, который возвращает массив объектов {{domxref("CSSStyleSheet")}}. Затем вы можете добавлять / удалять стили по желанию. Однако мы не будем расширять эти функции, потому что они являются несколько архаичным и трудным способом манипулирования стилем. Есть гораздо более простые способы.</p> + +<p>Первый способ - добавить встроенные стили непосредственно на элементы, которые вы хотите динамически стилизовать. Это делается с помощью свойства {{domxref("HTMLElement.style")}}, которое содержит встроенную информацию о стиле для каждого элемента документа. Вы можете установить свойства этого объекта для непосредственного обновления стилей элементов.</p> + +<ol> + <li>В качестве примера попробуйте добавить эти строки в наш текущий пример: + <pre class="brush: js notranslate">para.style.color = 'white'; +para.style.backgroundColor = 'black'; +para.style.padding = '10px'; +para.style.width = '250px'; +para.style.textAlign = 'center';</pre> + </li> + <li>Перезагрузите страницу, и вы увидите, что стили были применены к абзацу. Если вы посмотрите на этот параграф в инспекторе <a href="https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector">Page Inspector/DOM inspector </a>вашего браузера, вы увидите, что эти строки действительно добавляют встроенные стили в документ: + <pre class="brush: html notranslate"><p style="color: white; background-color: black; padding: 10px; width: 250px; text-align: center;">We hope you enjoyed the ride.</p></pre> + </li> +</ol> + +<div class="note"> +<p>Примечание: Обратите внимание на то, как версии свойств JavaScript стилей CSS пишутся в нижнем регистре верблюжьего стиля (lower camel case), в то время как версии свойств стилей CSS используют дефисы (например, <code>backgroundColor</code> и <code>background-color</code>). Убедитесь, что вы не перепутали их, иначе это не сработает.</p> +</div> + +<p>Существует еще один распространенный способ динамического управления стилями вашего документа, который мы рассмотрим сейчас.</p> + +<ol> + <li>Удалите предыдущие пять строк, добавленных в JavaScript.</li> + <li>Добавьте в свой HTML-код следующее: {{htmlelement("head")}}: + <pre class="notranslate"><style> +.highlight { + color: white; + background-color: black; + padding: 10px; + width: 250px; + text-align: center; +} +</style></pre> + </li> + <li>Теперь мы перейдем к очень полезному методу для общего манипулирования HTML - {{domxref("Element.setAttribute()")}} - это принимает два аргумента, атрибут, который вы хотите установить для элемента, и значение, которое вы хотите для его установки. В этом случае мы укажем имя класса выделения в нашем абзаце: + <pre class="brush: js notranslate">para.setAttribute('class', 'highlight');</pre> + </li> + <li>Обновите свою страницу, и вы не увидите изменений - CSS по-прежнему применяется к абзацу, но на этот раз, предоставив ему класс, который выбран нашим правилом CSS, а не как встроенные стили CSS.</li> +</ol> + +<p>Какой метод вы выбираете, зависит от вас; оба имеют свои преимущества и недостатки. Первый метод принимает меньше настроек и хорош для простого использования, тогда как второй метод более пурист (без смешивания CSS и JavaScript, без встроенных стилей, которые рассматриваются как плохая практика). Когда вы начнете создавать более крупные приложения, вы, вероятно, начнете использовать второй метод больше, но это действительно зависит от вас.</p> + +<p>На данный момент мы не сделали ничего полезного! Нет смысла использовать JavaScript для создания статического контента - вы можете просто записать его в свой HTML и не использовать JavaScript. Это сложнее, чем HTML, и для создания вашего контента с помощью JavaScript также есть другие связанные с ним проблемы (например, не читаемые поисковыми системами).</p> + +<p>В следующих параграфах мы рассмотрим еще несколько практических применений DOM API.</p> + +<div class="note"> +<p>Примечание. Вы можете найти наш пример <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/dom-example-manipulated.html">finished version of the dom-example.html</a> на GitHub (<a href="https://mdn.github.io/learning-area/javascript/apis/document-manipulation/dom-example-manipulated.html">см. также live</a>).</p> +</div> + +<h2 id="Активное_обучение_динамический_список_покупок">Активное обучение: динамический список покупок</h2> + +<p>До сих пор мы действительно смотрели на использование функций {{domxref("Node")}} и {{domxref("Document")}} для управления документами, но нет причин, по которым вы не можете получить данные из других источников и использовать его в пользовательском интерфейсе. Вспомните нашу простую демонстрацию <a href="http://mdn.github.io/learning-area/javascript/apis/introduction/maps-example.html">maps-example.html</a> из последней статьи - там мы извлекли некоторые данные о местоположении и использовали ее для отображения карты вашей области. Вам просто нужно убедиться, что ваши данные в правильном формате; JavaScript упрощает работу, чем многие другие языки, будучи слабо типизированным - например, числа автоматически преобразуются в строки, когда вы хотите распечатать их на экране.</p> + +<p>В этом примере мы решим общую проблему: убедитесь, что ваше приложение имеет размер как окно, в котором он просматривается, независимо от его размера. Это часто полезно в таких ситуациях, как игры, где вы хотите использовать как можно большую площадь экрана, чтобы играть в игру.</p> + +<p>Для начала создайте локальную копию наших демо-файлов <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/window-resize-example.html">window-resize-example.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/bgtile.png">bgtile.png</a>. Откройте его и посмотрите - вы увидите, что у нас есть элемент {{htmlelement("div")}}, который покрывает небольшую часть экрана, на который нанесена фоновая плитка. Мы будем использовать это, чтобы представить нашу область пользовательского интерфейса приложения.</p> + +<ol> + <li>Прежде всего, давайте возьмем ссылку на div, а затем возьмем ширину и высоту окна просмотра (внутреннее окно, где отображается ваш документ) и сохраните их в переменных - эти два значения удобно содержатся в {{domxref("Window.innerWidth")}} и {{domxref("Window.innerHeight")}}. Добавьте следующие строки внутри существующего элемента {{htmlelement("script")}}: + <pre class="brush: js notranslate">var div = document.querySelector('div'); +var WIDTH = window.innerWidth; +var HEIGHT = window.innerHeight;</pre> + </li> + <li>Затем мы динамически изменяем ширину и высоту div, равную ширине окна просмотра. Добавьте следующие две строки ниже своих первых: + <pre class="brush: js notranslate">div.style.width = WIDTH + 'px'; +div.style.height = HEIGHT + 'px';</pre> + </li> + <li>Сохраните и попробуйте обновить браузер - теперь вы должны увидеть, что div становится таким же большим, как ваш видовой экран, независимо от того, какой размер экрана вы используете. Если теперь вы попытаетесь изменить размер окна, чтобы увеличить его, вы увидите, что div остается одного размера - мы устанавливаем его только один раз.</li> + <li>Как насчет того, чтобы мы использовали событие, чтобы размер div изменялся при изменении размера окна? Объект {{domxref("Window")}} имеет событие, имеющееся на нем с именем resize, которое запускается каждый раз при изменении размера окна - давайте обратимся к нему через обработчик событий {{domxref("Window.onresize")}} и повторяйте наш размерный код каждый раз, когда он изменяется. Добавьте нижеследующую часть кода: + <pre class="brush: js notranslate">window.onresize = function() { + WIDTH = window.innerWidth; + HEIGHT = window.innerHeight; + div.style.width = WIDTH + 'px'; + div.style.height = HEIGHT + 'px'; +}</pre> + </li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>. Если у вас возникла проблема, посмотрите на наш <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/window-resize-example-finished.html">законченный пример изменения размера окна</a> (<a href="https://mdn.github.io/learning-area/javascript/apis/document-manipulation/window-resize-example-finished.html">см. также live</a>).</p> +</div> + +<h2 id="Активное_обучение_динамический_список_покупок_2">Активное обучение: динамический список покупок</h2> + +<p>Чтобы завершить статью, мы хотели бы задать вам небольшой вызов - мы хотим сделать простой пример списка покупок, который позволяет динамически добавлять элементы в список с помощью ввода формы и кнопки. Когда вы добавляете элемент на вход и нажимаете кнопку:</p> + +<ul> + <li>Элемент должен появиться в списке.</li> + <li>Каждому элементу должна быть предоставлена кнопка, которую можно нажать, чтобы удалить этот элемент из списка.</li> + <li>Вход должен быть опустошен и сфокусирован, чтобы вы могли ввести другой элемент.</li> +</ul> + +<p>Готовое демо будет выглядеть примерно так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14563/shopping-list.png" style="border-style: solid; border-width: 1px; display: block; height: 225px; margin: 0px auto; width: 369px;"></p> + +<p>Чтобы завершить упражнение, выполните следующие действия и убедитесь, что список ведет себя так, как описано выше.</p> + +<ol> + <li>Для начала загрузите копию нашего начального файла <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/shopping-list.html">shopping-list.html</a> и скопируйте его где-нибудь. Вы увидите, что у него есть минимальный CSS, список с меткой, ввод и кнопка, пустой список и элемент {{htmlelement("script")}}. Вы будете делать все свои дополнения внутри скрипта.</li> + <li>Создайте три переменные, содержащие ссылки на список ({{htmlelement("ul")}}, {{htmlelement("input")}} и {{htmlelement("button")}} элементы.</li> + <li>Создайте <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Functions">function</a>, которая будет запускаться в ответ на нажатие кнопки.</li> + <li>Внутри тела функции начните с сохранения текущего значения (<a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement#Properties">value</a>) входного элемента в переменной.</li> + <li>Затем очистите элемент ввода, установив его значение в пустую строку — <code>''</code>.</li> + <li>Создайте три новых элемента - элемент списка ({{htmlelement('li')}}), {{htmlelement('span')}} и {{htmlelement('button')}} и сохраните их в переменных.</li> + <li>Добавьте диапазон и кнопку в качестве дочерних элементов списка.</li> + <li>Установите текстовое содержимое диапазона на значение входного элемента, которое вы сохранили ранее, и текстовое содержимое кнопки «Удалить».</li> + <li>Добавить элемент списка в качестве дочернего списка.</li> + <li>Прикрепите обработчик события к кнопке удаления, чтобы при щелчке удалял весь элемент списка, внутри которого он находится.</li> + <li>Наконец, используйте метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus">focus()</a></code>, чтобы сфокусировать входной элемент, готовый для входа в следующий элемент списка покупок.</li> +</ol> + +<div class="note"> +<p>Примечание: Если у вас возникла действительно сложная проблема, взгляните на наши примеры <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/document-manipulation/shopping-list-finished.html">finished shopping list</a> (<a href="http://mdn.github.io/learning-area/javascript/apis/document-manipulation/shopping-list-finished.html">see it running live also</a>.)</p> +</div> + +<h2 id="Краткая_информация">Краткая информация</h2> + +<p>Мы закончили изучение документа и манипулирования DOM. На этом этапе вы должны понимать, что важная часть веб-браузера связана с управлением документами и другими аспектами веб-интерфейса пользователя. Самое главное, вы должны понять, что такое Document Object Model, и как манипулировать им для создания полезных функций.</p> + +<h2 id="Дополнительная_информация">Дополнительная информация</h2> + +<p>Есть много возможностей, которые можно использовать для управления вашими документами. Ознакомьтесь с некоторыми нашими рекомендациями и узнайте, что вы можете обнаружить:</p> + +<ul> + <li>{{domxref("Document")}}</li> + <li>{{domxref("Window")}}</li> + <li>{{domxref("Node")}}</li> + <li>{{domxref("HTMLElement")}}, {{domxref("HTMLInputElement")}}, {{domxref("HTMLImageElement")}}, etc.</li> +</ul> + +<p>(Полный список веб-индексов API, задокументированных MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/API">Web API index</a>)</p> + +<div>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Introduction", "Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs")}}</div> + +<div> +<h2 id="В_этот_модуль_входит">В этот модуль входит</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li> +</ul> +</div> diff --git a/files/ru/learn/javascript/client-side_web_apis/third_party_apis/index.html b/files/ru/learn/javascript/client-side_web_apis/third_party_apis/index.html new file mode 100644 index 0000000000..4977fe99c7 --- /dev/null +++ b/files/ru/learn/javascript/client-side_web_apis/third_party_apis/index.html @@ -0,0 +1,482 @@ +--- +title: Сторонние API +slug: Learn/JavaScript/Client-side_web_APIs/Third_party_APIs +tags: + - 3rd party + - API + - Third party + - Новичку +translation_of: Learn/JavaScript/Client-side_web_APIs/Third_party_APIs +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs/Drawing_graphics", "Learn/JavaScript/Client-side_web_APIs")}}</div> + +<p class="summary">API, которые мы рассмотрели до сих пор, встроены в браузер, но не все API таковы. Многие крупные веб-сайты и сервисы, такие как Google Maps, Twitter, Facebook, PayPal и т. д., Предоставляют API-интерфейсы, позволяющие разработчикам использовать свои данные (например, показывать ваш твиттер-поток в вашем блоге) или сервисы (например, отображение пользовательских карт Google на вашем сайте, или использование логина Facebook для входа в систему ваших пользователей). В этой статье рассматривается различие между API-интерфейсами браузера и сторонними API и показано типичное использование последних.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Основы JavaScript (см. <a href="/en-US/docs/Learn/JavaScript/First_steps">первые шаги</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">структурные элементы</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">объекты JavaScript</a>), the <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">основы клиентских API</a></td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Изучить, как работают сторонние API, и как использовать их для улучшения ваших сайтов.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_сторонние_API">Что такое сторонние API?</h2> + +<p>Сторонние API - это API, предоставляемые третьими лицами — как правило, такими компаниями, как Facebook, Twitter, or Google — чтобы вы могли получить доступ к их функциям с помощью JavaScript и использовать его на своем собственном сайте. Как мы показали в нашей <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">вводной статье об API</a>, одним из наиболее очевидных примеров является использование <a href="https://developers.google.com/maps/">Google Maps APIs</a> для отображения пользовательских карт на ваших страницах.</p> + +<p>Давайте снова посмотрим на наш пример карты (см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/introduction/maps-example.html">исходный код на GitHub</a>; <a href="https://mdn.github.io/learning-area/javascript/apis/introduction/maps-example.html">см. это в действии</a>), и используем его для иллюстрации того, как сторонние API отличаются от API-интерфейсов браузера.</p> + +<div class="note"> +<p><strong>Примечание</strong>: По умолчанию использование сторонних API на вашем сайте позволит им отслеживать файлы cookie своих доменов, устанавливать файлы cookie в исходное состояние, получать заголовки ссылок, определяющие посещаемые страницы, и разрешать им выполнять JavaScript на страницах, на которых они загружаются с теми же разрешениями (например, выполнить запросы AJAX на ваши серверы с теми же кукисами сеанса). Должны быть оценены вопросы регулирования, безопасности и конфиденциальности.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Возможно, вы захотите сразу <a href="/en-US/docs/Learn#Getting_our_code_examples">получить все наши примеры кода</a>, в этом случае вы можете просто искать репо для файлов примеров, которые вам нужны в каждом разделе.</p> +</div> + +<h3 id="Они_находятся_на_сторонних_серверах">Они находятся на сторонних серверах</h3> + +<p>API браузера встроены в браузер - вы можете получить к ним доступ сразу из JavaScript. Например, <a href="/en-US/docs/Web/API/Geolocation/Using_geolocation">API геолокации</a>, доступный в нашем примере, осуществляется с использованием свойства геолокации объекта <code><a href="/en-US/docs/Web/API/Navigator">Navigator</a></code>, которое возвращает объект <code><a href="/en-US/docs/Web/API/Geolocation">Geolocation</a></code>. Этот пример использует метод <code><a href="/en-US/docs/Web/API/Geolocation/getCurrentPosition">getCurrentPosition()</a></code> этого объекта, для запроса текущего положения устройства:</p> + +<pre class="brush: js">navigator.geolocation.getCurrentPosition(function(position) { ... });</pre> + +<p>Сторонние API, с другой стороны, расположены на сторонних серверах. Чтобы получить доступ к ним из JavaScript, вам сначала нужно подключиться к функциям API и сделать его доступным на вашей странице. Обычно это связано с первой ссылкой на библиотеку JavaScript, доступную на сервере через элемент {{htmlelement("script")}}, как показано в нашем примере:</p> + +<pre class="brush: js"><script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA"></script></pre> + +<p>Затем вы можете начать использовать объекты, доступные в этой библиотеке. Например:</p> + +<pre class="brush: js">var latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude); +var myOptions = { + zoom: 8, + center: latlng, + mapTypeId: google.maps.MapTypeId.TERRAIN, + disableDefaultUI: true +} + +var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);</pre> + +<p>Здесь мы создаем новый объект <code>LatLng</code>, используя конструктор <code>google.maps.LatLng()</code>, который содержит широту и долготу местоположения, которое мы хотим показать, полученные из API геолокации. Затем мы создаем объект опций (<code>myOptions</code>), содержащий эту и другую информацию, связанную с отображением карты. Наконец, мы фактически создаем карту, используя конструктор <code>google.maps.Map()</code>, который принимает в качестве параметров элемент, на котором мы хотим нарисовать карту, и объект опций.</p> + +<p>Это вся информация, которую API Карт Google требует для построения простой карты. Сервер, к которому вы подключаетесь, обрабатывает все сложные вещи, такие как отображение правильных фрагментов карты для отображаемой области и т. д.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Некоторые API обрабатывают доступ к их функциям несколько иначе, требуя от разработчика сделать HTTP-запрос (см. <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Получение данных с сервера</a>) на определенный шаблон URL для получения определенных данных. Они называются RESTful API, и мы покажем пример этого позже в статье.</p> +</div> + +<h3 id="Разрешения_обрабатываются_по-разному">Разрешения обрабатываются по-разному</h3> + +<p>Безопасность API-интерфейсов браузеров, как правило, обрабатывается запросами разрешения, как <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction#They_have_additional_security_mechanisms_where_appropriate">описано в нашей первой статье</a>. Целью этого является то, что пользователь знает, что происходит на сайтах, которые он посещает, и с меньшей вероятностью может стать жертвой того, кто использует API, злонамеренно.</p> + +<p>Сторонние API имеют немного другую систему разрешений - они, как правило, используют ключевые коды, чтобы позволить разработчикам получить доступ к функциям API. Просмотрите URL-адрес библиотеки API Карт Google, с которой мы связались:</p> + +<pre>https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA</pre> + +<p>Параметр URL, указанный в конце URL-адреса, является ключом разработчика - разработчик приложения должен применять его для получения ключа, а затем включать его в свой код определенным образом, чтобы иметь доступ к функциям API. В случае с Картами Google (и другими API Google) вы подаете заявку на получение ключа на <a href="https://console.cloud.google.com/">Google Cloud Platform</a>.</p> + +<p>Другие API могут потребовать, чтобы вы включили ключ немного по-другому, но шаблон для большинства из них довольно схож. <br> + <br> + Требование к ключу заключается в том, что не каждый может использовать функциональность API без какой-либо подотчетности. Когда разработчик зарегистрировался для ключа, они затем известны поставщику API, и действие может быть предпринято, если они начинают делать что-то вредоносное с помощью API (например, отслеживать местоположение пользователей или пытаться спамить API с множеством запросов для остановки его работы, например). Самое простое действие - просто отменить их привилегии API.</p> + +<h2 id="Расширенный_пример_Карт_Google">Расширенный пример Карт Google</h2> + +<p>Теперь когда мы рассмотрели пример API Карт Google и посмотрели, как он работает, добавим еще несколько функций, чтобы показать, как использовать некоторые другие функции API.</p> + +<ol> + <li> + <p>Чтобы начать этот раздел, сделайте себе копию <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/third-party-apis/google-maps/maps_start.html">исходного файла Карт Google</a>, в новой папке. Если Вы уже <a href="/en-US/docs/Learn#Getting_our_code_examples">клонировали репозиторий примеров</a>, у вас уже есть копия этого файла, которую Вы можете найти в папке the <em>javascript/apis/third-party-apis/google-maps</em>.</p> + </li> + <li> + <p>Затем получите свой собственный ключ разработчика, выполнив следующие шаги:</p> + + <ol> + <li>Перейдите в <a href="https://console.cloud.google.com/apis/dashboard">панель управления API-интерфейсом Google Cloud Platform</a>.</li> + <li>Создайте новый проект, если у вас его еще нет.</li> + <li>Нажмите кнопку <em>Enable API</em>.</li> + <li>Выберите <em>Google Maps JavaScript API</em>.</li> + <li>Нажмите кнопку <em>Enable</em>.</li> + <li>Нажмите <em>Create credentials</em>, затем выберите <em>API key</em>.</li> + <li>Скопируйте свой ключ API и замените существующий ключ в первом элементе {{htmlelement ('script')}} примера вашим собственным (фрагмент между <code>?key=</code> и меткой закрытия закрытия атрибута (<code>"</code>).)</li> + </ol> + + <div class="note"> + <p><strong>Примечание</strong>: Получение ключей API, связанных с Google, может быть немного затруднительным: в Менеджере API Google Cloud Platform много разных экранов, и рабочий процесс может немного отличаться в зависимости от того, как у вас уже установлена учетная запись. Если у вас возникнут проблемы с этим шагом, мы будем рады помочь — <a href="/en-US/docs/Learn#Contact_us">Свяжитесь с нами</a>.</p> + </div> + </li> + <li>Откройте исходный файл Карт Google, найдите строку <code>INSERT-YOUR-API-KEY-HERE</code>, и замените ее фактическим ключом API, который вы получили из панели управления Google Cloud Platform API Manager.</li> +</ol> + +<h3 id="Adding_a_custom_marker">Adding a custom marker</h3> + +<p>Adding a marker (icon) at a certain point on the map is easy — you just need to create a new marker using the <code>google.maps.Marker()</code> constructor, passing it an options object containing the position to display the marker at (as a <code>LatLng</code> object), and the <code>Map</code> object to display it on.</p> + +<ol> + <li> + <p>Add the following just below the <code>var map ...</code> line:</p> + + <pre class="brush: js">var marker = new google.maps.Marker({ + position: latlng, + map: map +});</pre> + + <p>Now if you refresh your page, you'll see a nice little marker pop up in the centre of the map. This is cool, but it is not exactly a custom marker — it is using the default marker icon.</p> + </li> + <li> + <p>To use a custom icon, we need to specify it when we create the marker, using its URL. First of all, add the following line above the previous block you added:</p> + + <pre class="brush: js">var iconBase = 'https://maps.google.com/mapfiles/kml/shapes/';</pre> + + <p>This defines the base URL where all the official Google Maps icons are stored (you could also specify your own icon location if you wished).</p> + </li> + <li> + <p>The icon location is specified in the <code>icon</code> property of the options object. Update the constructor like so:</p> + + <pre class="brush: js">var marker = new google.maps.Marker({ + position: latlng, + icon: iconBase + 'flag_maps.png', + map: map +});</pre> + + <p>Here we specify the icon property value as the <code>iconBase</code> plus the icon filename, to create the complete URL. Now try reloading your example and you'll see a custom marker displayed on your map!</p> + </li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: See <a href="https://developers.google.com/maps/documentation/javascript/custom-markers">Customizing a Google Map: Custom Markers</a> for more information.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: See <a href="https://fusiontables.google.com/DataSource?dsrcid=308519#map:id=3">Map marker or Icon names</a> to find out what other icons are available, and see what their reference names are. Their file name will be the icon name they display when you click on them, with ".png" added on the end.</p> +</div> + +<h3 id="Displaying_a_popup_when_the_marker_is_clicked">Displaying a popup when the marker is clicked</h3> + +<p>Another common use case for Google Maps is displaying more information about a place when its name or marker is clicked (popups are called <strong>info windows</strong> in the Google Maps API). This is also very simple to achieve, so let's have a look at it.</p> + +<ol> + <li> + <p>First of all, you need to specify a JavaScript string containing HTML that will define the content of the popup. This will be injected into the popup by the API and can contain just about any content you want. Add the following line below the <code>google.maps.Marker()</code> constructor definition:</p> + + <pre class="brush: js">var contentString = '<div id="content"><h2 id="firstHeading" class="firstHeading">Custom info window</h2><p>This is a cool custom info window.</p></div>';</pre> + </li> + <li> + <p>Next, you need to create a new info window object using the <code>google.maps.InfoWindow()</code> constructor. Add the following below your previous line:</p> + + <pre class="brush: js">var infowindow = new google.maps.InfoWindow({ + content: contentString +});</pre> + + <p>There are other properties available (see <a href="https://developers.google.com/maps/documentation/javascript/infowindows">Info Windows</a>), but here we are just specifying the <code>content</code> property in the options object, which points to the source of the content.</p> + </li> + <li> + <p>Finally, to get the popup to display when the marker is clicked, we use a simple click event handler. Add the following below the <code>google.maps.InfoWindow()</code> constructor:</p> + + <pre class="brush: js">marker.addListener('click', function() { + infowindow.open(map, marker); +});</pre> + + <p>Inside the function, we simply invoke the infowindow's <code>open()</code> function, which takes as parameters the map you want to display it on, and the marker you want it to appear next to.</p> + </li> + <li> + <p>Now try reloading the example, and clicking on the marker!</p> + </li> +</ol> + +<h3 id="Controlling_what_map_controls_are_displayed">Controlling what map controls are displayed</h3> + +<p>Inside the original <code>google.maps.Map()</code> constructor, you'll see the property <code>disableDefaultUI: true</code> specified. This disables all the standard UI controls you usually get on Google Maps.</p> + +<ol> + <li> + <p>Try setting its value to <code>false</code> (or just removing the line altogether) then reloading your example, and you'll see the map zoom buttons, scale indicator, etc.</p> + </li> + <li> + <p>Now undo your last change.</p> + </li> + <li> + <p>You can show or hide the controls in a more granular fashion by using other properties that specify single UI features. Try adding the following underneath the <code>disableDefaultUI: true</code> (remember to put a comma after <code>disableDefaultUI: true</code>, otherwise you'll get an error):</p> + + <pre class="brush: js">zoomControl: true, +mapTypeControl: true, +scaleControl: true,</pre> + </li> + <li> + <p>Now try reloading the example to see the effect these properties have. You can find more options to experiment with at the <a href="https://developers.google.com/maps/documentation/javascript/3.exp/reference#MapOptions">MapOptions object reference page</a>.</p> + </li> +</ol> + +<p>That's it for now — have a look around the <a href="https://developers.google.com/maps/documentation/javascript/">Google Maps APIs documentation</a>, and have some more fun playing!</p> + +<h2 id="A_RESTful_API_—_NYTimes">A RESTful API — NYTimes</h2> + +<p>Now let's look at another API example — the <a href="https://developer.nytimes.com">New York Times API</a>. This API allows you to retrieve New York Times news story information and display it on your site. This type of API is known as a <strong>RESTful API</strong> — instead of getting data using the features of a JavaScript library like we did with Google Maps, we get data by making HTTP requests to specific URLs, with data like search terms and other properties encoded in the URL (often as URL parameters). This is a common pattern you'll encounter with APIs.</p> + +<h2 id="An_approach_for_using_third-party_APIs">An approach for using third-party APIs</h2> + +<p>Below we'll take you through an exercise to show you how to use the NYTimes API, which also provides a more general set of steps to follow that you can use as an approach for working with new APIs.</p> + +<h3 id="Find_the_documentation">Find the documentation</h3> + +<p>When you want to use a third party API, it is essential to find out where the documentation is, so you can find out what features the API has, how you use them, etc. The New York Times API documentation is at <a href="https://developer.nytimes.com/">https://developer.nytimes.com/</a>.</p> + +<h3 id="Get_a_developer_key">Get a developer key</h3> + +<p>Most APIs require you to use some kind of developer key, for reasons of security and accountability. To sign up for an NYTimes API key, you need to go to <a href="https://developer.nytimes.com/signup">https://developer.nytimes.com/signup</a>.</p> + +<ol> + <li> + <p>Let's request a key for the "Article Search API" — fill in the form, selecting this as the API you want to use.</p> + </li> + <li> + <p>Next, wait a few minutes, then get the key from your email.</p> + </li> + <li> + <p>Now, to start the example off, make copies of <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/third-party-apis/nytimes/nytimes_start.html">nytimes_start.html</a> and <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/third-party-apis/nytimes/nytimes.css">nytimes.css</a> in a new directory on your computer. If you've already <a href="/en-US/docs/Learn#Getting_our_code_examples">cloned the examples repository</a>, you'll already have a copy of these files, which you can find in the <em>javascript/apis/third-party-apis/nytimes</em> directory. Initially the <code><script></code> element contains a number of variables needed for the setup of the example; below we'll fill in the required functionality.</p> + </li> +</ol> + +<p>The app will end up allowing you to type in a search term and optional start and end dates, which it will then use to query the Article Search API and display the search results.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14821/nytimes-search.png" style="border-style: solid; border-width: 1px; display: block; height: 374px; margin: 0px auto; width: 700px;"></p> + +<h3 id="Connect_the_API_to_your_app">Connect the API to your app</h3> + +<p>First, you'll need to make a connection between the API, and your app. This is usually done either by connecting to the API's JavaScript (as we did in the Google Maps API), or by making requests to the correct URL(s).</p> + +<p>In the case of this API, you need to include the API key as a <a href="/en-US/docs/Web/HTTP/Methods/GET">get</a> parameter every time you request data from it.</p> + +<ol> + <li> + <p>Find the following line:</p> + + <pre class="brush: js">var key = 'INSERT-YOUR-API-KEY-HERE';</pre> + + <p>Replace <code>INSERT-YOUR-API-KEY-HERE</code> with the actual API key you got in the previous section.</p> + </li> + <li> + <p>Add the following line to your JavaScript, below the "<code>// Event listeners to control the functionality</code>" comment. This runs a function called <code>fetchResults()</code> when the form is submitted (the button is pressed).</p> + + <pre class="brush: js">searchForm.addEventListener('submit', submitSearch);</pre> + </li> + <li> + <p>Now add the <code>submitSearch()</code> and <code>fetchResults()</code> function definitions, below the previous line:</p> + + <pre class="brush: js">function submitSearch(e) { + pageNumber = 0; + fetchResults(e); +} + +function fetchResults(e) { + // Use preventDefault() to stop the form submitting + e.preventDefault(); + + // Assemble the full URL + url = baseURL + '?api-key=' + key + '&page=' + pageNumber + '&q=' + searchTerm.value <span class="blob-code-inner"><span class="pl-s1"><span class="pl-k x">+</span><span class="x"> </span><span class="pl-s"><span class="pl-pds x">'</span><span class="x">&fq=document_type:("article")</span><span class="pl-pds x x-last">'</span></span></span></span>; + + if(startDate.value !== '') { + url += '&begin_date=' + startDate.value; + }; + + if(endDate.value !== '') { + url += '&end_date=' + endDate.value; + }; + +}</pre> + </li> +</ol> + +<p><code>submitSearch()</code> sets the page number back to 0 to begin with, then calls <code>fetchResults()</code>. This first calls <code><a href="/en-US/docs/Web/API/Event/preventDefault">preventDefault()</a></code> on the event object, to stop the form actually submitting (which would break the example). Next, we use some string manipulation to assemble the full URL that we will make the request to. We start off by assembling the parts we deem as mandatory for this demo:</p> + +<ul> + <li>The base URL (taken from the <code>baseURL</code> variable).</li> + <li>The API key, which has to be specified in the <code>api-key</code> URL parameter (the value is taken from the <code>key</code> variable).</li> + <li>The page number, which has to be specified in the <code>page</code> URL parameter (the value is taken from the <code>pageNumber</code> variable).</li> + <li>The search term, which has to be specified in the <code>q</code> URL parameter (the value is taken from the value of the <code>searchTerm</code> text {{htmlelement("input")}}).</li> + <li>The document type to return results for, as specified in an expression passed in via the <code>fq</code> URL parameter. In this case, we just want to return articles.</li> +</ul> + +<p>Next, we use a couple of <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if()</a></code> statements to check whether the <code>startDate</code> and <code>endDate</code> <code><input></code>s have had values filled in on them. If they do, we append their values to the URL, specified in <code>begin_date</code> and <code>end_date</code> URL parameters respectively.</p> + +<p>So, a complete URL would end up looking something like this:</p> + +<pre>https://api.nytimes.com/svc/search/v2/articlesearch.json?api-key=4f3c267e125943d79b0a3e679f608a78&page=0&q=cats +&<span class="blob-code-inner"><span class="pl-s1"><span class="pl-s"><span class="x">fq=document_type:("article")</span></span></span></span>&begin_date=20170301&end_date=20170312</pre> + +<div class="note"> +<p><strong>Note</strong>: You can find more details of what URL parameters can be included in the <a href="https://developer.nytimes.com/article_search_v2.json">Article Search API reference</a>.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: The example has rudimentary form data validation — the search term field has to be filled in before the form can be submitted (achieved using the <code>required</code> attribute), and the date fields have <code>pattern</code> attributes specified, which means they won't submit unless their values consist of 8 numbers (<code>pattern="[0-9]{8}"</code>). See <a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a> for more details on how these work.</p> +</div> + +<h3 id="Requesting_data_from_the_API">Requesting data from the API</h3> + +<p>Now we've constructed our URL, let's make a request to it. We'll do this using the <a href="/en-US/docs/Web/API/Fetch_API/Using_Fetch">Fetch API</a>.</p> + +<p>Add the following code block inside the <code>fetchResults()</code> function, just above the closing curly brace:</p> + +<pre class="brush: js">// Use fetch() to make the request to the API +fetch(url).then(function(result) { + return result.json(); +}).then(function(json) { + displayResults(json); +});</pre> + +<p>Here we run the request by passing our <code>url</code> variable to <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code>, convert the response body to JSON using the <code><a href="/en-US/docs/Web/API/Body/json">json()</a></code> function, then pass the resulting JSON to the <code>displayResults()</code> function so the data can be displayed in our UI.</p> + +<h3 id="Displaying_the_data">Displaying the data</h3> + +<p>OK, let's look at how we'll display the data. Add the following function below your <code>fetchResults()</code> function.</p> + +<pre class="brush: js">function displayResults(json) { + while (section.firstChild) { + section.removeChild(section.firstChild); + } + + var articles = json.response.docs; + + if(articles.length === 10) { + nav.style.display = 'block'; + } else { + nav.style.display = 'none'; + } + + if(articles.length === 0) { + var para = document.createElement('p'); + para.textContent = 'No results returned.' + section.appendChild(para); + } else { + for(var i = 0; i < articles.length; i++) { + var article = document.createElement('article'); + var heading = document.createElement('h2'); + var link = document.createElement('a'); + var img = document.createElement('img'); + var para1 = document.createElement('p'); + var para2 = document.createElement('p'); + var clearfix = document.createElement('div'); + + var current = articles[i]; + console.log(current); + + link.href = current.web_url; + link.textContent = current.headline.main; + para1.textContent = current.<span class="blob-code-inner"><span class="pl-s1"><span class="pl-smi x x-first x-last">snippet</span></span></span>; + para2.textContent = 'Keywords: '; + for(var j = 0; j < current.keywords.length; j++) { + var span = document.createElement('span'); + span.textContent += current.keywords[j].value + ' '; + para2.appendChild(span); + } + + if(current.multimedia.length > 0) { + img.src = 'http://www.nytimes.com/' + current.multimedia[0].url; + img.alt = current.headline.main; + } + + clearfix.setAttribute('class','clearfix'); + + article.appendChild(heading); + heading.appendChild(link); + article.appendChild(img); + article.appendChild(para1); + article.appendChild(para2); + article.appendChild(clearfix); + section.appendChild(article); + } + } +};</pre> + +<p>There's a lot of code here; let's explain it step by step:</p> + +<ul> + <li>The <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/while">while</a></code> loop is a common pattern used to delete all of the contents of a DOM element, in this case, the {{htmlelement("section")}} element. We keep checking to see if the <code><section></code> has a first child, and if it does, we remove the first child. The loop ends when <code><section></code> no longer has any children.</li> + <li>Next, we set the <code>articles</code> variable to equal <code>json.response.docs</code> — this is the array holding all the objects that represent the articles returned by the search. This is done purely to make the following code a bit simpler.</li> + <li>The first <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if()</a></code> block checks to see if 10 articles are returned (the API returns up to 10 articles at a time.) If so, we display the {{htmlelement("nav")}} that contains the <em>Previous 10</em>/<em>Next 10</em> pagination buttons. If less than 10 articles are returned, they will all fit on one page, so we don't need to show the pagination buttons. We will wire up the pagination functionality in the next section.</li> + <li>The next <code>if()</code> block checks to see if no articles are returned. If so, we don't try to display any — we just create a {{htmlelement("p")}} containing the text "No results returned." and insert it into the <code><section></code>.</li> + <li>If some articles are returned, we, first of all, create all the elements that we want to use to display each news story, insert the right contents into each one, and then insert them into the DOM at the appropriate places. To work out which properties in the article objects contained the right data to show, we consulted the <a href="https://developer.nytimes.com/article_search_v2.json">Article Search API reference</a>. Most of these operations are fairly obvious, but a few are worth calling out: + <ul> + <li>We used a <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for">for loop</a> (<code>for(var j = 0; j < current.keywords.length; j++) { ... }</code> ) to loop through all the keywords associated with each article, and insert each one inside its own {{htmlelement("span")}}, inside a <code><p></code>. This was done to make it easy to style each one.</li> + <li>We used an <code>if()</code> block (<code>if(current.multimedia.length > 0) { ... }</code>) to check whether each article actually has any images associated with it (some stories don't.) We display the first image only if it actually exists (otherwise an error would be thrown).</li> + <li>We gave our <div> element a class of "clearfix", so we can easily apply clearing to it (this technique is needed at the time of writing to stop floated layouts from breaking.)</li> + </ul> + </li> +</ul> + +<p>If you try the example now, it should work, although the pagination buttons won't work yet.</p> + +<h3 id="Wiring_up_the_pagination_buttons">Wiring up the pagination buttons</h3> + +<p>To make the pagination buttons work, we will increment (or decrement) the value of the <code>pageNumber</code> variable, and then re-rerun the fetch request with the new value included in the page URL parameter. This works because the NYTimes API only returns 10 results at a time — if more than 10 results are available, it will return the first 10 (0-9) if the <code>page</code> URL parameter is set to 0 (or not included at all — 0 is the default value), the next 10 (10-19) if it is set to 1, and so on.</p> + +<p>This allows us to easily write a simplistic pagination function.</p> + +<ol> + <li> + <p>Below the existing <code><a href="/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code> call, add these two new ones, which cause the <code>nextPage()</code> and <code>previousPage()</code> functions to be invoked when the relevant buttons are clicked:</p> + + <pre class="brush: js">nextBtn.addEventListener('click', nextPage); +previousBtn.addEventListener('click', previousPage);</pre> + </li> + <li> + <p>Below your previous addition, let's define the two functions — add this code now:</p> + + <pre class="brush: js">function nextPage(e) { + pageNumber++; + fetchResults(e); +}; + +function previousPage(e) { + if(pageNumber > 0) { + pageNumber--; + } else { + return; + } + fetchResults(e); +};</pre> + + <p>The first function is simple — we increment the <code>pageNumber</code> variable, then run the <code>fetchResults()</code> function again to display the next page's results.</p> + + <p>The second function works nearly exactly the same way in reverse, but we also have to take the extra step of checking that <code>pageNumber</code> is not already zero before decrementing it — if the fetch request runs with a minus <code>page</code> URL parameter, it could cause errors. If the <code>pageNumber</code> is already 0, we simply <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/return">return</a></code> out of the function, to avoid wasting processing power (If we are already at the first page, we don't need to load the same results again).</p> + </li> +</ol> + +<h2 id="YouTube_example">YouTube example</h2> + +<p>We also built another example for you to study and learn from — see our <a href="https://mdn.github.io/learning-area/javascript/apis/third-party-apis/youtube/">YouTube video search example</a>. This uses two related APIs:</p> + +<ul> + <li>The <a href="https://developers.google.com/youtube/v3/docs/">YouTube Data API</a> to search for YouTube videos and return results.</li> + <li>The <a href="https://developers.google.com/youtube/iframe_api_reference">YouTube IFrame Player API</a> to display the returned video examples inside IFrame video players so you can watch them.</li> +</ul> + +<p>This example is interesting because it shows two related third-party APIs being used together to build an app. The first one is a RESTful API, while the second one works more like Google Maps (with constructors, etc.). It is worth noting however that both of the APIs require a JavaScript library to be applied to the page. The RESTful API has functions available to handle making the HTTP requests and returning the results, so you don't have to write them out yourself using say fetch or XHR.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14823/youtube-example.png" style="border-style: solid; border-width: 1px; display: block; height: 389px; margin: 0px auto; width: 700px;"></p> + +<p>We are not going to say too much more about this example in the article — <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/third-party-apis/youtube">the source code</a> has detailed comments inserted inside it to explain how it works.</p> + +<h2 id="Summary">Summary</h2> + +<p>This article has given you a useful introduction to using third party APIs to add functionality to your websites.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Client-side_web_APIs/Fetching_data", "Learn/JavaScript/Client-side_web_APIs/Drawing_graphics", "Learn/JavaScript/Client-side_web_APIs")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li> +</ul> diff --git a/files/ru/learn/javascript/howto/index.html b/files/ru/learn/javascript/howto/index.html new file mode 100644 index 0000000000..b3fa76b1cf --- /dev/null +++ b/files/ru/learn/javascript/howto/index.html @@ -0,0 +1,304 @@ +--- +title: Решите общие проблемы в вашем JavaScript-коде +slug: Learn/JavaScript/Howto +tags: + - Начинающий +translation_of: Learn/JavaScript/Howto +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Следующие ссылки указывают на решение общих повседневных проблем, которые вам нужно будет исправить, чтобы код JavaScript работал правильно.</p> + +<h2 id="Частые_ошибки_начинающих">Частые ошибки начинающих</h2> + +<h3 id="Правильное_написание_и_оболочка">Правильное написание и оболочка</h3> + +<p> </p> + +<p>Если ваш код не работает и / или браузер жалуется, что что-то не определено, убедитесь, что вы правильно указали все имена переменных, имена функций и т. д.</p> + +<p>Некоторые общие встроенные функции браузера, которые вызывают проблемы:</p> + +<p> </p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Correct</th> + <th scope="col">Wrong</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>getElementsByTagName()</code></td> + <td><code>getElementbyTagName()</code></td> + </tr> + <tr> + <td><code>getElementsByName()</code></td> + <td><code>getElementByName()</code></td> + </tr> + <tr> + <td><code>getElementsByClassName()</code></td> + <td><code>getElementByClassName()</code></td> + </tr> + <tr> + <td><code>getElementById()</code></td> + <td><code>getElementsById()</code></td> + </tr> + </tbody> +</table> + +<h3 id="Положение_двоеточия_точки_с_запятой">Положение двоеточия / точки с запятой</h3> + +<p>Вам нужно убедиться, что вы не помещаете точки с запятой неправильно. Например:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Correct</th> + <th scope="col">Wrong</th> + </tr> + <tr> + <td><code>elem.style.color = 'red';</code></td> + <td><code>elem.style.color = 'red;'</code></td> + </tr> + </thead> +</table> + +<h3 id="Функции">Функции</h3> + +<p> </p> + +<p>Есть ряд вещей, которые могут пойти не так с функциями.</p> + +<p>Одна из наиболее распространенных ошибок - объявить функцию, но не называть ее нигде. Например</p> + +<p>:</p> + +<pre class="brush: js">function myFunction() { + alert('This is my function.'); +};</pre> + +<p>Этот код ничего не сделает, если вы его не назовете, например</p> + +<pre class="brush: js">myFunction();</pre> + +<h4 id="Область_действия">Область действия</h4> + +<p>Помнините, что <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_scope_and_conflicts">functions have their own scope</a> —вы не можете получить доступ к значению переменной, установленному внутри функции извне функции, если вы не объявили переменную глобально (т. е. не внутри каких-либо функций), или <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">return the value</a> из функции.</p> + +<h4 id="Запуск_кода_после_оператора_возврата">Запуск кода после оператора возврата</h4> + +<p> </p> + +<p>Помните также, что когда вы возвращаете значение из функции, интерпретатор JavaScript выходит из функции - никакой код после выполнения оператора return не выполняется.</p> + +<p>Фактически, некоторые браузеры (например, Firefox) выдадут вам сообщение об ошибке в консоли разработчика, если у вас есть код после оператора return. Firefox дает вам «недостижимый код после оператора возврата».</p> + +<p> </p> + +<h3 id="Обозначение_объекта_по_сравнению_с_обычным_назначением">Обозначение объекта по сравнению с обычным назначением</h3> + +<p>Когда вы назначаете что-то в JavaScript, вы используете один знак равенства, например:</p> + +<pre class="brush: js">var myNumber = 0;</pre> + +<p>Это не работает в <a href="/en-US/docs/Learn/JavaScript/Objects">Objects</a>, однако - с объектами, вам нужно отделить имена членов от их значений, используя двоеточия, и разделить каждый элемент запятой, например:</p> + +<pre class="brush: js">var myObject = { + name : 'Chris', + age : 38 +}</pre> + +<h2 id="Basic_definitions">Basic definitions</h2> + +<div class="column-container"> +<div class="column-half"> +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#A_high-level_definition">What is JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#What_is_a_variable">What is a variable?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">What are strings?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#What_is_an_Array">What is an array?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">What is a loop?</a></li> +</ul> +</div> + +<div class="column-half"> +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">What is a function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">What is an event?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Object_basics">What is an object?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#No_really_what_is_JSON">What is JSON?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction#What_are_APIs">What is a web API?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#The_document_object_model">What is the DOM?</a></li> +</ul> +</div> +</div> + +<h2 id="Basic_use_cases">Basic use cases</h2> + +<div class="column-container"> +<div class="column-half"> +<h3 id="General">General</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#How_do_you_add_JavaScript_to_your_page">How do you add JavaScript to your page?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#Comments">How do you add comments to JavaScript code?</a></li> +</ul> + +<h3 id="Variables">Variables</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Declaring_a_variable">How do you declare a variable?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Initializing_a_variable">How do you initialize a variable with a value?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#Updating_a_variable">How do you update a variable's value?</a> (also see <a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Assignment_operators">Assignment operators</a>)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#Variable_types">What data types can values have in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Loose_typing">What does 'loosely typed' mean?</a></li> +</ul> + +<h3 id="Math">Math</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Types_of_numbers">What types of number do you have to deal with in web development?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Arithmetic_operators">How do you do basic math in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Operator_precedence">What is operator precedence, and how is it handled in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Increment_and_decrement_operators">How do you increment and decrement values in JavaScript?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Math#Comparison_operators">How do you compare values in JavaScript?</a> (e.g. to see which one is bigger, or to see if one value is equal to another).</li> +</ul> + +<h3 id="Strings">Strings</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Creating_a_string">How do you create a string in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Single_quotes_versus_double_quotes">Do you have to use single quotes or double quotes?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Escaping_characters_in_a_string">How do you escape characters in strings?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Concatenating_strings">How do you join strings together?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Numbers_versus_strings">Can you join strings and numbers together?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Finding_the_length_of_a_string">How do you find the length of a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Retrieving_a_specific_string_character">How you find what character is at a certain position in a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Finding_a_substring_inside_a_string_and_extracting_it">How do you find and extract a specific substring from a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Changing_case">How do you change the case of a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Updating_parts_of_a_string">How do you replace one specific substring with another?</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Arrays">Arrays</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Creating_an_array">How do you create an array?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Accessing_and_modifying_array_items">How do you access and modify the items in an array?</a> (this includes multidimensional arrays)</li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Finding_the_length_of_an_array">How do you find the length of an array?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Adding_and_removing_array_items">How you add and remove array items?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Converting_between_strings_and_arrays">How do you split a string into array items, or join array items into a string?</a></li> +</ul> + +<h3 id="Debugging_JavaScript">Debugging JavaScript</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong#Types_of_error">What are the basic types of error?</a></li> + <li><a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools, and how do you access them?</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#The_Console_API">How do you log a value to the JavaScript console?</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#Using_the_JavaScript_debugger">How do you use breakpoints, and other JavaScript debugging features?</a></li> +</ul> + +<p>For more information on JavaScript debugging, see <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Handling common JavaScript problems</a>; also see <a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong#Other_common_errors">Other common errors</a> for a description of common errors.</p> + +<h3 id="Making_decisions_in_code">Making decisions in code</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">How do you execute different blocks of code, depending on a variable's value or other condition?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#if_..._else_statements">How do you use if ...else statements?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Nesting_if_..._else">How do nest one decision block inside another?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Logical_operators_AND_OR_and_NOT">How do you use AND, OR, and NOT operators in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#switch_statements">How do you conveniently handle a large number of choices for one condition?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Ternary_operator">How do you use a ternary operator to make a quick choice between two options based on a true or false test?</a></li> +</ul> + +<h3 id="Loopingiteration">Looping/iteration</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">How do you run the same bit of code over and over again?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#Exiting_loops_with_break">How do you exit a loop before the end if a certain condition is met?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#Skipping_iterations_with_continue">How do you skip to the next iteration of a loop if a certain condition is met?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#while_and_do_..._while">How do you use while and do ... while loops?</a></li> + <li>How to iterate over the elements in an array</li> + <li>How to iterate over the elements in a multidimensional array</li> + <li>How to iterate over the members in an object</li> + <li>How to iterate over the members of an object nested inside an array</li> +</ul> +</div> +</div> + +<h2 id="Intermediate_use_cases">Intermediate use cases</h2> + +<div class="column-container"> +<div class="column-half"> +<h3 id="Functions">Functions</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Built-in_browser_functions">How do you find functions in the browser?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Functions_versus_methods">What is the difference between a function and a method?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">How do you create your own functions?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Invoking_functions">How do you run (call, or invoke) a function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Anonymous_functions">What is an anonymous function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_parameters">How do you specify parameters (or arguments) when invoking a function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_scope_and_conflicts">What is function scope?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">What are return values, and how do you use them?</a></li> +</ul> + +<h3 id="Objects">Objects</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Object_basics">How do you create an object?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Dot_notation">What is dot notation?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation">What is bracket notation?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Setting_object_members">How do you get and set the methods and properties of an object?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#What_is_this">What is <code>this</code>, in the context of an object?</a></li> + <li><a href="/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">What is object-oriented programming?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Constructors_and_object_instances">What are constructors and instances, and how do you create them?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Other_ways_to_create_object_instances">What different ways are there to create objects in JavaScript?</a></li> +</ul> + +<h3 id="JSON">JSON</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#JSON_structure">How do you structure JSON data, and read it from JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#Loading_our_JSON">How can you load a JSON file into a page?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#Converting_between_objects_and_text">How do you convert a JSON object to a text string, and back again?</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Events">Events</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_handler_properties">What are event handlers and how do you use them?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Inline_event_handlers_%E2%80%94_don%27t_use_these">What are inline event handlers?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#addEventListener()_and_removeEventListener()">What does the <code>addEventListener()</code> function do, and how do you use it?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#What_mechanism_should_I_use">Which mechanism should I use to add event code to my web pages?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_objects">What are event objects, and how do you use them?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Preventing_default_behaviour">How do you prevent default event behaviour?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture">How do events fire on nested elements? (event propagation, also related — event bubbling and capturing)</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation">What is event delegation, and how does it work?</a></li> +</ul> + +<h3 id="Object-oriented_JavaScript">Object-oriented JavaScript</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">What are object prototypes?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes#The_constructor_property">What is the constructor property, and how can you use it?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes#Modifying_prototypes">How do you add methods to the constructor?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">How do you create a new constructor that inherits its members from a parent constructor?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance#Object_member_summary">When should you use inheritance in JavaScript?</a></li> +</ul> + +<h3 id="Web_APIs">Web APIs</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#Active_learning_Basic_DOM_manipulation">How do you manipulate the DOM (e.g. adding or removing elements) using JavaScript?</a></li> +</ul> + +<p> </p> +</div> +</div> diff --git a/files/ru/learn/javascript/index.html b/files/ru/learn/javascript/index.html new file mode 100644 index 0000000000..586c33a969 --- /dev/null +++ b/files/ru/learn/javascript/index.html @@ -0,0 +1,64 @@ +--- +title: JavaScript +slug: Learn/JavaScript +tags: + - JavaScript + - Начала + - Начинающий + - Основы +translation_of: Learn/JavaScript +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">{{Glossary("JavaScript")}} — это язык программирования, который даёт возможность реализовывать сложное поведение веб-страницы. Каждый раз, когда вы видите веб-страницу, она не только отображает статическое содержимое, но и делает большее - своевременно отображает обновление контента, выводит интерактивные карты, 2D/3D анимацию, прокручивает видео и т.д. - будьте уверены, здесь не обошлось без JavaScript.</p> + +<h2 id="Учебный_план">Учебный план</h2> + +<p>Считается, что JavaScript сложнее изучить, чем связанные с ним технологии, наподобие <a href="/ru/docs/Learn/HTML">HTML</a> и <a href="/ru/docs/Learn/CSS">CSS</a>. Поэтому, перед изучением JavaScript, настоятельно рекомендуем сначала ознакомиться хотя бы с этими двумя технологиями. Начните с проработки следующих модулей:</p> + +<ul> + <li><a href="/ru/docs/Learn/Getting_started_with_the_web">Начало работы с Веб</a></li> + <li><a href="/ru/docs/Web/Guide/HTML/Introduction">Введение в HTML</a></li> + <li><a href="/ru/docs/Learn/CSS/First_steps">Введение в CSS</a></li> +</ul> + +<p>Имеющийся опыт программирования на других языках также может помочь в обучении.</p> + +<p>После изучения основ JavaScript вы будете готовы к ознакомлению с более сложными темами, например:</p> + +<ul> + <li>Углубленный курс JavaScript, изложенный в нашем <a href="/ru/docs/Web/JavaScript/Guide">Руководстве по JavaScript</a></li> + <li><a href="/ru/docs/Web/API">Программный интерфейс WebAPI</a></li> +</ul> + +<h2 id="Модули">Модули</h2> + +<p>Этот раздел содержит следующие модули, проходить которые рекомендуется в порядке перечисления.</p> + +<dl> + <dt><a href="/ru/docs/Learn/JavaScript/Первые_шаги">Первые шаги в JavaScript</a></dt> + <dd>В нашем первом модуле, посвященном JavaScript, мы сначала ответим на несколько главных вопросов, таких, как "Что такое JavaScript?", "На что он похож?" и "Что с его помощью можно сделать?", а затем перейдем к практике - расскажем, как писать и выполнять код на JavaScript. После чего подробнее рассмотрим некоторые ключевые конструкции JavaScript: переменные, строки, числа и массивы.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks">Структурные элементы JavaScript</a></dt> + <dd>В этом модуле мы продолжим изучение главных составных частей JavaScript и обратим внимание на повсеместно встречающиеся типы конструкций: условные операторы, циклы, функции и события. В ходе обучения Вы уже сталкивались с ними, но только мимоходом. Теперь мы поговорим именно о них.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Объекты">Введение в объекты JavaScript</a></dt> + <dd>Практически всё, что встречается в JavaScript, является объектом. Начиная с таких ключевых конструкций, как строки и массивы, и заканчивая интерфейсом взаимодействия с браузером, который построен поверх JavaScript. Вы даже можете создавать собственные объекты, заключая взаимосвязанные функции и переменные в готовые пакеты. Если Вы хотите продолжить изучение языка и писать более эффективный код, то очень важно понять объектно-ориентированную природу JavaScript. Чтобы помочь Вам в этом, мы представляем этот модуль. В нем мы подробно рассматриваем основы и синтаксис ООП (объектно-ориентированного программирования), показываем, как создавать свои объекты, и объясняем, что такое данные в формате JSON и как с ними работать.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Client-side_web_APIs">Клиентский Web API</a></dt> + <dd>При написании клиентского JavaScript для сайтов или приложений вы не обойдётесь без использования API - то есть интерфейсов для работы с различными функциями браузера или операционной системы, на которой работает сайт, или даже для работы с данными, получаемыми с других сайтов или сервисов. В этом модуле мы изучим, какие это API и как использовать некоторые наиболее распространённые API, которые вам будут часто попадаться во время разработки.</dd> +</dl> + +<h2 id="Решение_общих_проблем_на_JavaScript">Решение общих проблем на JavaScript</h2> + +<p>Статья <a href="/ru/docs/Learn/JavaScript/Howto">Использование JavaScript для решения общих проблем</a> предоставляет ссылки к секциям контента, раскрывающих суть того, как использовать JavaScript для решения очень часто встречающихся проблем при создании веб-страницы.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<dl> + <dt><a href="/ru/docs/Web/JavaScript">JavaScript на MDN</a></dt> + <dd>Главная точка входа к ядру JavaScript-документации на MDN — то место, где вы найдёте обширную справочную документация по всем аспектам языка JavaScript, и некоторые продвинутые учебники для опытных JavaScript-разработчиков.</dd> + <dt><a href="https://learnjavascript.online">Learn JavaScript</a></dt> + <dd>Отличный ресурс для начинающих веб-разработчиков - изучайте JavaScript в интерактивной среде, с короткими уроками и интерактивными тестами с автоматизированной оценкой. Первые 40 уроков бесплатно, а полный курс доступен за небольшую разовую плату.</dd> + <dt><a href="https://exlskills.com/learn-en/courses/javascript-fundamentals-basics_javascript">JavaScript Fundamentals на EXLskills</a></dt> + <dd>Изучайте JavaScript бесплатно с курсом с открытым исходным кодом EXLskills, который знакомит вас со всем необходимым, чтобы начать создавать приложения в JS.</dd> + <dt><a href="https://www.youtube.com/user/codingmath">Математика для программиста</a></dt> + <dd>Великолепная серия видеоуроков по математике от <a href="https://twitter.com/bit101">Keith Peters</a>, которую необходимо понимать каждому эффективному программисту</dd> +</dl> diff --git a/files/ru/learn/javascript/объекты/adding_bouncing_balls_features/index.html b/files/ru/learn/javascript/объекты/adding_bouncing_balls_features/index.html new file mode 100644 index 0000000000..fe97392371 --- /dev/null +++ b/files/ru/learn/javascript/объекты/adding_bouncing_balls_features/index.html @@ -0,0 +1,212 @@ +--- +title: Добавление функций в нашу демонстрацию отбойных шаров +slug: Learn/JavaScript/Объекты/Adding_bouncing_balls_features +translation_of: Learn/JavaScript/Objects/Adding_bouncing_balls_features +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">В этом упражнении мы будем использовать проект прыгающих шаров из предыдущей статьи и добавим в него новые интересные возможности.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Перед тем как приступить к этому упражнению нужно выполнить задания из всех статей текущего модуля.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Проверить насколько хорошо вы понимаете объекты и связанные с ними конструкции в языке Javascript. </td> + </tr> + </tbody> +</table> + +<h2 id="Начало">Начало</h2> + +<p>Для начала скопируйте файлы <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/index-finished.html">index-finished.html</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/style.css">style.css</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/main-finished.js">main-finished.js</a> из предыдущей статьи в новую директорию на вашем компьютере.</p> + +<p>Для выполнения упражнения вы можете использовать сайт <a class="external external-icon" href="http://jsbin.com/">JSBin</a> или <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a>. Вы можете вставлять HTML, CSS и JavaScript код в один из этих онлайн-редакторов. Если ваш онлайн-редактор не поддерживает раздельные панели для редактирования JavaScript/CSS кода, то вы можете встроить код в HTML с помощью тегов <code><script></code>/<code><style></code>.</p> + +<div class="note"> +<p><strong>Примечание</strong>. Если у вас что-то не получается — попросите о помощи. Более подробная информация находится в секции {{anch("Assessment or further help")}} в конце этой страницы.</p> +</div> + +<h2 id="Краткое_описание_проекта">Краткое описание проекта</h2> + +<p>Наша веселая демонстрация шаров - это весело, но теперь мы хотим сделать ее немного более интерактивной, добавив контролируемый пользователем злой круг, который будет есть шары, если он их поймает. Мы также хотим проверить ваши навыки создания объектов, создав общий объект <code>Shape()</code>, который могут наследовать наши шары и злой круг. Наконец, мы хотим добавить счетчик очков, чтобы отслеживать количество оставшихся шаров для захвата.</p> + +<p>Следующий скриншот дает вам представление о том, как должна выглядеть готовая программа:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13875/bouncing-evil-circle.png" style="display: block; margin: 0 auto;"></p> + +<ul> +</ul> + +<p>Чтобы дать вам больше идеи, посмотрите на <a href="https://mdn.github.io/learning-area/javascript/oojs/assessment/">законченный пример</a> (не заглядывая в исходный код!)</p> + +<h2 id="Шаги_по_завершению">Шаги по завершению</h2> + +<p>В следующих разделах описывается, что вам нужно делать.</p> + +<h3 id="Создание_наших_новых_объектов">Создание наших новых объектов</h3> + +<p>Прежде всего, измените существующий конструктор <code>Ball()</code> так, чтобы он стал конструктором <code>Shape()</code> и добавил новый конструктор <code>Ball()</code>:</p> + +<ol> + <li>Конструктор <code>Shape()</code> должен определять свойства <code>x</code>, <code>y</code>, <code>velX</code> и <code>velY</code>, так же, как и конструктор <code>Ball()</code>, но не свойства <code>color</code> и <code>size</code>.</li> + <li>Он также должен определить новое свойство<code>exists</code>, которое используется для отслеживания наличия шаров в программе (не было съедено злым кругом). Это должно быть логическое (<code>true</code> / <code>false</code>).</li> + <li>Конструктор <code>Ball()</code> должен наследовать свойства <code>x</code>, <code>y</code>, <code>velX</code>, <code>velY</code> и <code>exists</code> из конструктора <code>Shape()</code>.</li> + <li>Он также должен определить свойство <code>color</code> и <code>size</code>, как это сделал оригинальный конструктор <code>Ball()</code>.</li> + <li>Не забудьте установить <code>prototype</code> и <code>constructor</code> конструктора <code>Ball()</code> соответствующим образом.</li> +</ol> + +<p>Определения меток шара <code>draw()</code>, <code>update()</code> и <code>collisionDetect()</code> должны быть такими же, как и раньше.</p> + +<p>Вам также нужно добавить новый параметр в новый вызов конструктора <code>new Ball() ( ... )</code> - параметр <code>exists</code> должен быть 5-м параметром и ему должно быть присвоено значение <code>true</code>.</p> + +<p>На этом этапе попробуйте перезагрузить код - он должен работать так же, как и раньше, с нашими перепроектированными объектами.</p> + +<h3 id="Определение_EvilCircle">Определение EvilCircle()</h3> + +<p>Теперь пришло время встретить плохого парня - <code>EvilCircle()</code>! Наша игра будет включать только один злой круг, но мы все еще будем определять его с помощью конструктора, который наследует от <code>Shape()</code>, чтобы дать вам некоторую практику. Возможно, вам захочется добавить еще один круг в приложение, которое может контролироваться другим игроком или иметь несколько злобных окружений, управляемых компьютером. Вы, вероятно, не собираетесь захватить мир одним злым кругом, но он будет делать для этой оценки.</p> + +<p>Конструктор <code>EvilCircle()</code> должен наследовать <code>x</code>, <code>y</code>, <code>velX</code>, <code>velY</code> и <code>exists</code> из <code>Shape()</code>, но <code>velX</code> и <code>velY</code> должны всегда равняться 20.</p> + +<p>Вы должны сделать что-то вроде <code>Shape.call(this, x, y, 20, 20, exists);</code></p> + +<p>Он также должен определить свои собственные свойства следующим образом:</p> + +<ul> + <li><code>color</code> — <code>'white'</code></li> + <li><code>size</code> — <code>10</code></li> +</ul> + +<p>Опять же, не забудьте определить свои унаследованные свойства как параметры в конструкторе и правильно установить свойства <code>prototype</code> и <code>constructor</code>.</p> + +<h3 id="Defining_EvilCircles_methods">Defining EvilCircle()'s methods</h3> + +<p><code>EvilCircle()</code> должен иметь четыре метода, как описано ниже.</p> + +<h4 id="draw"><code>draw()</code></h4> + +<p>Этот метод имеет ту же цель, что и метод <code>draw()</code> метода <code>Ball()</code>: он рисует экземпляр объекта на холсте. Он будет работать очень схожим образом, поэтому вы можете начать с копирования определения <code>Ball.prototype.draw</code>. Затем вы должны внести следующие изменения:</p> + +<ul> + <li>Мы хотим, чтобы злой круг не был заполнен, а скорее имел внешнюю линию (удар). Вы можете добиться этого, обновив <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle">fillStyle</a></code> и <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fill">fill()</a></code> до <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeStyle">strokeStyle</a></code> и s<code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/stroke">stroke()</a></code>.</li> + <li>Мы также хотим сделать ход немного толще, так что вы можете увидеть злой круг немного легче. Этого можно добиться, установив значение для <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth">lineWidth</a></code> где-нибудь после вызова <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/beginPath">beginPath()</a></code> (3 будем делать).</li> +</ul> + +<h4 id="checkBounds"><code>checkBounds()</code></h4> + +<p>Этот метод будет делать то же самое, что и первая часть функции <code>Ball()</code>'s <code>update()</code>, чтобы посмотреть, не исчезнет ли злой круг от края экрана и не прекратит это делать. Опять же, вы можете просто скопировать определение <code>Ball.prototype.update</code>, но есть несколько изменений, которые вы должны сделать:</p> + +<ul> + <li>Избавьтесь от последних двух строк - мы не хотим автоматически обновлять позицию злого круга на каждом кадре, потому что мы будем перемещать его каким-то другим способом, как вы увидите ниже.</li> + <li>Внутри операторов <code>if()</code>, если тесты возвращают true, мы не хотим обновлять <code>velX</code> / <code>velY</code>; мы хотим вместо этого изменить значение <code>x</code> / <code>y</code>, так что злой круг возвращается на экран немного. Добавление или вычитание (по мере необходимости) свойства <code>size</code> злого круга имеет смысл.</li> +</ul> + +<h4 id="setControls"><code>setControls()</code></h4> + +<p>Этот метод добавит прослушиватель событий <code>onkeydown</code> к объекту <code>window</code>, чтобы при нажатии определенных клавиш клавиатуры мы могли перемещать злой круг вокруг. Следующий код должен быть помещен внутри определения метода:</p> + +<pre class="brush: js">var _this = this; +window.onkeydown = function(e) { + if (e.keyCode === 65) { + _this.x -= _this.velX; + } else if (e.keyCode === 68) { + _this.x += _this.velX; + } else if (e.keyCode === 87) { + _this.y -= _this.velY; + } else if (e.keyCode === 83) { + _this.y += _this.velY; + } + }</pre> + +<p>Поэтому, когда нажата клавиша, проконсультируется о свойствах <a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode">keyCode</a> объекта события, чтобы увидеть, какая клавиша нажата. Если это один из четырех, представленных указанными ключевыми кодами, тогда злой круг будет перемещаться влево / вправо / вверх / вниз.</p> + +<ul> + <li>Для бонусного пункта сообщите нам, к каким ключам относятся указанные коды ключей.</li> + <li>В другой бонусной точке вы можете сказать нам, почему нам пришлось установить <code>var _this = this</code>; в позиции, в которой он находится? Это как-то связано с функциональной областью.</li> +</ul> + +<h4 id="collisionDetect"><code>collisionDetect()</code></h4> + +<p>Этот метод будет действовать очень похоже на метод <code>collisionDetect()</code> в <code>Ball()</code>, поэтому вы можете использовать его в качестве основы для этого нового метода. Но есть несколько отличий:</p> + +<ul> + <li>В внешнем выражении <code>if</code> вам больше не нужно проверять, совпадает ли текущий мяч на итерации с шаром, который выполняет проверку, потому что он больше не является мячиком, это злой круг! Вместо этого вам нужно выполнить проверку, чтобы проверить, существует ли проверенный шар (с каким свойством вы могли бы это сделать?). Если этого не существует, он уже был съеден злым кругом, поэтому нет необходимости проверять его снова.</li> + <li>Во внутреннем <code>if</code>-выражении вы больше не хотите, чтобы объекты меняли цвет при обнаружении столкновения - вместо этого вы хотите установить любые шары, которые сталкиваются с злым кругом, чтобы больше не существовать (опять же, как вы думаете, d сделать это?).</li> +</ul> + +<h3 id="Приведение_злого_круга_в_программу">Приведение злого круга в программу</h3> + +<p>Теперь мы определили злой круг, нам нужно на самом деле заставить его появиться на нашей сцене. Для этого вам нужно внести некоторые изменения в функцию <code>loop()</code>.</p> + +<ul> + <li>Прежде всего, создайте новый экземпляр объекта злого круга (указав необходимые параметры), затем вызовите его метод <code>setControls()</code>. Вам нужно только сделать эти две вещи один раз, а не на каждой итерации цикла.</li> + <li>В точке, где вы прокручиваете каждый шар и вызываете функции <code>draw()</code>, <code>update()</code> и <code>collisionDetect()</code> для каждого из них, делайте так, чтобы эти функции вызывались только в том случае, если текущий шар существует.</li> + <li>На каждой итерации цикла вызовите методы draw <code>draw()</code>, <code>checkBounds()</code> и <code>collisionDetect()</code> для злого шарика.</li> +</ul> + +<h3 id="Реализация_счетчика_баллов">Реализация счетчика баллов</h3> + +<p>Чтобы выполнить счетчик счетчиков, выполните следующие действия:</p> + +<ol> + <li>В своем HTML-файле добавьте элемент {{HTMLElement ("p")}} непосредственно под элементом {{HTMLElement ("h1")}}, содержащим текст «Ball count:».</li> + <li>В вашем файле CSS добавьте следующее правило внизу: + <pre class="brush: css">p { + position: absolute; + margin: 0; + top: 35px; + right: 5px; + color: #aaa; +}</pre> + </li> + <li>В своем JavaScript сделайте следующие обновления: + <ul> + <li>Создайте переменную, которая хранит ссылку на абзац.</li> + <li>Держите подсчет количества шаров на экране в некотором роде.</li> + <li>Увеличьте количество и покажите обновленное количество шаров каждый раз, когда шар добавляется в сцену.</li> + <li>Уменьшите счет и покажите обновленное количество мячей каждый раз, когда злой круг ест шарик (его не существует).</li> + </ul> + </li> +</ol> + +<h2 id="Советы_и_подсказки">Советы и подсказки</h2> + +<ul> + <li>Эта оценка довольно сложная. Делайте каждый шаг медленно и осторожно.</li> + <li>Может быть, идея сохранить отдельную копию демонстрации после того, как вы получите каждый этап работы, так что вы можете вернуться к ней, если позже окажетесь в беде.</li> +</ul> + +<h2 id="Assessment">Assessment</h2> + +<p>Если вы проводите эту оценку в рамках организованного курса, вы должны уметь отдать свою работу своему учителю / наставнику для маркировки. Если вы самообучаетесь, то вы можете получить руководство по маркировке довольно легко, задав <a href="https://discourse.mozilla.org/t/adding-features-to-our-bouncing-balls-demo-assessment/24689">тему обсуждения для этого упражнения</a> или в IRC-канале <a href="irc://irc.mozilla.org/mdn">#mdn</a> в <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Сначала попробуйте упражнение - ничего не выиграть от обмана!</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_building_practice", "", "Learn/JavaScript/Objects")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> +</ul> + + + +<div class="s3gt_translate_tooltip_mini_box" id="s3gt_translate_tooltip_mini" style="background: initial !important; border: initial !important; border-radius: initial !important; border-collapse: initial !important; direction: ltr !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; max-width: initial !important; min-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; text-align: initial !important; text-shadow: initial !important; width: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 112px; top: 698px; opacity: 0;"> +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_logo" style="width: 12px; height: 12px; border-radius: 4px;" title="Перевести выделенный фрагмент"></div> + +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_sound" style="width: 12px; height: 12px; border-radius: 4px;" title="Прослушать"></div> + +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_copy" style="width: 12px; height: 12px; border-radius: 4px;" title="Скопировать текст в буфер обмена"></div> +</div> diff --git a/files/ru/learn/javascript/объекты/index.html b/files/ru/learn/javascript/объекты/index.html new file mode 100644 index 0000000000..9acc354feb --- /dev/null +++ b/files/ru/learn/javascript/объекты/index.html @@ -0,0 +1,47 @@ +--- +title: Введение в объекты JavaScript +slug: Learn/JavaScript/Объекты +tags: + - JavaScript + - Начинающим + - Объекты + - Руководства +translation_of: Learn/JavaScript/Objects +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">В JavaScript большинство сущностей являются объектами, начиная с самого основного функционала JavaScript, такого как строки (strings) и массивы (array), и заканчивая встроенными в браузер API. Вы можете даже создавать свои собственные объекты, чтобы инкапсулировать связанные между собой функции и переменные в эффективные пакеты и действовать как удобные хранилища данных. Понимание объектно-ориентированной природы JavaScript очень важно, если Вы хотите продолжить дальнейшее более углубленное изучение языка. Поэтому мы предоставляем Вам данный модуль, чтобы помочь Вам разобраться в этом. Здесь мы детально обучим Вас теории и синтаксису объектов, а затем рассмотрим, как создавать свои собственные объекты. </p> + +<h2 id="Необходимые_знания">Необходимые знания</h2> + +<p>Перед тем, как начать изучение данного модуля, Вы должны иметь некоторое представление о HTML и CSS. Мы советуем Вам поработать над разделами <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Introduction">Введение в HTML</a> и <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a> перед изучением этого модуля JavaScript.</p> + +<p>Также Вам необходимо знать основы JavaScript перед подробным изучением объектов JavaScript. Предварительно поработайте с разделами <a href="/en-US/docs/Learn/JavaScript/First_steps">Первые шаги в JavaScript</a> и <a href="/en-US/docs/Learn/JavaScript/Building_blocks">Структурные элементы в JavaScript</a> перед началом изучения данного модуля.</p> + +<div class="note"> +<p><span style="font-size: 14px;"><strong>Примечание</strong></span>: Если Вы работаете за компьютером/планшетом/другим устройством, на котором у Вас нет возможности создавать собственные файлы, постарайтесь поработать с примерами кода на платформах онлайн-программирования, таких, как <a href="http://jsbin.com/">JSBin</a> or <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<dl> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B">Основы объектов</a></dt> + <dd>В первой статье мы рассмотрим объекты в JavaScript. Мы будем разбирать основы синтаксиса объектов JavaScript и заново изучим некоторый функционал JavaScript, который мы уже исследовали ранее на курсе, подтвердив тот факт, что большая часть функционала, с которым мы уже столкнулись, в действительности является объектами.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Объектно-ориентированный JavaScript для начинающих</a></dt> + <dd>Закончив с основами, мы сфокусируемся на объектно-ориентированном JavaScript (OOJS) — эта статья представляет основы теории объектно-ориентированного программирования (ООП). Затем мы изучим, как JavaScript эмулирует классы объектов через конструктор функций, и как создавать экземпляры объектов.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Прототипы объектов</a></dt> + <dd>Прототипы - это механизм, благодаря которому объекты в JavaScript наследуют функционал друг друга, но при этом они работают иначе по сравнению с механизмами наследования в классических объектно-ориентированных языках. В этой статье мы изучим эти отличия, объясним, как работает цепочка прототипов, и рассмотрим, как свойство прототипа может быть использовано для добавления методов к существующим конструкторам.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Наследование в JavaScript</a></dt> + <dd>После знакомства с самыми жуткими подробностями OOJS, эта статья покажет, как создавать "дочерные" классы объектов (конструкторы), которые наследуют функционал от своих "родительских" классов. В дополнении, мы дадим Вам пару советов о том, где и когда можно использовать OOJS.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Работа с JSON-данными</a></dt> + <dd>Представление объектов в JavaScript (JavaScript Object Notation) (JSON) - это стандартный формат для представления структурированных данных в виде объектов JavaScript, который обычно используется для представления и передачи данных на веб-сайтах (т.е. передача некоторых данных от сервера к клиенту - таким образом они могут быть отображены на веб-странице). Вы довольно часто будете с этим сталкиваться, поэтому в данной статье мы предоставим вам все, что необходимо для работы с JSON с помощью JavaScript, в том числе доступ к элементам данных в объекте JSON и написания собственного JSON-кода.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Практика построения объектов</a></dt> + <dd>В предыдущих статьях мы рассматривали самые основные моменты в теории и синтаксисе объектов в JavaScript, дав Вам твердую основу для начала. В этой статье мы погрузимся в практические занятия, получим больше практической работы в построении собственных объектов в JavaScript, чтобы сделать кое-что веселое и красочное - несколько цветных прыгающих шариков.</dd> +</dl> + +<h2 id="Задания">Задания</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Добавление функционала к демо с прыгающими шариками</a></dt> + <dd>В этом задании, мы ожидаем, что Вы, используя демо с прыгающими шариками из предыдущей статьи как отправную точку, добавите немного нового и интересного функционала в него.</dd> +</dl> diff --git a/files/ru/learn/javascript/объекты/inheritance/index.html b/files/ru/learn/javascript/объекты/inheritance/index.html new file mode 100644 index 0000000000..c1565cd72f --- /dev/null +++ b/files/ru/learn/javascript/объекты/inheritance/index.html @@ -0,0 +1,266 @@ +--- +title: Наследование в JavaScript +slug: Learn/JavaScript/Объекты/Inheritance +tags: + - JavaScript + - Наследование + - ООП +translation_of: Learn/JavaScript/Objects/Inheritance +--- +<p> + <audio class="audio-for-speech"></audio> +</p> + +<div class="translate-tooltip-mtz hidden"> +<div class="header"> +<div class="header-controls"></div> + +<div class="translate-icons"><img class="from" src=""> <img class="arrow"> <img class="to" src=""></div> +</div> + +<div class="translated-text"> +<div class="words"></div> + +<div class="sentences"></div> +</div> +</div> + +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">Теперь, когда объясняется большая часть подробностей OOJS, эта статья показывает, как создавать «дочерние» классы объектов (конструкторы), которые наследуют признаки из своих «родительских» классов. Кроме того, мы дадим некоторые советы о том, когда и где вы можете использовать OOJS , и посмотрим, как классы рассматриваются в современном синтаксисе ECMAScript.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Базовая компьютерная грамотность, понимание основ HTML и CSS, знакомство с основами JavaScript (см. <a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8">Первые шаги</a> и <a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks">Структурные элементы</a>) and основы Объектно-ориентированного JS (см. <a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B">Введение в объекты</a>).</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять, как можно реализовать наследование в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Прототипное_наследование">Прототипное наследование</h2> + +<p>До сих пор мы видели некоторое наследование в действии - мы видели, как работают прототипы и как элементы наследуются, поднимаясь по цепочке. Но в основном это связано с встроенными функциями браузера. Как создать объект в JavaScript, который наследует от другого объекта?</p> + +<p>Давайте рассмотрим, как это сделать на конкретном примере.</p> + +<h2 id="Начало_работы">Начало работы</h2> + +<p>Прежде всего сделайте себе локальную копию нашего файла <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-start.html">oojs-class-inheritance-start.html</a> (он также работает <a href="https://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-start.html">в режиме реального времени</a>). В файле вы найдете тот же пример конструктора <code>Person()</code>, который мы использовали на протяжении всего модуля, с небольшим отличием - мы определили внутри конструктора только лишь свойства:</p> + +<pre class="brush: js notranslate">function Person(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; +};</pre> + +<p><em>Все</em> методы определены в прототипе конструктора. Например:</p> + +<pre class="brush: js notranslate">Person.prototype.greeting = function() { + alert('Hi! I\'m ' + this.name.first + '.'); +};</pre> + +<div class="note"> +<p><strong>Примечание</strong>. В исходном коде вы также увидите определенные методы <code>bio()</code> и <code>farewell()</code>. Позже вы увидите, как они могут быть унаследованы другими конструкторами.</p> +</div> + +<p>Скажем так, мы хотели создать класс <code>Teacher</code>, подобный тому, который мы описали в нашем первоначальном объектно-ориентированном определении, которое наследует всех членов от <code>Person</code>, но также включает в себя:</p> + +<ol> + <li>Новое свойство, <code>subject</code> - оно будет содержать предмет, который преподает учитель.</li> + <li>Обновленный метод <code>greeting()</code>, который звучит немного более формально, чем стандартный метод <code>greeting()</code>— более подходит для учителя, обращающегося к некоторым ученикам в школе.</li> +</ol> + +<h2 id="Определение_функции-конструктора_Teacher">Определение функции-конструктора Teacher()</h2> + +<p>Первое, что нам нужно сделать, это создать конструктор <code>Teacher()</code> - добавьте ниже следующий код:</p> + +<pre class="brush: js notranslate">function Teacher(first, last, age, gender, interests, subject) { + Person.call(this, first, last, age, gender, interests); + + this.subject = subject; +}</pre> + +<p>Это похоже на конструктор Person во многих отношениях, но здесь есть что-то странное, что мы не видели раньше - функцию <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call()</a></code>. Эта функция в основном позволяет вам вызывать функцию, определенную где-то в другом месте, но в текущем контексте. Первый параметр указывает значение <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this">this</a></code>, которое вы хотите использовать при выполнении функции, а остальные параметры - те, которые должны быть переданы функции при ее вызове.</p> + +<p>Мы хотим, чтобы конструктор <code>Teacher()</code> принимал те же параметры, что и конструктор <code>Person()</code>, от которго он наследуется, поэтому мы указываем их как параметры в вызове <code>call()</code>.</p> + +<p>Последняя строка внутри конструктора просто определяет новое свойство <code>subject</code>, которое будут иметь учителя, и которого нет у Person().</p> + +<p>В качестве примечания мы могли бы просто сделать это:</p> + +<pre class="brush: js notranslate">function Teacher(first, last, age, gender, interests, subject) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + this.subject = subject; +}</pre> + +<p>Но это просто переопределяет свойства заново, а не наследует их от <code>Person()</code>, так что теряется смысл того, что мы пытаемся сделать. Он также занимает больше строк кода.</p> + +<h3 id="Наследование_от_конструктора_без_параметров">Наследование от конструктора без параметров</h3> + +<p>Обратите внимание, что если конструктор, от которого вы наследуете, не принимает значения своего свойства из параметров, вам не нужно указывать их в качестве дополнительных аргументов в <code>call()</code>. Так, например, если у вас было что-то действительно простое:</p> + +<pre class="brush: js notranslate">function Brick() { + this.width = 10; + this.height = 20; +}</pre> + +<p>Вы можете наследовать свойства <code>width</code> и <code>height</code>, выполнив это (как и другие шаги, описанные ниже, конечно):</p> + +<pre class="brush: js notranslate">function BlueGlassBrick() { + Brick.call(this); + + this.opacity = 0.5; + this.color = 'blue'; +}</pre> + +<p>Обратите внимание, что мы указали только <code>this</code> внутри <code>call()</code> - никаких других параметров не требуется, поскольку мы не наследуем никаких свойств родителя, которые задаются через параметры.</p> + +<h2 id="Установка_Teachers_prototype_и_конструктор_ссылок">Установка Teacher()'s prototype и конструктор ссылок</h2> + +<p>Пока все хорошо, но у нас есть проблема. Мы определили новый конструктор и у него есть свойство <code>prototype</code>, которое по умолчанию просто содержит ссылку на саму конструкторскую функцию. Он не содержит методов свойства <code>prototype</code> конструктора <code>Person</code>. Чтобы увидеть это, введите <code>Object.getOwnPropertyNames(Teacher.prototype)</code> в поле ввода текста или в вашу консоль JavaScript. Затем введите его снова, заменив <code>Teacher</code> на <code>Person</code>. Новый конструктор <em>не наследует</em> эти методы. Чтобы увидеть это, сравните выводы в консоль <code>Person.prototype.greeting</code> и <code>Teacher.prototype.greeting</code>. Нам нужно заставить <code>Teacher()</code> наследовать методы, определенные на прототипе <code>Person()</code>. Итак, как мы это делаем?</p> + +<ol> + <li>Добавьте следующую строку ниже своего предыдущего добавления: + <pre class="brush: js notranslate">Teacher.prototype = Object.create(Person.prototype);</pre> + Здесь наш друг <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create">create()</a></code> снова приходит на помощь. В этом случае мы используем его для создания нового объекта и делаем его значением <code>Teacher.prototype</code>. Новый объект имеет свой прототип <code>Person.prototype</code> и, следовательно, наследует, если и когда это необходимо, все доступные методы <code>Person.prototype</code>.</li> + <li>Нам нужно сделать еще одну вещь, прежде чем двигаться дальше. После добавления последней строки, <code>Teacher.prototype.constructor</code> стало равным <code>Person()</code>, потому что мы просто устанавливаем <code>Teacher.prototype</code> для ссылки на объект, который наследует его свойства от <code>Person.prototype</code>! Попробуйте сохранить код, загрузите страницу в браузере и введите <code>Teacher.prototype.constructor</code> в консоль для проверки.</li> + <li>Это может стать проблемой, поэтому нам нужно сделать это правильно. Вы можете сделать это, вернувшись к исходному коду и добавив следующие строки внизу: + <pre class="notranslate"><code>Object.defineProperty(Teacher.prototype, 'constructor', { + value: Teacher, + enumerable: false, // false, чтобы данное свойство не появлялось в цикле for in + writable: true });</code></pre> + </li> + <li>Теперь, если вы сохраните и обновите, введите <code>Teacher.prototype.constructor</code>, чтобы вернуть <code>Teacher()</code>, плюс мы теперь наследуем <code>Person()</code>!</li> +</ol> + +<h2 id="Предоставление_Teacher_новой_функции_greeting">Предоставление Teacher() новой функции greeting()</h2> + +<p>Чтобы завершить наш код, нам нужно определить новую функцию <code>greeting()</code> в конструкторе <code>Teacher()</code>.</p> + +<p>Самый простой способ сделать это - определить его на прототипе <code>Teacher()</code> - добавить в нижнюю часть кода следующее:</p> + +<pre class="brush: js notranslate">Teacher.prototype.greeting = function() { + var prefix; + + if (this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') { + prefix = 'Mr.'; + } else if (this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') { + prefix = 'Mrs.'; + } else { + prefix = 'Mx.'; + } + + alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.'); +};</pre> + +<p>Это выводит на экран приветствие учителя, в котором используется соответствующий префикс имени для своего пола, разработанный с использованием условного оператора.</p> + +<h2 id="Попробуйте_пример">Попробуйте пример</h2> + +<p>Теперь, когда вы ввели весь код, попробуйте создать экземпляр объекта из <code>Teacher()</code>, поставив ниже вашего JavaScript кода (или что-то похожее по вашему выбору):</p> + +<pre class="brush: js notranslate">var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');</pre> + +<p>Теперь сохраните, обновите, и попробуйте получить доступ к свойствам и методам вашего нового объекта <code>teacher1</code>, например:</p> + +<pre class="brush: js notranslate">teacher1.name.first; +teacher1.interests[0]; +teacher1.bio(); +teacher1.subject; +teacher1.greeting(); +teacher1.farewell();</pre> + +<p>Все должно работать нормально. Запросы в строках 1, 2, 3 и 6 унаследованны от общего конструктора <code>Person()</code> (класса). Запрос в строке 4 обращается к <code>subject</code>, доступному только для более специализированного конструктора (класса) <code>Teacher()</code>. Запрос в строке 5 получил бы доступ к методу <code>greeting()</code>, унаследованному от <code>Person()</code>, но <code>Teacher()</code> имеет свой собственный метод <code>greeting()</code> с тем же именем, поэтому запрос обращается к этому методу.</p> + +<div class="note"> +<p><strong>Примечание</strong>. Если вам не удается заставить это работать, сравните свой код с нашей <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-finished.html">готовой версией</a> (см. также <a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-student.html">рабочее демо</a>).</p> +</div> + +<p>Методика, которую мы здесь рассмотрили, - это не единственный способ создания наследующих классов в JavaScript, но он работает нормально и это дает вам представление о том, как реализовать наследование в JavaScript.</p> + +<p>Вам также может быть интересно узнать некоторые из новых функций {{glossary("ECMAScript")}}, которые позволяют нам делать наследование более чисто в JavaScript (см. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">Classes</a>). Мы не рассматривали их здесь, поскольку они пока не поддерживаются очень широко в браузерах. Все остальные конструкторы кода, которые мы обсуждали в этом наборе статей, поддерживаются еще в IE9 или ранее и есть способы добиться более ранней поддержки, чем это.</p> + +<p>Обычный способ - использовать библиотеку JavaScript - большинство популярных опций имеют простой набор функций, доступных для выполнения наследования более легко и быстро. <a href="http://coffeescript.org/#classes">CoffeeScript</a> , например, предоставляет класс, расширяет и т.д.</p> + +<h2 id="Дальнейшее_упражнение">Дальнейшее упражнение</h2> + +<p>В нашем <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">руководстве по Объектно-ориентированному JavaScript для начинающих</a> мы также включили класс <code>Student</code> как концепцию, которая наследует все особенности <code>Person</code>, а также имеет другой метод <code>greeting()</code> от <code>Person</code>, который гораздо более неформален, чем приветствие <code>Teacher</code>. Посмотрите, как выглядит приветствие ученика в этом разделе, и попробуйте реализовать собственный конструктор <code>Student()</code>, который наследует все функции <code>Person()</code> и реализует другую функцию <code>greeting()</code>.</p> + +<div class="note"> +<p><strong>Примечание</strong>. Если вам не удается заставить это работать, сравните свой код с нашей <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-student.html">готовой версией</a> (см. также <a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-student.html">рабочее демо</a>).</p> +</div> + +<h2 id="Object_member_summary">Object member summary</h2> + +<p>Подводя итог, вы в основном получили три типа свойств / методов, о которых нужно беспокоиться:</p> + +<ol> + <li>Те, которые определены внутри функции-конструктора, которые присваиваются экземплярам объекта. Их довольно легко заметить - в вашем собственном коде они представляют собой элементы, определенные внутри конструктора, используя строки <code>this.x = x</code>; в встроенном коде браузера они являются членами, доступными только для экземпляров объектов (обычно создаются путем вызова конструктора с использованием ключевого слова <code>new</code>, например <code>var myInstance = new myConstructor ()</code>.</li> + <li>Те, которые определяются непосредственно самим конструктором, которые доступны только для конструктора. Они обычно доступны только для встроенных объектов браузера и распознаются путем непосредственной привязки к конструктору, а не к экземпляру. Например, <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys()</a></code>.</li> + <li>Те, которые определены в прототипе конструктора, которые наследуются всеми экземплярами и наследуют классы объектов. К ним относятся любой член, определенный в свойстве прототипа конструктора, например. <code>myConstructor.prototype.x()</code>.</li> +</ol> + +<p>Если вы не уверены, что это такое, не беспокойтесь об этом, пока вы еще учитесь и знание придет с практикой.</p> + +<h2 id="Когда_вы_используете_наследование_в_JavaScript">Когда вы используете наследование в JavaScript?</h2> + +<p>В частности, после этой последней статьи вы можете подумать: «У-у-у, это сложно». Ну, ты прав. Прототипы и наследование представляют собой некоторые из самых сложных аспектов JavaScript, но многие возможности и гибкость JavaScript вытекают из его структуры объектов и наследования и стоит понять, как это работает.</p> + +<p>В некотором смысле вы используете наследование все время. Всякий раз, когда вы используете различные функции веб-API или методы/свойства, определенные во встроенном объекте браузера, который вы вызываете в своих строках, массивах и т.д., вы неявно используете наследование.</p> + +<p>Что касается использования наследования в вашем собственном коде, вы, вероятно, не будете часто его использовать, особенно для начала и в небольших проектах. Это пустая трата времени на использование объектов и наследование только ради этого, когда они вам не нужны. Но по мере того, как ваши базы кода становятся больше, вы с большей вероятностью найдете необходимость в этом. Если вы начинаете создавать несколько объектов с подобными функциями, то создание универсального типа объекта, содержащего все общие функции и наследование этих функций в более специализированных типах объектов, может быть удобным и полезным.</p> + +<div class="note"> +<p><strong>Примечание</strong>. Из-за того, как работает JavaScript, с цепочкой прототипов и т.д., совместное использование функций между объектами часто называется <strong>делегированием</strong>. Специализированные объекты делегируют функциональность универсальному типу объекта.</p> +</div> + +<p>При использовании наследования вам рекомендуется не иметь слишком много уровней наследования и тщательно отслеживать, где вы определяете свои методы и свойства. Можно начать писать код, который временно изменяет прототипы встроенных объектов браузера, но вы не должны этого делать, если у вас нет действительно веской причины. Слишком много наследования могут привести к бесконечной путанице и бесконечной боли при попытке отладки такого кода.</p> + +<p>В конечном счете, объекты - это еще одна форма повторного использования кода, например функций или циклов, со своими конкретными ролями и преимуществами. Если вы обнаруживаете, что создаете кучу связанных переменных и функций и хотите отслеживать их все вместе и аккуратно их упаковывать, объект является хорошей идеей. Объекты также очень полезны, когда вы хотите передать коллекцию данных из одного места в другое. Обе эти вещи могут быть достигнуты без использования конструкторов или наследования. Если вам нужен только один экземпляр объекта, вам лучше всего использовать литерал объекта и вам, разумеется, не нужно наследование.</p> + +<h2 id="Резюме">Резюме</h2> + +<p>В этой статье мы рассмотрели оставшуюся часть основной теории и синтаксиса OOJS, которые, как мы думаем, вам следует знать сейчас. На этом этапе вы должны понимать основы JavaScript, ООП, прототипы и прототипное наследование, как создавать классы (конструкторы) и экземпляры объектов, добавлять функции в классы и создавать подклассы, которые наследуются от других классов.</p> + +<p>В следующей статье мы рассмотрим, как работать с JavaScript Object Notation (JSON), общим форматом обмена данными, написанным с использованием объектов JavaScript.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="http://www.objectplayground.com/">ObjectPlayground.com</a> — A really useful interactive learning site for learning about objects.</li> + <li><a href="https://www.amazon.com/gp/product/193398869X/">Secrets of the JavaScript Ninja</a>, Chapter 6 — A good book on advanced JavaScript concepts and techniques, by John Resig and Bear Bibeault. Chapter 6 covers aspects of prototypes and inheritance really well; you can probably track down a print or online copy fairly easily.</li> + <li><a href="https://github.com/getify/You-Dont-Know-JS/blob/master/this%20&%20object%20prototypes/README.md#you-dont-know-js-this--object-prototypes">You Don't Know JS: this & Object Prototypes</a> — Part of Kyle Simpson's excellent series of JavaScript manuals, Chapter 5 in particular looks at prototypes in much more detail than we do here. We've presented a simplified view in this series of articles aimed at beginners, whereas Kyle goes into great depth and provides a more complex but more accurate picture.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Основы">Основы объекта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Object-oriented_JS">Объектно-ориентированный JavaScript для начинающих</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Object_prototypes">Прототипы объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Inheritance">Наследование в JavaScript</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/JSON">Работа с данными JSON</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Object_building_practice">Практика построения объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Adding_bouncing_balls_features">Добавление функций в нашу демонстрацию прыгающих шаров</a></li> +</ul> diff --git a/files/ru/learn/javascript/объекты/json/index.html b/files/ru/learn/javascript/объекты/json/index.html new file mode 100644 index 0000000000..371f254ec6 --- /dev/null +++ b/files/ru/learn/javascript/объекты/json/index.html @@ -0,0 +1,353 @@ +--- +title: Работа с JSON +slug: Learn/JavaScript/Объекты/JSON +tags: + - Beginner + - JSON + - JavaScript +translation_of: Learn/JavaScript/Objects/JSON +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">Обозначение объектов JavaScript (JSON - JavaScript Object Notation) - стандартный текстовый формат для представления структурированных данных на основе синтаксиса объекта JavaScript. Он обычно используется для передачи данных в веб-приложениях (например, отправка некоторых данных с сервера клиенту,таким образом чтобы это могло отображаться на веб-странице или наоборот). Вы будете сталкиваться с этим довольно часто, поэтому в этой статье мы даем вам все, что вам нужно для работы с JSON используя JavaScript, включая парсинг JSON, чтобы вы могли получить доступ к данным внутри него при создании JSON.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, базовые знания HTML и CSS, знакомство с основами JavaScript (см. <a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a> и <a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a>) и основами OOJS (see <a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять, как работать с данными, хранящимися в JSON, и создавать свои собственные объекты JSON.</td> + </tr> + </tbody> +</table> + +<h2 id="Нет_действительно_что_такое_JSON">Нет, действительно, что такое JSON?</h2> + +<p>{{glossary("JSON")}} - текстовый формат данных, следующий за синтаксисом объекта JavaScript, который был популяризирован <a href="https://en.wikipedia.org/wiki/Douglas_Crockford">Дугласом Крокфордом</a>. Несмотря на то, что он очень похож на буквенный синтаксис объекта JavaScript, его можно использовать независимо от JavaScript, и многие среды программирования имеют возможность читать (анализировать) и генерировать JSON.</p> + +<p>JSON существует как строка,что необходимо при передаче данных по сети. Он должен быть преобразован в собственный объект JavaScript, если вы хотите получить доступ к данным. Это не большая проблема. JavaScript предоставляет глобальный объект <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a>, который имеет методы для преобразования между ними.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Преобразование строки в родной объект называется десериализацией (преобразование из последовательной формы в параллельную<em>)</em>, в то время как преобразовании родного объекта в строку, таким образом ,чтобы он мог быть передан через сеть, называется сериализацией(преобразование в последовательную форму).</p> +</div> + +<p>Объект JSON может быть сохранен в собственном файле, который в основном представляет собой текстовый файл с расширением <code>.json</code> и {{glossary("MIME type")}} <code>application/json</code>.</p> + +<h3 id="Структура_JSON">Структура JSON</h3> + +<p>Как описано выше, JSON представляет собой строку, формат которой очень похож на буквенный формат объекта JavaScript. Вы можете включать одни и те же базовые типы данных внутри JSON, так же как и в стандартном объекте JavaScript - строки, числа, массивы, булевы и другие объектные литералы. Это позволяет построить иерархию данных, к примеру, так:</p> + +<pre class="brush: json">{ + "squadName": "Super hero squad", + "homeTown": "Metro City", + "formed": 2016, + "secretBase": "Super tower", + "active": true, + "members": [ + { + "name": "Molecule Man", + "age": 29, + "secretIdentity": "Dan Jukes", + "powers": [ + "Radiation resistance", + "Turning tiny", + "Radiation blast" + ] + }, + { + "name": "Madame Uppercut", + "age": 39, + "secretIdentity": "Jane Wilson", + "powers": [ + "Million tonne punch", + "Damage resistance", + "Superhuman reflexes" + ] + }, + { + "name": "Eternal Flame", + "age": 1000000, + "secretIdentity": "Unknown", + "powers": [ + "Immortality", + "Heat Immunity", + "Inferno", + "Teleportation", + "Interdimensional travel" + ] + } + ] +}</pre> + +<p>Если бы мы загрузили этот объект в программу JavaScript, создали переменную с названием <code>superHeroes</code>, мы могли бы затем получить доступ к данным внутри нее, используя те же самые точечную и скобочную нотации, которые мы рассмотрели в статье <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics">JavaScript object basics</a>. Например:</p> + +<pre class="brush: js">superHeroes.homeTown +superHeroes['active']</pre> + +<p>Чтобы получить доступ к последующим данным по иерархии, вам просто нужно объединить требуемые имена свойств и индексы массивов. Например, чтобы получить доступ к третьей сверхспособности второго героя, указанного в списке участников, вы должны сделать следующее:</p> + +<pre class="brush: js">superHeroes['members'][1]['powers'][2]</pre> + +<ol> + <li>Сначала у нас есть имя переменной - <code>superHeroes</code>.</li> + <li>Внутри мы хотим получить доступ к свойству <code>members</code>, поэтому мы используем <code>['members']</code>.</li> + <li><code>members</code> содержат массив, заполненный объектами. Мы хотим получить доступ ко второму объекту внутри массива, поэтому мы используем <code>[1]</code>.</li> + <li>Внутри этого объекта мы хотим получить доступ к свойству <code>powers</code>, поэтому мы используем <code>['powers']</code>.</li> + <li>Внутри свойства <code>powers</code> находится массив, содержащий сверхспособности выбранного героя. Нам нужен третий, поэтому мы используем <code>[2]</code>.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>. Мы сделали JSON, видимый выше, доступным внутри переменной в нашем примере <a href="http://mdn.github.io/learning-area/javascript/oojs/json/JSONTest.html">JSONTest.html</a> (см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/JSONTest.html">исходный код</a>). Попробуйте загрузить это, а затем получить доступ к данным внутри переменной через консоль JavaScript вашего браузера.</p> +</div> + +<h3 id="Массивы_как_JSON">Массивы как JSON</h3> + +<p>Выше мы упоминали ,что JSON текст выглядит практически так же как и JavaScript объект,и это почти правильно.Причина,по которой мы говорим почти правильно заключается в том ,что массив также валиден JSON например:</p> + +<pre class="brush: json">[ + { + "name": "Molecule Man", + "age": 29, + "secretIdentity": "Dan Jukes", + "powers": [ + "Radiation resistance", + "Turning tiny", + "Radiation blast" + ] + }, + { + "name": "Madame Uppercut", + "age": 39, + "secretIdentity": "Jane Wilson", + "powers": [ + "Million tonne punch", + "Damage resistance", + "Superhuman reflexes" + ] + } +]</pre> + +<p>Вышесказанное вполне справедливо для JSON. Вам просто нужно получить доступ к элементам массива (в его анализируемой версии), начиная с индекса массива, например <code>[0]["powers"][0]</code>.</p> + +<h3 id="Другие_примечания">Другие примечания</h3> + +<ul> + <li>JSON - это чисто формат данных - он содержит только свойства, без методов.</li> + <li>JSON требует двойных кавычек, которые будут использоваться вокруг строк и имен свойств. Одиночные кавычки недействительны.</li> + <li>Даже одна неуместная запятая или двоеточие могут привести к сбою JSON-файла и не работать. Вы должны быть осторожны, чтобы проверить любые данные, которые вы пытаетесь использовать (хотя сгенерированный компьютером JSON с меньшей вероятностью включает ошибки, если программа генератора работает правильно). Вы можете проверить JSON с помощью приложения вроде <a href="http://jsonlint.com/">JSONLint</a>.</li> + <li>JSON может принимать форму любого типа данных, допустимого для включения в JSON, а не только массивов или объектов. Так, например, одна строка или номер будут действительным объектом JSON.</li> + <li>В отличие от кода JavaScript, в котором свойства объекта могут не заключаться в двойные кавычки, в JSON в качестве свойств могут использоваться только строки заключенные в двойные кавычки.</li> +</ul> + +<h2 id="Активное_обучение_Работа_с_примером_JSON">Активное обучение: Работа с примером JSON</h2> + +<p>Итак, давайте рассмотрим пример, чтобы показать то, как мы можем использовать некоторые данные JSON на веб-сайте.</p> + +<h3 id="Начало_работы">Начало работы</h3> + +<p>Для начала создайте локальные копии наших файлов <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes.html">heroes.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/style.css">style.css</a>. Последний содержит простой CSS для стилизации нашей страницы, в то время как первый содержит очень простой HTML-код сущности:</p> + +<pre class="brush: html"><header> +</header> + +<section> +</section></pre> + +<p>Плюс {{HTMLElement("script")}}, чтобы содержать код JavaScript, который мы будем писать в этом упражнении. На данный момент он содержит только две строки, которые захватывают ссылки на элементы {{HTMLElement("header")}} и {{HTMLElement("section")}} и сохраняют их в переменных:</p> + +<pre class="brush: js">var header = document.querySelector('header'); +var section = document.querySelector('section');</pre> + +<p>Мы предоставили данные JSON на нашем GitHub, на <a href="https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json</a>.</p> + +<p>Мы собираемся загрузить его на нашу страницу и использовать некоторые изящные манипуляции DOM, чтобы отобразить их, например:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13857/json-superheroes.png" style="display: block; margin: 0 auto;"></p> + +<h3 id="Получение_JSON">Получение JSON</h3> + +<p>Чтобы получить JSON, мы будем использовать API, называемый {{domxref("XMLHttpRequest")}} (часто называемый <strong>XHR</strong>). Это очень полезный объект JavaScript, который позволяет нам делать сетевые запросы для извлечения ресурсов с сервера через JavaScript (например, изображения, текст, JSON, даже фрагменты HTML), что означает, что мы можем обновлять небольшие разделы контента без необходимости перезагрузки всей страницы. Это привело к более отзывчивым веб-страницам и звучит захватывающе, но, к сожалению, выходит за рамки этой статьи, чтобы изучить это гораздо более подробно.</p> + +<ol> + <li>Начнем с того, что мы собираемся сохранить URL-адрес JSON, который мы хотим получить в переменной. Добавьте нижеследующий код JavaScript: + <pre class="brush: js">var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';</pre> + </li> + <li>Чтобы создать запрос, нам нужно создать новый экземпляр объекта запроса из конструктора <code>XMLHttpRequest</code>, используя ключевое слово <code>new</code>. Добавьте следующую ниже свою последнюю строку: + <pre class="brush: js">var request = new XMLHttpRequest();</pre> + </li> + <li>Теперь нам нужно открыть новый запрос, используя метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open">open()</a></code>. Добавьте следующую строку: + <pre class="brush: js">request.open('GET', requestURL);</pre> + + <p>Это занимает не менее двух параметров - есть другие доступные параметры. Нам нужно только два обязательных для этого простого примера:</p> + + <ul> + <li>Метод HTTP, который следует использовать при выполнении сетевого запроса. В этом случае <code><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET">GET</a></code> самый подходящий, так как мы просто извлекаем некоторые простые данные.</li> + <li>URL-адрес для запроса - это URL-адрес файла JSON, который мы сохранили ранее.</li> + </ul> + </li> + <li>Затем добавьте следующие две строки: здесь мы устанавливаем <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType">responseType</a></code> в JSON, так что XHR знает, что сервер будет возвращать JSON и, что это должно быть преобразовано за кулисами в объект JavaScript. Затем мы отправляем запрос методом <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send">send()</a></code>: + <pre class="brush: js">request.responseType = 'json'; +request.send();</pre> + </li> + <li>Последний бит этого раздела предполагает ожидание ответа на возврат с сервера, а затем работы с ним. Добавьте следующий код ниже вашего предыдущего кода: + <pre class="brush: js">request.onload = function() { + var superHeroes = request.response; + populateHeader(superHeroes); + showHeroes(superHeroes); +}</pre> + </li> +</ol> + +<p>Здесь мы сохраняем ответ на наш запрос (доступный в свойстве <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/response">response</a></code>) в переменной <code>superHeroes</code>; эта переменная теперь будет содержать объект JavaScript, основанный на JSON! Затем мы передаем этот объект двум вызовам функций - первый из них заполнит <code><header></code> правильными данными, а второй создаст информационную карту для каждого героя в команде и вставляет ее в <code><section></code>.</p> + +<p>Мы свернули код в обработчик событий, который запускается, когда событие загрузки запускается в объекте запроса (см. <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code>) - это связано с тем, что событие загрузки запускается, когда ответ успешно возвращается; поступая таким образом,это гарантия того, что <code>request.response</code> определенно будет доступен, когда мы начнем работу с ним.</p> + +<p>Заполнение заголовка</p> + +<p>Теперь мы извлекли данные JSON и превратили его в объект JavaScript, давайте воспользуемся им, написав две функции, на которые мы ссылались выше. Прежде всего, добавьте следующее определение функции ниже предыдущего кода:</p> + +<pre class="brush: js">function populateHeader(jsonObj) { + var myH1 = document.createElement('h1'); + myH1.textContent = jsonObj['squadName']; + header.appendChild(myH1); + + var myPara = document.createElement('p'); + myPara.textContent = 'Hometown: ' + jsonObj['homeTown'] + ' // Formed: ' + jsonObj['formed']; + header.appendChild(myPara); +}</pre> + +<p>Мы назвали параметр <code>jsonObj</code>, чтобы напомнить себе, что этот объект JavaScript возник из JSON. Здесь мы сначала создаем элемент {{HTMLElement("h1")}} с <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement">createElement()</a></code>, устанавливаем его <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent">textContent</a></code> равным свойству <code>squadName</code> объекта, а затем добавляем его в заголовок с помощью <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild">appendChild()</a></code>. Затем мы выполняем очень похожую операцию с абзацем: создаем его, устанавливаем его текстовое содержимое и добавляем его в заголовок. Единственное различие заключается в том, что его текст задан, как конкатенированная строка, содержащая как <code>homeTown</code>, так и <code>formed</code> свойства объекта.</p> + +<h3 id="Создание_информационных_карт_героя">Создание информационных карт героя</h3> + +<p>Затем добавьте следующую функцию внизу кода, которая создает и отображает карты супергероев:</p> + +<pre class="brush: js">function showHeroes(jsonObj) { + var heroes = jsonObj['members']; + + for (var i = 0; i < heroes.length; i++) { + var myArticle = document.createElement('article'); + var myH2 = document.createElement('h2'); + var myPara1 = document.createElement('p'); + var myPara2 = document.createElement('p'); + var myPara3 = document.createElement('p'); + var myList = document.createElement('ul'); + + myH2.textContent = heroes[i].name; + myPara1.textContent = 'Secret identity: ' + heroes[i].secretIdentity; + myPara2.textContent = 'Age: ' + heroes[i].age; + myPara3.textContent = 'Superpowers:'; + + var superPowers = heroes[i].powers; + for (var j = 0; j < superPowers.length; j++) { + var listItem = document.createElement('li'); + listItem.textContent = superPowers[j]; + myList.appendChild(listItem); + } + + myArticle.appendChild(myH2); + myArticle.appendChild(myPara1); + myArticle.appendChild(myPara2); + myArticle.appendChild(myPara3); + myArticle.appendChild(myList); + + section.appendChild(myArticle); + } +}</pre> + +<p>Для начала сохраним свойство <code>members</code> объекта JavaScript в новой переменной. Этот массив содержит несколько объектов, которые содержат информацию для каждого героя.</p> + +<p>Затем мы используем <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#The_standard_for_loop">for loop</a> для циклического прохождения каждого объекта в массиве. Для каждого из них мы:</p> + +<ol> + <li>Создаем несколько новых элементов: <code><article></code>, <code><h2></code>, три <code><p></code> и <code><ul></code>.</li> + <li>Установливаем <code><h2></code>, чтобы содержать <code>name</code> текущего героя.</li> + <li>Заполняем три абзаца своей <code>secretIdentity</code>, <code>age</code> и строкой, в которой говорится: «Суперспособности:», чтобы ввести информацию в список.</li> + <li>Сохраняем свойство <code>powers</code> в другой новой переменной под названием <code>superPowers</code> - где содержится массив, в котором перечислены сверхспособности текущего героя.</li> + <li>Используем другой цикл <code>for</code>, чтобы прокрутить сверхспособности текущего героя , для каждого из них мы создаем элемент <code><li></code>, помещаем в него сверхспособности, а затем помещаем <code>listItem</code> внутри элемента <code><ul></code> (<code>myList</code>) с помощью <code>appendChild()</code>.</li> + <li>Последнее, что мы делаем, это добавляем <code><h2></code>, <code><p></code> и <code><ul></code> внутри <code><article></code> (<code>myArticle</code>), а затем добавляем <code><article></code> в <code><section></code>. Важное значение имеет порядок, в котором добавляются элементы, так как это порядок, который они будут отображать внутри HTML.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>. Если вам не удается заставить этот пример работать, попробуйте обратиться к нашему исходному коду <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished.html">heroes-finished.html</a> (см. также он работает <a href="https://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished.html">в режиме live</a>).</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>. Если у вас возникли проблемы после нотации точек / скобок, которые мы используем для доступа к объекту JavaScript, в этом поможет открытие файла <a href="http://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">superheroes.json</a> на другой вкладке или в текстовом редакторе ,и обращаться к нему каждый раз, когда вам нужен JavaScript. Вы также можете обратиться к нашей статье <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics">JavaScript objectbasics</a> чтобы получить дополнительную информацию о нотации точек и скобок.</p> +</div> + +<h2 id="Преобразование_между_объектами_и_текстом">Преобразование между объектами и текстом</h2> + +<p>Вышеприведенный пример был прост с точки зрения доступа к объекту JavaScript, потому что мы задали XHR-запрос для прямого преобразования ответа JSON в объект JavaScript, используя:</p> + +<pre class="brush: js">request.responseType = 'json';</pre> + +<p>Но иногда нам не так везет - иногда мы получаем сырую строку JSON и нам нужно преобразовать ее в объект самостоятельно. И когда мы хотим отправить объект JavaScript по сети, нам нужно преобразовать его в JSON (строку) перед отправкой. К счастью, эти две проблемы настолько распространены в веб-разработке, что встроенный объект <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a> доступен в браузерах, которые содержат следующие два метода:</p> + +<ul> + <li><code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">parse()</a></code>: принимает строку JSON в качестве параметра и возвращает соответствующий объект JavaScript.</li> + <li><code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify">stringify()</a></code>: принимает объект, как параметр и возвращает эквивалентную строковую JSON строку.</li> +</ul> + +<p>Вы можете увидеть первый метод в действии в нашем примере <a href="http://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished-json-parse.html">heroes-finished-json-parse.html</a> (см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished-json-parse.html">исходный код</a>) - это то же самое, что и в примере, который мы создали ранее, за исключением того, что мы установили XHR для возврата сырого JSON текста, затем используется <code>parse()</code>, чтобы преобразовать его в фактический объект JavaScript. Ключевой фрагмент кода находится здесь:</p> + +<pre class="brush: js">request.open('GET', requestURL); +request.responseType = 'text'; // now we're getting a string! +request.send(); + +request.onload = function() { + var superHeroesText = request.response; // get the string from the response + var superHeroes = JSON.parse(superHeroesText); // convert it to an object + populateHeader(superHeroes); + showHeroes(superHeroes); +}</pre> + +<p>Как вы могли догадаться, <code>stringify()</code> работает обратным образом. Попробуйте ввести следующие строки в консоль JavaScript браузера один за другим, чтобы увидеть его в действии:</p> + +<pre class="brush: js">var myJSON = { "name": "Chris", "age": "38" }; +myJSON +var myString = JSON.stringify(myJSON); +myString</pre> + +<p>Здесь мы создаем объект JavaScript, затем проверяем, что он содержит, а затем преобразуем его в строку JSON, используя <code>stringify()</code> , сохраняя возвращаемое значение в новой переменной, а затем снова проверяем его.</p> + +<h2 id="Резюме">Резюме</h2> + +<p>В этой статье мы предоставили вам простое руководство по использованию JSON в ваших программах, в том числе о том, как создавать и анализировать JSON, и как получить доступ к данным, заблокированным внутри него. В следующей статье мы рассмотрим объектно-ориентированный JavaScript.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON object reference page</a></li> + <li><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest object reference page</a></li> + <li><a href="/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest">Using XMLHttpRequest</a></li> + <li><a href="/en-US/docs/Web/HTTP/Methods">HTTP request methods</a></li> + <li><a href="http://json.org">Official JSON web site with link to ECMA standard</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B">Основы объекта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object-oriented_JS">Объектно-ориентированный JavaScript для начинающих</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object_prototypes">Прототипы объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Inheritance">Наследование в JavaScript</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/JSON">Работа с данными JSON</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object_building_practice">Практика построения объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Adding_bouncing_balls_features">Добавление функций в нашу демонстрацию прыгающих шаров</a></li> +</ul> + +<div class="s3gt_translate_tooltip_mini_box" id="s3gt_translate_tooltip_mini" style="background: initial !important; border: initial !important; border-radius: initial !important; border-collapse: initial !important; direction: ltr !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; max-width: initial !important; min-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; text-align: initial !important; text-shadow: initial !important; width: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 124px; top: 1171px; opacity: 0;"> +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_logo" style="width: 12px; height: 12px; border-radius: 4px;" title="Перевести выделенный фрагмент"></div> + +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_sound" style="width: 12px; height: 12px; border-radius: 4px;" title="Прослушать"></div> + +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_copy" style="width: 12px; height: 12px; border-radius: 4px;" title="Скопировать текст в буфер обмена"></div> +</div> diff --git a/files/ru/learn/javascript/объекты/object-oriented_js/index.html b/files/ru/learn/javascript/объекты/object-oriented_js/index.html new file mode 100644 index 0000000000..0299268a90 --- /dev/null +++ b/files/ru/learn/javascript/объекты/object-oriented_js/index.html @@ -0,0 +1,286 @@ +--- +title: Объектно-ориентированный JavaScript для начинающих +slug: Learn/JavaScript/Объекты/Object-oriented_JS +tags: + - Constructor + - Create + - JavaScript + - OOJS + - Object + - Новичку + - ООП + - экземпляр +translation_of: Learn/JavaScript/Objects/Object-oriented_JS +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">Разобравшись с основами, сосредоточимся на объектно-ориентированном JavaScript (OOJS) — данная статья дает базовое представление о теории объектно-ориентированного программирования (ООП), далее рассмотрено как JavaScript эмулирует классы объектов с помощью функции-конструктора и как создаются экземпляры объектов.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p class="brush: html">Базовая компьютерная грамотность, базовое понимание HTML и CSS, знакомство с основами JavaScript (см. <a href="/en-US/docs/Learn/JavaScript/First_steps">Первые шаги</a> и <a href="/en-US/docs/Learn/JavaScript/Building_blocks">C</a>труктурные элементы JavaScript) и основы OOJS (см. <a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Введение в объекты</a>).</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять основную теорию объектно-ориентированного программирования, как это относится к JavaScript («все является объектом») и как создавать конструкторы и экземпляры объектов.</td> + </tr> + </tbody> +</table> + +<h2 id="Объектно-ориентированное_программирование_основы">Объектно-ориентированное программирование: основы</h2> + +<p>Начнём с упрощённого высокоуровневого представления о том, что такое <em>объектно-ориентированное программирование</em> <em>(ООП)</em>. Мы говорим упрощённого, потому что ООП может быстро стать очень сложным, и если сейчас дать полный курс, вероятно, можно запутать больше, чем помочь. Основная идея ООП заключается в том, что мы используем объекты для отображения моделей из реального мира в наших программах и/или упрощения доступа к функциям, которые в противном случае было бы трудно или невозможно использовать.</p> + +<p>Объекты могут содержать данные и код, представляющие информацию о том, что вы пытаетесь смоделировать, а также о том, какие у этих объектов должны быть функциональные возможности или поведение. Данные объекта (а часто так же и функции) могут быть точно сохранены (официальный термин "<strong>инкапсулированы"</strong>) внутри пакета объекта, упрощая структуру и доступ к ним. Пакету объекта может быть присвоено определенное имя, на которое можно сослаться и которое иногда называют <strong>пространством имен.</strong> Объекты также широко используются в качестве хранилищ данных, которые могут быть легко отправлены по сети.</p> + +<h3 id="Определение_шаблона_объекта">Определение шаблона объекта</h3> + +<p>Рассмотрим простую программу, которая отображает информацию об учениках и учителях в школе. Здесь мы рассмотрим теорию ООП в целом, а не в контексте какого-либо конкретного языка программирования.</p> + +<p>Вернёмся к объекту Person из нашей статьи <a href="/ru/docs/Learn/JavaScript/Объекты/Основы">Основы объектов</a>, который определяет общие сведения и функциональные возможности человека. Есть много вещей, которые вы <em>можете</em> узнать о человеке (его адрес, рост, размер обуви, профиль ДНК, номер паспорта, значимые черты личности ...), но в данном случае нас интересует только имя, возраст, пол и интересы, а также мы хотим иметь возможность написать краткую информацию о нём, основываясь на этих данных, и сделать так, чтобы он поздоровался. Это известно как <strong>абстракция</strong> — создание простой модели более сложной сущности, которая представляет её наиболее важные аспекты таким образом, чтобы с ней было удобно работать для выполнения целей нашей программы.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13889/person-diagram.png" style="display: block; height: 219px; margin: 0px auto; width: 610px;"></p> + +<p>В некоторых языках ООП, это общее определение типа объекта называется <strong>class</strong> (JavaScript использует другой механизм и терминологию, как вы увидите ниже) — это на самом деле не объект, а шаблон, который определяет, какие характеристики должен иметь объект.</p> + +<h3 id="Создание_реальных_объектов">Создание реальных объектов</h3> + +<p>Из нашего класса мы можем создать <strong>экземпляры объектов</strong> — объекты, содержащие данные и функциональные возможности, определённые в классе. Из нашего класса Person мы теперь можем создавать модели реальных людей:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13883/MDN-Graphics-instantiation-2.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p> + +<p>Когда экземпляр объекта создается из класса, для его создания выполняется <strong>функция-конструктор </strong>класса. Этот процесс создания экземпляра объекта из класса называется <strong>создание экземпляра (instantiation)</strong> — из класса <strong>создается</strong> экземпляр объекта.</p> + +<h3 id="Специализированные_классы">Специализированные классы</h3> + +<p>В нашем случае нам не нужны все люди — нам требуются учителя и ученики, которые являются более конкретными типами людей. В ООП мы можем создавать новые классы на основе других классов — эти новые <strong>дочерние классы</strong> могут быть созданы для <strong>наследования</strong> данных и характеристик <strong>родительского класса</strong>, так чтобы можно было использовать функциональные возможности, общие для всех типов объекта, вместо того чтобы дублировать их. Когда функциональность различается между классами, можно по мере необходимости определять специализированные функции непосредственно на них.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13881/MDN-Graphics-inherited-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p> + +<p>Это действительно полезно — преподаватели и студенты имеют много общих характеристик, таких как имя, пол и возраст, и удобно определить их только один раз. Вы можете также задать одну и ту же характеристику отдельно в разных классах, поскольку каждое определение этой характеристики будет находиться в отдельном пространстве имен. Например, приветствие студента может быть в форме "Yo, I'm [firstName]" (например <em>Yo, I'm Sam</em>), в то время как учитель может использовать что-то более формальное, такое как "Hello, my name is [Prefix] [lastName], and I teach [Subject]." (например <em>Hello, My name is Mr Griffiths, and I teach Chemistry</em>).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Если вам интересно, существует специальный термин <strong>Polymorphism (Полиморфизм)</strong> - это забавное слово, обозначающее реализацию той же функциональности для нескольких типов объекта. </p> +</div> + +<p>Теперь вы можете создавать экземпляры объекта из дочерних классов. Например:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13885/MDN-Graphics-instantiation-teacher-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p> + +<p>Далее мы рассмотрим, как ООП теорию можно применить на практике в JavaScript.</p> + +<h2 id="Конструкторы_и_экземпляры_объектов">Конструкторы и экземпляры объектов</h2> + +<p>JavaScript использует специальные функции, называемые функциями конструктора (<strong>constructor functions</strong>) для определения объектов и их свойств. Они полезны, потому что вы часто будете сталкиваться с ситуациями, в которых не известно, сколько объектов вы будете создавать; конструкторы позволяют создать столько объектов, сколько нужно эффективным способом, прикреплением данных и функций для объектов по мере необходимости.</p> + +<p>Рассмотрим создание классов через конструкторы и создание экземпляров объектов из них в JavaScript. Прежде всего, мы хотели бы, чтобы вы создали новую локальную копию файла <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a>, который мы видели в нашей первой статье «Объекты».</p> + +<h3 id="Простой_пример">Простой пример</h3> + +<ol> + <li>Давайте рассмотрим как можно определить человека с нормальной функцией. Добавьте эту функцию в элемент <code>script</code>: + + <pre class="brush: js notranslate">function createNewPerson(name) { + const obj = {}; + obj.name = name; + obj.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; + return obj; +}</pre> + </li> + <li>Теперь вы можете создать нового человека, вызвав эту функцию - попробуйте следующие строки в консоли JavaScript браузера: + <pre class="brush: js notranslate">const salva = createNewPerson('Salva'); +salva.name; +salva.greeting();</pre> + Это работает достаточно хорошо, но код излишне многословен; если мы знаем, что хотим создать объект, зачем нам явно создавать новый пустой объект и возвращать его? К счастью, JavaScript предоставляет нам удобный способ в виде функций-конструкторов - давайте сделаем это сейчас!</li> + <li>Замените предыдущую функцию следующей: + <pre class="brush: js notranslate">function Person(name) { + this.name = name; + this.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; +}</pre> + </li> +</ol> + +<p>Функция-конструктор - это JavaScript версия класса. Вы заметите, что в нем есть все признаки, которые вы ожидаете от функции, хотя он ничего не возвращает и явно не создает объект - он в основном просто определяет свойства и методы. Вы также увидите, что ключевое слово this также используется здесь, - это в основном говорит о том, что всякий раз, когда создается один из этих экземпляров объектов, свойство имени объекта будет равно значению <code>name</code>, переданному вызову конструктора, и метод <code>greeting()</code> будет использовать значение имени, переданное также вызову конструктора.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Имя функции конструктора обычно начинается с заглавной буквы - это соглашение используется для упрощения распознавания функций конструктора в коде.</p> +</div> + +<p>Итак, как мы вызываем конструктор для создания некоторых объектов?</p> + +<ol> + <li>Добавьте следующие строки под предыдущим добавлением кода: + <pre class="brush: js notranslate">let person1 = new Person('Bob'); +let person2 = new Person('Sarah');</pre> + </li> + <li>Сохраните код и перезагрузите его в браузере и попробуйте ввести следующие строки в консоль JS: + <pre class="brush: js notranslate">person1.name +person1.greeting() +person2.name +person2.greeting()</pre> + </li> +</ol> + +<p>Круто! Теперь, как вы видите, у нас есть два новых объекта на странице, каждый из которых хранится в отдельном пространстве имен - при доступе к их свойствам и методам вы должны начинать вызовы с <code>person1</code> или <code>person2</code>; функциональность, содержащаяся внутри, аккуратно упакована, поэтому она не будет конфликтовать с другими функциями. Тем не менее, у них есть одно и то же свойство <code>name</code> и <code>greeting()</code>. Обратите внимание, что они используют свое собственное значение <code>name</code>, которое было присвоено им, когда они были созданы; это одна из причин, почему очень важно использовать <code>this</code>, таким образом они будут использовать свои собственные значения, а не какие-либо другие.</p> + +<p>Давайте снова посмотрим на вызовы конструктора:</p> + +<pre class="brush: js notranslate">let person1 = new Person('Bob'); +let person2 = new Person('Sarah');</pre> + +<p>В каждом случае ключевое слово <code>new</code> используется, чтобы сообщить браузеру, что мы хотим создать экземпляр нового объекта, за которым следует имя функции с ее необходимыми параметрами, содержащимися в круглых скобках, и результат сохраняется в переменной - очень похоже на то, как вызывается стандартная функция. Каждый экземпляр создается в соответствии с этим определением:</p> + +<pre class="brush: js notranslate">function Person(name) { + this.name = name; + this.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; +}</pre> + +<p>После создания новых объектов переменные <code>person1</code> и <code>person2</code> содержат следующие объекты:</p> + +<pre class="brush: js notranslate">{ + name: 'Bob', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +} + +{ + name: 'Sarah', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +}</pre> + +<p>Обратите внимание, что когда мы вызываем нашу функцию-конструктор, мы определяем <code>greeting()</code> каждый раз, что не является идеальным. Чтобы этого избежать, вместо этого мы можем определить функции на прототипе, о которых мы поговорим позже.</p> + +<h3 id="Создавая_наш_готовый_конструктор">Создавая наш готовый конструктор</h3> + +<p>Пример, рассмотренный выше, был лишь наглядным примером, чтобы вы поняли суть. Теперь, давайте создадим нашу конечную функцию-конструктор <code>Person()</code>.</p> + +<ol> + <li>Замените весь предыдущий код новой функцией конструктора - это, в принципе, тот же самое что и в наглядном примере, но несколько сложнее: + <pre class="brush: js notranslate">function Person(first, last, age, gender, interests) { + this.name = { + first : first, + last: last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + this.bio = function() { + alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); + }; + this.greeting = function() { + alert('Hi! I\'m ' + this.name.first + '.'); + }; +};</pre> + </li> + <li>Теперь добавьте следующую строку ниже, чтобы создать экземпляр объекта из него: + <pre class="brush: js notranslate">let person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre> + </li> +</ol> + +<p>Как вы могли заметить, вы можете получить доступ к свойствам и методам, как это было ранее, - попробуйте использовать их в консоли JS:</p> + +<pre class="brush: js notranslate">person1['age'] +person1.interests[1] +person1.bio() +// etc.</pre> + +<div class="note"><strong>Примечание</strong>: Если у Вас возникли проблемы с работой кода, попробуйте сравнить его с нашей версией - см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-finished.html">oojs-class-finished.html</a> (также смотрите, как он работает <a href="https://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-finished.html">в прямом эфире</a>).</div> + +<h3 id="Дальнейшие_упражнения">Дальнейшие упражнения</h3> + +<p>Для начала, попробуйте добавить еще пару собственных строк создания объекта и попробуйте получить и установить элементы полученных экземпляров объектов.</p> + +<p>Кроме того, есть несколько проблем с нашим методом <code>bio()</code> - вывод всегда включает местоимение «He» ("Он" в пер. с англ.), даже если ваш человек является женщиной или какой-либо другой предпочтительной гендерной классификацией. И <code>bio</code> будет включать только два интереса, даже если в массиве <code>interests</code> указано больше. Можете ли Вы решить, как исправить это в определении класса (конструкторе)? Вы можете поместить любой код, который вам нравится внутри конструктора (вам, вероятно, понадобятся несколько условий и цикл). Подумайте о том, как предложения должны быть структурированы по-разному в зависимости от пола и в зависимости от того, имеет ли число перечисленных интересов 1, 2 или более 2.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Если у Вас возникли трудности с решением задачи, мы предоставили <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">ответ в нашем репозитории GitHub</a> (<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">см. это в действии</a>) — но сначала попробуйте написать сами!</p> +</div> + +<h2 id="Другие_способы_создания_экземпляров_объектов">Другие способы создания экземпляров объектов</h2> + +<p>До сих пор мы видели два разных способа создания экземпляра объекта - <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#Object_basics">объявление объектного литерала</a> и использование функции конструктора (см. выше).</p> + +<p>Это имеет смысл, но есть и другие способы - мы бы хотели ознакомить Вас с ними на случай, если Вы встретите их в своих путешествиях по Сети.</p> + +<h3 id="Конструктор_Object">Конструктор Object ()</h3> + +<p>Прежде всего, вы можете использовать конструктор <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">Object()</a></code> для создания нового объекта. Да, даже общие объекты имеют конструктор, который генерирует пустой объект.</p> + +<ol> + <li>Попробуйте ввести это в консоль JavaScript вашего браузера: + <pre class="brush: js notranslate">let person1 = new Object();</pre> + </li> + <li>Это сохраняет ссылку на пустой объект в переменную <code>person1</code>. Затем вы можете добавить свойства и методы к этому объекту с использованием точечной или скобочной нотации по желанию; попробуйте эти примеры в консоли: + <pre class="brush: js notranslate">person1.name = 'Chris'; +person1['age'] = 38; +person1.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); +};</pre> + </li> + <li>Вы также можете передать литерал объекта конструктору <code>Object()</code> в качестве параметра, чтобы заполнить его свойствами / методами. Попробуйте это в консоли JS: + <pre class="brush: js notranslate">let person1 = new Object({ + name: 'Chris', + age: 38, + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +});</pre> + </li> +</ol> + +<h3 id="Использование_метода_create">Использование метода create()</h3> + +<p>Конструкторы могут помочь вам определить порядок кода - вы можете создать конструктор в одном месте, а затем создавать экземпляры по мере необходимости, и их происхождение будет понятным.</p> + +<p>Однако некоторые люди предпочитают создавать экземпляры объектов без предварительного создания конструкторов, особенно если они создают только несколько экземпляров объекта. JavaScript имеет встроенный метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create">create()</a></code>, который позволяет вам это делать. С его помощью вы можете создать новый объект на основе любого существующего объекта.</p> + +<ol> + <li>Закончив упражнение из предыдущего раздела, загруженное в браузер, попробуйте это в консоли JavaScript: + <pre class="brush: js notranslate">let person2 = Object.create(person1);</pre> + </li> + <li>Теперь попробуйте: + <pre class="brush: js notranslate">person2.name +person2.greeting()</pre> + </li> +</ol> + +<p>Вы увидите, что <code>person2</code> был создан на основе <code>person1</code> - он имеет те же свойства и метод, доступные для него.</p> + +<p>Одно ограничение метода <code>create()</code> заключается в том, что IE8 не поддерживает его. Поэтому конструкторы могут быть более эффективными, если вы хотите поддерживать старые браузеры.</p> + +<p>Подробнее мы рассмотрим особенности метода <code>create()</code> немного позже.</p> + +<h2 id="Сводка">Сводка</h2> + +<p>В этой статье представлен упрощенный взгляд на объектно-ориентированную теорию — это еще не вся история, но она дает представление о том, с чем мы имеем дело. Кроме того, мы начали рассматривать различные способы создания экземпляров объектов.</p> + +<p>В следующей статье мы рассмотрим прототипы объектов JavaScript.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/JavaScript/Объекты/Основы">Основы объекта</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Объекты/Object-oriented_JS">Объектно-ориентированный JavaScript для начинающих</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Объекты/Object_prototypes">Прототипы объектов</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Объекты/Inheritance">Наследование в JavaScript</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Объекты/JSON">Работа с данными JSON</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Объекты/Object_building_practice">Практика построения объектов</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Объекты/Adding_bouncing_balls_features">Добавление функций в нашу демонстрацию прыгающих шаров</a></li> +</ul> diff --git a/files/ru/learn/javascript/объекты/object_building_practice/index.html b/files/ru/learn/javascript/объекты/object_building_practice/index.html new file mode 100644 index 0000000000..b06b769ca4 --- /dev/null +++ b/files/ru/learn/javascript/объекты/object_building_practice/index.html @@ -0,0 +1,302 @@ +--- +title: Практика построения объектов +slug: Learn/JavaScript/Объекты/Object_building_practice +tags: + - Guide + - JavaScript +translation_of: Learn/JavaScript/Objects/Object_building_practice +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">В предыдущих статьях мы рассмотрели всю существенную теорию объектов JavaScript и детали синтаксиса, давая вам прочную основу для начала. В этой статье мы погружаемся в практическое упражнение, давая вам больше практики в создании пользовательских объектов JavaScript, с веселым и красочным результатом.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, базовые знания HTML и CSS, знакомство с основами JavaScript (see <a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a> and <a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a>) и основами OOJS (см. <a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Получение некоторой практики в использовании объектов и объектно-ориентированных методов в реальном мире.</td> + </tr> + </tbody> +</table> + +<h2 id="Давайте_подбросим_несколько_мячей">Давайте подбросим несколько мячей</h2> + +<p>В этой статье мы напишем классическую демонстрацию «прыгающих шаров», чтобы показать вам, насколько полезными могут быть объекты в JavaScript. Наши маленькие шары будут подпрыгивать на экране и менять цвет, когда они касаются друг друга. Готовый пример будет выглядеть примерно так:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13865/bouncing-balls.png" style="display: block; height: 614px; margin: 0px auto; width: 800px;"></p> + +<ol> +</ol> + +<p>В этом примере будет использоваться <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Canvas API</a> для рисования шаров на экране и API <a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a> для анимации всего экрана - вам не нужно иметь никаких предыдущих знаний об этих API, и мы надеемся, что к тому моменту, когда вы закончите эту статью, вам будет интересно изучить их больше. По пути мы воспользуемся некоторыми изящными объектами и покажем вам пару хороших приемов, таких как отскоки шаров от стен и проверка того, попали ли они друг в друга (иначе известный как <strong>обнаружение столкновения</strong>).</p> + +<h2 id="Начало_работы">Начало работы</h2> + +<p>Для начала создайте локальные копии наших файлов<code><a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/index.html">index.html</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/style.css">style.css</a></code> и <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/main.js">main.js</a></code>. Они содержат следующее:</p> + +<ol> + <li>Очень простой HTML-документ, содержащий элемент {{HTMLElement("h1")}}, элемент {{HTMLElement("canvas")}} для рисования наших шаров и элементы для применения нашего CSS и JavaScript в нашем HTML.</li> + <li>Некоторые очень простые стили, которые в основном служат для стилизации и позиционирования <code><h1></code>, и избавляются от любых полос прокрутки или отступы по краю страницы (так что это выглядит красиво и аккуратно).</li> + <li>Некоторые JavaScript, которые служат для настройки элемента <code><canvas></code> и предоставляют общую функцию, которую мы собираемся использовать.</li> +</ol> + +<p>Первая часть скрипта выглядит так:</p> + +<pre class="brush: js notranslate">var canvas = document.querySelector('canvas'); + +var ctx = canvas.getContext('2d'); + +var width = canvas.width = window.innerWidth; +var height = canvas.height = window.innerHeight;</pre> + +<p>Этот скрипт получает ссылку на элемент <code><canvas></code>, а затем вызывает метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext">getContext()</a></code>, чтобы дать нам контекст, по которому мы можем начать рисовать. Результирующая переменная (ctx) - это объект, который непосредственно представляет область рисования холста и позволяет рисовать на ней 2D-фигуры.</p> + +<p>Затем мы устанавливаем переменные, называемые <code>width</code> и <code>height</code>, а также ширину и высоту элемента canvas (представленные свойствами <code>canvas.width</code> и <code>canvas.height</code>), чтобы равняться ширине и высоте окна просмотра браузера (область, на которой отображается веб-страница - это можно получить из свойств {{domxref("Window.innerWidth")}} и {{domxref("Window.innerHeight")}}).</p> + +<p>Вы увидите здесь, что мы объединяем несколько назначений вместе, чтобы все переменные были установлены быстрее - это совершенно нормально.</p> + +<p>Последний бит исходного скрипта выглядит следующим образом:</p> + +<pre class="brush: js notranslate">function random(min, max) { + var num = Math.floor(Math.random() * (max - min + 1)) + min; + return num; +}</pre> + +<p>Эта функция принимает два числа в качестве аргументов и возвращает случайное число в диапазоне между ними.</p> + +<h2 id="Моделирование_мяча_в_нашей_программе">Моделирование мяча в нашей программе</h2> + +<p>В нашей программе будет много шаров, подпрыгивающих вокруг экрана. Поскольку эти шары будут вести себя одинаково, имеет смысл представлять их в виде объекта. Начнем с добавления следующего конструктора в конец нашего кода.</p> + +<pre class="brush: js notranslate">function Ball(x, y, velX, velY, color, size) { + this.x = x; + this.y = y; + this.velX = velX; + this.velY = velY; + this.color = color; + this.size = size; +}</pre> + +<p>Здесь мы включаем некоторые параметры, которые определяют свойства, которым должен соответствовать каждый шар в нашей программе:</p> + +<ul> + <li><code>x</code> и <code>y</code> координаты - горизонтальные и вертикальные координаты, где мяч будет запускаться на экране. Координаты могут находиться в диапазоне от 0 (верхний левый угол) до ширины и высоты окна просмотра браузера (нижний правый угол).</li> + <li>горизонтальная и вертикальная скорость (<code>velX</code> и <code>velY</code>) - каждому шару задана горизонтальная и вертикальная скорость; в реальном выражении эти значения будут регулярно добавляться к значениям координат <code>x</code>/<code>y</code>, когда мы начнем анимировать шары, чтобы их перемещать на каждом кадре.</li> + <li><code>color</code> - каждый мяч получает цвет.</li> + <li><code>size</code> - каждый мяч получает размер - это будет его радиус в пикселях.</li> +</ul> + +<p>Этим мы сортируем свойства, но что насчет методов? Мы хотим заставить эти шары на самом деле сделать что-то в нашей программе.</p> + +<h3 id="Рисование_шара">Рисование шара</h3> + +<p>Сначала добавьте следующий метод <code>draw()</code> к <code>Ball()</code>'s <code>prototype</code>:</p> + +<pre class="brush: js notranslate">Ball.prototype.draw = function() { + ctx.beginPath(); + ctx.fillStyle = this.color; + ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI); + ctx.fill(); +}</pre> + +<p>Используя эту функцию, мы можем сказать нашему шару нарисовать себя на экране, вызвав ряд членов контекста двумерного холста, который мы определили ранее (<code>ctx</code>). Контекст похож на бумагу, и теперь мы хотим, чтобы наше перо рисовало что-то на нем:</p> + +<ul> + <li>Во-первых, мы используем <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/beginPath">beginPath()</a></code>, чтобы указать, что мы хотим нарисовать фигуру на бумаге.</li> + <li>Затем мы используем <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle">fillStyle</a></code> для определения того, какой цвет нам нужен, - мы устанавливаем его в свойство цвета нашего шара.</li> + <li>Затем мы используем метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc">arc()</a></code> для отслеживания формы дуги на бумаге. Его параметры: + <ul> + <li>Положение <code>x</code> и <code>y</code> центра дуги - мы указываем свойства <code>x</code> и <code>y</code> нашего шара.</li> + <li>Радиус нашей дуги - мы указываем свойство <code>size</code> шарика.</li> + <li>Последние два параметра определяют начальное и конечное число градусов по кругу, по которому проходит дуга. Здесь мы указываем 0 градусов и <code>2 * PI</code>, что эквивалентно 360 градусам в радианах (досадно, вы должны указать это в радианах). Это дает нам полный круг. Если вы указали только <code>1 * PI</code>, вы получите полукруг (180 градусов).</li> + </ul> + </li> + <li>В последнем случае мы используем метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fill">fill()</a></code>, который в основном утверждает: «Закончите рисование пути, начатого с <code>beginPath()</code>, и заполните область, которую он занимает с цветом, указанным ранее в <code>fillStyle</code>».</li> +</ul> + +<p>Теперь вы можете начать тестирование своего объекта..</p> + +<ol> + <li>Сохраните код и загрузите HTML-файл в браузер.</li> + <li>Откройте консоль JavaScript браузера, а затем обновите страницу, чтобы размер холста изменился в соответствии с новой шириной и высотой окна просмотра браузера после открытия консоли.</li> + <li>Чтобы создать новый экземпляр шара, введите следующее: + <pre class="brush: js notranslate">var testBall = new Ball(50, 100, 4, 4, 'blue', 10);</pre> + </li> + <li>Попробуйте вызвать его свойства и методы: + <pre class="brush: js notranslate">testBall.x +testBall.size +testBall.color +testBall.draw()</pre> + </li> + <li>После введения последней строки, вы должны увидеть, как мяч нарисовался где-то на вашем холсте.</li> +</ol> + +<h3 id="Обновление_данных_мяча">Обновление данных мяча</h3> + +<p>Мы можем нарисовать мяч в нужном положении, но чтобы начать движение мяча, нам нужна функция обновления. Добавьте следующий код внизу вашего файла JavaScript, чтобы добавить метод <code>update()</code> к <code>Ball()</code>'s <code>prototype</code>:</p> + +<pre class="brush: js notranslate">Ball.prototype.update = function() { + if ((this.x + this.size) >= width) { + this.velX = -(this.velX); + } + + if ((this.x - this.size) <= 0) { + this.velX = -(this.velX); + } + + if ((this.y + this.size) >= height) { + this.velY = -(this.velY); + } + + if ((this.y - this.size) <= 0) { + this.velY = -(this.velY); + } + + this.x += this.velX; + this.y += this.velY; +}</pre> + +<p>Первые четыре части функции проверяют, достиг ли шар края холста. Если это так, мы изменяем полярность соответствующей скорости, чтобы заставить шар двигаться в противоположном направлении. Так, например, если мяч двигался вверх (положительный <code>velY</code>), то вертикальная скорость изменяется так, что он начинает двигаться вниз (отрицательная величина <code>velY</code>).</p> + +<p>В этих четырех случаях мы:</p> + +<ul> + <li>Проверяем больше ли координата <code>x</code>, чем ширина холста (мяч уходит с правого края).</li> + <li>Проверяем будет ли координата <code>x</code> меньше 0 (мяч уходит с левого края).</li> + <li>Проверяем будет ли координата <code>y</code> больше высоты холста (мяч уходит с нижнего края).</li> + <li>Проверяем будет ли координата <code>y</code> меньше 0 (мяч уходит с верхнего края).</li> +</ul> + +<p>В каждом случае мы включаем <code>size</code> шарика в расчет, потому что координаты <code>x</code>/<code>y</code> находятся в центре шара, но мы хотим, чтобы край шара отскакивал от периметра - мы не хотим, чтобы мяч на половину заходил за границу экрана прежде чем он начнет возвращаться назад.</p> + +<p>Последние две строки добавляют значение <code>velX</code> к координате <code>x</code>, а значение <code>velY</code> - координате <code>y</code> - шар фактически перемещается при каждом вызове этого метода.</p> + +<p>На сейчас этого достаточно, давайте продолжим анимацию!</p> + +<h2 id="Анимация_мяча">Анимация мяча</h2> + +<p>Теперь давайте приступать к веселью! Сейчас мы начнем добавлять шары к холсту и анимировать их.</p> + +<ol> + <li>Во-первых, нам нужно где-то хранить все наши шары. Следующий массив выполнит это задание - добавьте его внизу кода: + <pre class="brush: js notranslate">var balls = [];</pre> + + <p>Все программы, которые оживляют вещи, обычно включают цикл анимации, который служит для обновления информации в программе, а затем визуализации результирующего представления для каждого кадра анимации; это основа для большинства игр и других подобных программ.</p> + </li> + <li>Добавьте ниже эту часть кода: + <pre class="brush: js notranslate">function loop() { + ctx.fillStyle = 'rgba(0, 0, 0, 0.25)'; + ctx.fillRect(0, 0, width, height); + + while (balls.length < 25) { + var ball = new Ball( + random(0,width), + random(0,height), + random(-7,7), + random(-7,7), + 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')', + random(10,20) + ); + balls.push(ball); + } + + for (var i = 0; i < balls.length; i++) { + balls[i].draw(); + balls[i].update(); + } + + requestAnimationFrame(loop); +}</pre> + + <p>Наша функция <code>loop()</code> выполняет следующие действия:</p> + + <ul> + <li>Устанавливает цвет заливки на полупрозрачный черный, затем рисует прямоугольник цвета по всей ширине и высоте холста, используя <code>fillRect()</code> (четыре параметра обеспечивают начальную координату, а ширину и высоту для рисованного прямоугольника ). Это позволяет скрыть рисунок предыдущего кадра до того, как будет нарисован следующий. Если вы этого не сделаете, вы увидите, как длинные змеи пробираются вокруг холста, а не шары! Цвет заливки устанавливается на полупрозрачный, <code>rgba(0,0,0,0,25)</code>, чтобы позволить нескольким кадрам слегка просвечивать, создавая маленькие тропы за шариками по мере их перемещения. Если вы изменили 0.25 на 1, вы больше не увидите их. Попробуйте изменить это число, чтобы увидеть эффект, который он имеет.</li> + <li>Создает новый экземпляр нашего <code>Ball()</code>, используя случайные значения, сгенерированные с помощью нашей функции <code>random()</code>, затем <code>push()</code> на конец нашего массива шаров, но только в том случае, когда количество шаров в массиве меньше 25. Итак когда у нас есть 25 мячей на экране, больше не появляется шаров. Вы можете попробовать изменить число в <code>balls.length < 25</code>, чтобы получить больше или меньше шаров на экране. В зависимости от того, сколько вычислительной мощности имеет ваш компьютер / браузер, если указать несколько тысячь шаров, это может довольно существенно повлиять на производительность анимации. </li> + <li>перебирает все шары в массиве <code>balls</code> и запускает каждую функцию <code>draw()</code> и <code>update()</code> для рисования каждого из них на экране, а затем выполняет необходимые обновления по положению и скорости во времени для следующего кадра.</li> + <li>Выполняет функцию снова с помощью метода <code>requestAnimationFrame()</code> - когда этот метод постоянно запускается и передается одно и то же имя функции, он будет запускать эту функцию определенное количество раз в секунду для создания плавной анимации. Обычно это делается рекурсивно - это означает, что функция вызывает себя каждый раз, когда она запускается, поэтому она будет работать снова и снова.</li> + </ul> + </li> + <li>И последнее, но не менее важное: добавьте следующую строку в конец вашего кода - нам нужно вызвать функцию один раз, чтобы начать анимацию. + <pre class="brush: js notranslate">loop();</pre> + </li> +</ol> + +<p>Вот и все для основы - попробуйте сохранить и освежить, чтобы проверить свои прыгающие шары!</p> + +<h2 id="Добавление_обнаружения_столкновений">Добавление обнаружения столкновений</h2> + +<p>Теперь немного поиграем, давайте добавим в нашу программу обнаружение конфликтов, поэтому наши мячи узнают, когда они ударят по другому шару.</p> + +<ol> + <li>Прежде всего, добавьте следующее определение метода ниже, где вы определили метод <code>update()</code> (т.е. блок <code>Ball.prototype.update</code>). + + <pre class="brush: js notranslate">Ball.prototype.collisionDetect = function() { + for (var j = 0; j < balls.length; j++) { + if (!(this === balls[j])) { + var dx = this.x - balls[j].x; + var dy = this.y - balls[j].y; + var distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < this.size + balls[j].size) { + balls[j].color = this.color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) +')'; + } + } + } +}</pre> + + <p>Этот метод немного сложный, поэтому не беспокойтесь, если вы не понимаете, как именно это работает. Ниже приводится объяснение:</p> + + <ul> + <li>Для каждого шара нам нужно проверить каждый другой шар, чтобы увидеть, столкнулся ли он с текущим мячом. Чтобы сделать это, мы открываем еще один цикл <code>for</code> через все шары в массиве <code>balls[]</code>.</li> + <li>Сразу же в нашем цикле for мы используем оператор <code>if</code>, чтобы проверить, проходит ли текущий шарик, тот же самый шар, что и тот, который мы сейчас проверяем. Мы не хотим проверять, что мяч столкнулся с самим собой! Для этого мы проверяем, является ли текущий мяч (т.е. мяч, метод которого вызван методом collisionDetect) такой же, как шар петли (т.е. шар, на который ссылается текущая итерация цикла for в collisionDetect метод). Затем мы используем <code>!</code> чтобы отменить проверку, чтобы код внутри оператора if выполнялся только в том случае, если они <strong>не</strong> совпадают.</li> + <li>Затем мы используем общий алгоритм для проверки столкновения двух окружностей. Мы в основном проверяем, перекрывается ли какая-либо из областей круга. Это объясняется далее <a href="https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection">2D collision detection</a>.</li> + <li>Если обнаружено столкновение, выполняется код внутри внутреннего оператора <code>if</code>. В этом случае мы просто устанавливаем свойство <code>color</code> обоих кругов на новый случайный цвет. Мы могли бы сделать что-то гораздо более сложное, например, заставить шары отскакивать друг от друга реалистично, но это было бы гораздо сложнее реализовать. Для такого моделирования физики разработчики склонны использовать игры или библиотеку физики, такие как <a href="http://wellcaffeinated.net/PhysicsJS/">PhysicsJS</a>, <a href="http://brm.io/matter-js/">matter.js</a>, <a href="http://phaser.io/">Phaser</a> и т.д.</li> + </ul> + </li> + <li>Вы также должны вызвать этот метод в каждом кадре анимации. Добавьте следующий код после строки <code>balls[i].update();</code> + <pre class="brush: js notranslate">balls[i].collisionDetect();</pre> + </li> + <li>Сохраните и обновите демо снова, и вы увидите, как ваши мячи меняют цвет, когда они сталкиваются!</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>. Если вам не удается заставить этот пример работать, попробуйте сравнить код JavaScript с нашей <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/bouncing-balls/main-finished.js">готовой версией</a> (также смотрите, как он работает <a href="https://mdn.github.io/learning-area/javascript/oojs/bouncing-balls/index-finished.html">в прямом эфире</a>).</p> +</div> + +<h2 id="Резюме">Резюме</h2> + +<p>Мы надеемся, что вам понравилось писать собственный пример случайных прыгающих шаров в реальном мире, используя различные объектные и объектно-ориентированные методы из всего модуля! Это должно было дать вам некоторую полезную практику использования объектов и хорошего контекста реального мира.</p> + +<p>Вот и все для предметных статей - все, что осталось сейчас, - это проверить свои навыки в оценке объекта.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="/en-US/docs/Web/API/Canvas_API/Tutorial">Canvas tutorial</a> — руководство для новичков по использованию 2D-холста.</li> + <li><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></li> + <li><a href="/en-US/docs/Games/Techniques/2D_collision_detection">2D collision detection</a></li> + <li><a href="/en-US/docs/Games/Techniques/3D_collision_detection">3D collision detection</a></li> + <li><a href="/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript">2D breakout game using pure JavaScript</a> — a great beginner's tutorial showing how to build a 2D game.</li> + <li><a href="/en-US/docs/Games/Tutorials/2D_breakout_game_Phaser">2D breakout game using Phaser</a> — explains the basics of building a 2D game using a JavaScript game library.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B">Основы объекта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object-oriented_JS">Объектно-ориентированный JavaScript для начинающих</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object_prototypes">Прототипы объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Inheritance">Наследование в JavaScript</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/JSON">Работа с данными JSON</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object_building_practice">Практика построения объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Adding_bouncing_balls_features">Добавление функций в нашу демонстрацию прыгающих шаров</a></li> +</ul> diff --git a/files/ru/learn/javascript/объекты/object_prototypes/index.html b/files/ru/learn/javascript/объекты/object_prototypes/index.html new file mode 100644 index 0000000000..0a76580d9c --- /dev/null +++ b/files/ru/learn/javascript/объекты/object_prototypes/index.html @@ -0,0 +1,285 @@ +--- +title: Прототипы объектов +slug: Learn/JavaScript/Объекты/Object_prototypes +tags: + - JavaScript + - create() + - Конструктор + - Начинающий + - ООП + - Обучение + - Обьект + - Статья + - прототип +translation_of: Learn/JavaScript/Objects/Object_prototypes +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</div> + +<div>Прототипы - это механизм, с помощью которого объекты JavaScript наследуют свойства друг от друга. В этой статье мы объясним, как работают цепочки прототипов, и рассмотрим, как свойство prototype можно использовать для добавления методов к существующим конструкторам.</div> + +<div></div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Базовая компьютерная грамотность, базовое понимание HTML и CSS, знакомство с основами JavaScript (см. <a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8">Первые шаги</a> и <a href="ru/docs/Learn/JavaScript/Building_blocks">Строительные блоки</a>) и основы OOJS (см. <a href="/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B">Введение в объекты</a>).</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Понять прототипы объектов JavaScript, как работают прототипные цепочки и как добавить новые методы в <code>prototype</code> свойство.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Язык_основанный_на_прототипах">Язык основанный на прототипах?</h2> + +<p>JavaScript часто описывают как язык <strong>прототипного наследования</strong> — каждый объект, имеет <strong>объект-прототип</strong>, который выступает как шаблон, от которого объект наследует методы и свойства. Объект-прототип так же может иметь свой прототип и наследовать его свойства и методы и так далее. Это часто называется <strong>цепочкой прототипов </strong>и объясняет почему одним объектам доступны свойства и методы которые определены в других объектах.</p> + +<p>Точнее, свойства и методы определяются в свойстве <code>prototype</code> функции-конструктора объектов, а не в самих объектах.</p> + +<p>В JavaScript создается связь между экземпляром объекта и его прототипом (свойство <code>__proto__</code>, которое является производным от свойства <code>prototype</code> конструктора), а свойства и методы обнаруживаются при переходе по цепочке прототипов.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Важно понимать, что существует различие между прототипом объекта (который доступен через <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf">Object.getPrototypeOf(obj)</a></code> или через устаревшее свойство <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto">__proto__</a></code>) и свойством <code>prototype</code> в функциях-конструкторах. Первое свойство является свойством каждого экземпляра, а второе - свойством конструктора. То есть <code>Object.getPrototypeOf(new Foobar())</code> относится к тому же объекту, что и <code>Foobar.prototype</code>.</p> +</div> + +<p>Давайте посмотрим на пример, чтобы стало понятнее.</p> + +<h2 id="Понимание_прототипа_объектов">Понимание прототипа объектов</h2> + +<p>Вернемся к примеру, когда мы закончили писать наш конструктор <code>Person()</code>- загрузите пример в свой браузер. Если у вас еще нет работы от последней статьи, используйте наш пример <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> (см. Также <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">исходный код</a>).</p> + +<p>В этом примере мы определили конструкторную функцию, например:</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">function</span> <span class="function token">Person</span><span class="punctuation token">(</span>first<span class="punctuation token">,</span> last<span class="punctuation token">,</span> age<span class="punctuation token">,</span> gender<span class="punctuation token">,</span> interests<span class="punctuation token">)</span> <span class="punctuation token">{</span> + + <span class="comment token">// Определения методов и свойств</span> + </code><code> this.name = { + 'first': first, + 'last' : last + }; + this.age = age; + this.gender = gender; + //...см. </code><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B">Введение в объекты</a> для полного определения<code class="language-js"> +<span class="punctuation token">}</span></code></pre> + +<p>Затем мы создаём экземпляр объекта следующим образом:</p> + +<pre class="brush: js">var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre> + +<p>Если вы наберете «<code>person1.</code>» в вашей консоли JavaScript, вы должны увидеть, что браузер пытается автоматически заполнить это с именами участников, доступных на этом объекте:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13853/object-available-members.png" style="display: block; margin: 0 auto;"></p> + +<p>В этом списке вы увидите элементы, определенные в конструкторе person 1 — Person() — <code>name</code>, <code>age</code>, <code>gender</code>, <code>interests</code>, <code>bio</code>, и <code>greeting</code>. Однако вы также увидите некоторые другие элементы — <code>watch</code>, <code>valueOf</code>и т. д. — они определены в объекте прототипа Person (), который является <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code>.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13891/MDN-Graphics-person-person-object-2.png" style="display: block; height: 150px; margin: 0px auto; width: 700px;"></p> + +<p>Итак, что произойдет, если вы вызываете метод в <code>person1</code>, который фактически определен в <code>Object</code>? Например:</p> + +<pre class="brush: js">person1.valueOf()</pre> + +<p>Этот метод — <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf">Object.valueOf()</a></code>наследуется <code>person1</code>, потому что его конструктором является <code>Person()</code>, а прототипом <code>Person()</code> является <code>Object()</code>. <code>valueOf()</code> возвращает значение вызываемого объекта — попробуйте и убедитесь! В этом случае происходит следующее:</p> + +<ul> + <li>Сначала браузер проверяет, имеет ли объект <code>person1</code> доступный в нем метод <code>valueOf()</code>, как определено в его конструкторе <code>Person()</code>.</li> + <li>Это не так, поэтому следующим шагом браузер проверяет, имеет ли прототип объекта (<code>Object()</code>) конструктора <code>Person()</code> доступный в нем метод <code>valueOf()</code>. Так оно и есть, поэтому он вызывается, и все хорошо!</li> +</ul> + +<div class="note"> +<p><strong>Примечание:</strong> Мы хотим повторить, что методы и свойства <strong>не</strong> копируются из одного объекта в другой в цепочке прототипов - к ним обращаются, поднимаясь по цепочке, как описано выше.</p> +</div> + +<div class="note"> +<p><strong>Примечание</strong>: Официально нет способа получить доступ к объекту прототипа объекта напрямую - «ссылки» между элементами в цепочке определены во внутреннем свойстве, называемом <code>[[prototype]]</code> в спецификации для языка JavaScript ( см. {{glossary("ECMAScript")}}). Однако у большинства современных браузеров есть свойство, доступное для них под названием <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto">__proto__</a></code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto"> </a>(это 2 подчеркивания с обеих сторон), который содержит объект-прототип объекта-конструктора. Например, попробуйте <code>person1.__proto__</code> и <code>person1.__proto__.__proto__</code>, чтобы увидеть, как выглядит цепочка в коде!</p> + +<p>С ECMAScript 2015 вы можете косвенно обращаться к объекту прототипа объекта <code>Object.getPrototypeOf (obj)</code>.</p> +</div> + +<h2 id="Свойство_prototype_Где_определены_унаследованные_экземпляры">Свойство prototype: Где определены унаследованные экземпляры</h2> + +<p>Итак, где определены наследуемые свойства и методы? Если вы посмотрите на страницу со ссылкой <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code>, вы увидите в левой части большое количество свойств и методов - это намного больше, чем количество унаследованных членов, доступных для объекта <code>person1</code>. Некоторые из них унаследованы, а некоторые нет - почему это?</p> + +<p>Как упоминалось выше, наследованные свойства это те, что определены в свойстве <code>prototype</code> (вы можете называть это подпространством имен), то есть те, которые начинаются с <code>Object.prototype.</code>, а не те, которые начинаются с простого <code>Object</code>. Значение свойства <code>prototype</code> - это объект, который в основном представляет собой контейнер для хранения свойств и методов, которые мы хотим наследовать объектами, расположенными дальше по цепочке прототипов.</p> + +<p>Таким образом <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch">Object.prototype.watch()</a></code>, <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf">Object.prototype.valueOf()</a></code> и т. д. доступны для любых типов объектов, которые наследуются от <code>Object.prototype</code>, включая новые экземпляры объектов, созданные из конструктора <code>Person()</code> .</p> + +<p><code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is">Object.is()</a></code>, <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys()</a></code> и другие члены, не определенные в контейнере <code>prototype</code>, не наследуются экземплярами объектов или типами объектов, которые наследуются от <code>Object.prototype</code>. Это методы / свойства, доступные только в конструкторе <code>Object()</code>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Это кажется странным - как у вас есть метод, определенный для конструктора, который сам по себе является функцией? Ну, функция также является типом объекта - см. Ссылку на конструктор <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function">Function()</a></code>, если вы нам не верите.</p> +</div> + +<ol> + <li>Вы можете проверить существующие свойства прототипа для себя - вернитесь к нашему предыдущему примеру и попробуйте ввести следующее в консоль JavaScript: + <pre class="brush: js">Person.prototype</pre> + </li> + <li>Результат покажет вам не много, ведь мы ничего не определили в прототипе нашего конструктора! По умолчанию <code>prototype</code> конструктора всегда пуст. Теперь попробуйте следующее: + <pre class="brush: js">Object.prototype</pre> + </li> +</ol> + +<p>Вы увидите большое количество методов, определенных для свойства <code>prototype</code> <code>Object</code>'а , которые затем доступны для объектов, которые наследуются от <code>Object</code>, как показано выше.</p> + +<p>Вы увидите другие примеры наследования цепочек прототипов по всему JavaScript - попробуйте найти методы и свойства, определенные на прототипе глобальных объектов <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code>, <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">Date</a></code>, <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">Number</a></code> и <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code>, например. Все они имеют несколько элементов, определенных на их прототипе, поэтому, например, когда вы создаете строку, вот так:</p> + +<pre class="brush: js">var myString = 'This is my string.';</pre> + +<p>В <code>myString</code> сразу есть множество полезных методов, таких как <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split">split()</a></code>, <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf">indexOf()</a></code>, <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a></code> и т. д.</p> + +<div class="warning"> +<p><strong>Важно</strong>: Свойство <code>prototype</code> является одной из наиболее противоречивых названий частей JavaScript - вы можете подумать, что <code>this</code> указывает на объект прототипа текущего объекта, но это не так (это внутренний объект, к которому можно получить доступ <code>__proto__</code>, помните ?). <code>prototype</code> вместо этого - свойство, содержащее объект, на котором вы определяете членов, которые вы хотите наследовать.</p> +</div> + +<h2 id="Снова_create">Снова create()</h2> + +<p>Ранее мы показали, как метод <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create">Object.create()</a></code> может использоваться для создания нового экземпляра объекта.</p> + +<ol> + <li>Например, попробуйте это в консоли JavaScript предыдущего примера: + <pre class="brush: js">var person2 = Object.create(person1);</pre> + </li> + <li>На самом деле <code>create()</code>создает новый объект из указанного объекта-прототипа. Здесь <code>person2</code> создается с помощью <code>person1</code> в качестве объекта-прототипа. Это можно проверить, введя в консоли следующее: + <pre class="brush: js">person2.__proto__</pre> + </li> +</ol> + +<p>Это вернет объект <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">person1</span></font>.</p> + +<h2 id="Свойство_constructor">Свойство constructor</h2> + +<p>Каждая функция-конструктор имеет свойство <code>prototype</code>, значением которого является объект, содержащий свойство <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">constructor</a></code>. Это свойство <code>constructor</code> указывает на исходную функцию-конструктор. Как вы увидите в следующем разделе, свойства, определенные в свойстве <code>Person.prototype</code> (или в общем случае в качестве свойства прототипа функции конструктора, который является объектом, как указано в предыдущем разделе) становятся доступными для всех объектов экземпляра, созданных с помощью конструктор <code>Person()</code>. Следовательно, свойство конструктора также доступно для объектов <code>person1</code> и <code>person2</code>.</p> + +<ol> + <li>Например, попробуйте эти команды в консоли: + <pre class="brush: js">person1.constructor +person2.constructor</pre> + + <p>Они должны возвращать конструктор <code>Person()</code>, поскольку он содержит исходное определение этих экземпляров.</p> + + <p>Хитрый трюк заключается в том, что вы можете поместить круглые скобки в конец свойства <code>constructor</code> (содержащие любые требуемые параметры) для создания другого экземпляра объекта из этого конструктора. Конструктор - это функция в конце концов, поэтому ее можно вызвать с помощью круглых скобок; вам просто нужно включить ключевое слово <code>new</code>, чтобы указать, что вы хотите использовать эту функцию в качестве конструктора.</p> + </li> + <li>Попробуйте это в консоли: + <pre class="brush: js">var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);</pre> + </li> + <li>Теперь попробуйте получить доступ к функциям вашего нового объекта, например: + <pre class="brush: js">person3.name.first +person3.age +person3.bio()</pre> + </li> +</ol> + +<p>Это хорошо работает. Вам не нужно будет использовать его часто, но это может быть действительно полезно, если вы хотите создать новый экземпляр и не имеете ссылки на исходный конструктор, который легко доступен по какой-либо причине.</p> + +<p>Свойство <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">constructor</a></code> имеет другие применения. Например, если у вас есть экземпляр объекта и вы хотите вернуть имя конструктора этого экземпляра, вы можете использовать следующее:</p> + +<pre class="brush: js">instanceName.constructor.name</pre> + +<p>Например, попробуйте это:</p> + +<pre class="brush: js">person1.constructor.name +</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Значение <code>constructor.name</code> может измениться (из-за прототипического наследования, привязки, препроцессоров, транспилеров и т. д.), Поэтому для более сложных примеров вы захотите использовать оператор <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof">instanceof</a></code>.</p> +</div> + +<ol> +</ol> + +<h2 id="Изменение_прототипов">Изменение прототипов</h2> + +<p>Давайте рассмотрим пример изменения свойства <code>prototype</code> функции-конструктора — методы, добавленные в прототип, затем доступны для всех экземпляров объектов, созданных из конструктора.</p> + +<ol> + <li>Вернитесь к нашему примеру <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> и создайте локальную копию <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">исходного кода</a>. Ниже существующего JavaScript добавьте следующий код, который добавляет новый метод в свойство <code>prototype</code> конструктора: + + <pre class="brush: js">Person.prototype.farewell = function() { + alert(this.name.first + ' has left the building. Bye for now!'); +};</pre> + </li> + <li>Сохраните код и загрузите страницу в браузере и попробуйте ввести следующее в текстовый ввод: + <pre class="brush: js">person1.farewell();</pre> + </li> +</ol> + +<p>Должно появиться всплывающее окно, с именем пользователя, определенным в конструкторе. Это действительно полезно, но ещё более полезно то, что вся цепочка наследования обновляется динамически, автоматически делая этот новый метод доступным для всех экземпляров объектов, полученных из конструктора.</p> + +<p>Подумайте об этом на мгновение. В нашем коде мы определяем конструктор, затем мы создаем экземпляр объекта из конструктора, <em>затем</em> добавляем новый метод к прототипу конструктора:</p> + +<pre class="brush: js">function Person(first, last, age, gender, interests) { + + // определения свойств и методов + +} + +var person1 = new Person('Tammi', 'Smith', 32, 'neutral', ['music', 'skiing', 'kickboxing']); + +Person.prototype.farewell = function() { + alert(this.name.first + ' has left the building. Bye for now!'); +};</pre> + +<p>Но метод <code>farewell()</code> <em>по-прежнему</em> доступен в экземпляре объекта <code>person1</code> - его элементы были автоматически обновлены, чтобы включить недавно определенный метод <code>farewell()</code>.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Если у вас возникли проблемы с получением этого примера для работы, посмотрите на наш пример <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-prototype.html">oojs-class-prototype.html</a> (см. также это <a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-prototype.html">running live</a>).</p> +</div> + +<p>Вы редко увидите свойства, определенные в свойстве <code>prototype</code>, потому что они не очень гибки при таком определении. Например, вы можете добавить свойство следующим образом:</p> + +<pre class="brush: js">Person.prototype.fullName = 'Bob Smith';</pre> + +<p>Это не очень гибко, так как человека нельзя назвать так. Было бы намного лучше сделать это, создав <code>fullName</code> из <code>name.first</code> и <code>name.last</code>:</p> + +<pre class="brush: js">Person.prototype.fullName = this.name.first + ' ' + this.name.last;</pre> + +<p>Однако это не работает, поскольку в этом случае <code>this</code> будет ссылаться на глобальную область, а не на область функции. Вызов этого свойства вернет <code>undefined undefined</code>. Это отлично работало с методом, который мы определили ранее в прототипе, потому что он находится внутри области функций, которая будет успешно перенесена в область экземпляра объекта. Таким образом, вы можете определить постоянные свойства прототипа (т. е. те, которые никогда не нуждаются в изменении), но обычно лучше определять свойства внутри конструктора.</p> + +<p>Фактически, довольно распространенный шаблон для большего количества определений объектов - это определение свойств внутри конструктора и методов в прототипе. Это упрощает чтение кода, поскольку конструктор содержит только определения свойств, а методы разделены на отдельные блоки. Например:</p> + +<pre class="brush: js">// Определение конструктора и его свойств + +function Test(a, b, c, d) { + // определение свойств... +} + +// Определение первого метода + +Test.prototype.x = function() { ... }; + +// Определение второго метода + +Test.prototype.y = function() { ... }; + +//...и так далее</pre> + +<p>Этот образец можно увидеть в действии в примере <a href="https://github.com/zalun/school-plan-app/blob/master/stage9/js/index.js">приложения плана школы </a>Петра Залевы.</p> + +<h2 id="Резюме">Резюме</h2> + +<p>В этой статье рассмотрены прототипы объектов JavaScript (в том числе и то, как прототип цепочки объектов позволяет объектам наследовать функции друг от друга), свойство прототипа и как его можно использовать для добавления методов к конструкторам и другие связанные с этой статьёй темы.</p> + +<p>В следующей статье мы рассмотрим то, как вы можете реализовать наследование функциональности между двумя собственными настраиваемыми объектами.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</p> + + + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Основы">Основы объекта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Object-oriented_JS">Объектно-ориентированный JavaScript для начинающих</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Object_prototypes">Прототипы объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Inheritance">Наследование в JavaScript</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/JSON">Работа с данными JSON</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Object_building_practice">Практика построения объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Объекты/Adding_bouncing_balls_features">Добавление функций в нашу демонстрацию прыгающих шаров</a></li> +</ul> diff --git a/files/ru/learn/javascript/объекты/основы/index.html b/files/ru/learn/javascript/объекты/основы/index.html new file mode 100644 index 0000000000..a4e7cc0071 --- /dev/null +++ b/files/ru/learn/javascript/объекты/основы/index.html @@ -0,0 +1,257 @@ +--- +title: Основы объектов в JavaScript +slug: Learn/JavaScript/Объекты/Основы +tags: + - JavaScript + - ООП +translation_of: Learn/JavaScript/Objects/Basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">В этой статье мы рассмотрим объекты в JavaScript. Мы будем разбирать основы синтаксиса объектов JavaScript и заново изучим некоторый функционал JavaScript, который мы уже исследовали ранее на курсе, подтвердив тот факт, что большая часть функционала, с которым мы уже столкнулись, в действительности является объектами.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Элементарная компьютерная грамотность, базовое понимание HTML и CSS, знакомство с основами JavaScript (см. <a href="/ru/docs/Learn/JavaScript/Первые_шаги">Первые шаги</a> и <a href="/ru/docs/Learn/JavaScript/Building_blocks">Структурные элементы</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понимать основу теории перед началом объектно-ориентированного программирования, как это связано с JavaScript ("большинство сущностей являются объектами"), и как начать работу с объектами JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Основы_объектов">Основы объектов</h2> + +<p>Объект — это совокупность связанных данных и/или функциональных возможностей. Обычно состоят из нескольких переменных и функций, которые называются свойства и методы, если они находятся внутри объектов. Разберём пример, чтобы показать, как они выглядят.</p> + +<p>Чтобы начать, скопируйте себе <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> файл. В нём содержится очень мало: {{HTMLElement("script")}} элемент для написания в нём исходного кода. Мы будем использовать это как основу для изучения основ синтаксиса объектов. Во время работы с этим примером у вас должна быть открытая <a href="/ru/docs/Learn/Discover_browser_developer_tools#%D0%9A%D0%BE%D0%BD%D1%81%D0%BE%D0%BB%D1%8C_JavaScript">консоль JavaScript инструментов разработчика</a>, готовая к вводу некоторых команд.</p> + +<p>Как и во многих случаях в JavaScript, создание объекта часто начинается с определения и инициализации переменной. Попробуйте ввести следующий код JavaScript в ваш файл, а затем сохраните файл и обновите страницу браузера:</p> + +<pre class="brush: js notranslate">const person = {};</pre> + +<p>Если Вы введёте <code>person</code> в текстовое JS консоль и нажмёте клавишу Enter, должен получиться следующий результат:</p> + +<pre class="brush: js notranslate"><code class="language-js">Object</code><code> </code>{ }</pre> + +<p>Поздравляем, Вы только что создали Ваш первый объект. Но это пустой объект, поэтому мы не можем с ним ничего сделать. Давайте обновим наш объект, чтобы он выглядел так:</p> + +<pre class="brush: js notranslate">const person = { + name: ['Bob', 'Smith'], + age: 32, + gender: 'male', + interests: ['music', 'skiing'], + bio: function() { + alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); + }, + greeting: function() { + alert('Hi! I\'m ' + this.name[0] + '.'); + } +}; +</pre> + +<p>После сохранения и обновления, попробуйте ввести что-нибудь следующее в консоль JavaScript браузера:</p> + +<pre class="brush: js notranslate"><code class="language-js">person<span class="punctuation token">.</span>name</code> +person.name[0] +person.age +person.interests[1] +person.bio() +person.greeting()</pre> + +<p>Теперь внутри объекта есть некоторые данные и функционал, и теперь можно получить доступ к ним с помощью некоторого лёгкого и простого синтаксиса!</p> + +<div class="note"> +<p><strong>Примечание</strong>: Если у вас возникли проблемы с применением файла в работе, попробуйте сравнить ваш код с нашей версией — см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-finished.html">oojs-finished.html</a> (также <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-finished.html">see it running live</a>). Одна из распространенных ошибок, когда Вы начинаете с объектами ставить запятую в конце последнего члена — это приводит к ошибке.</p> +</div> + +<p>Итак что здесь происходит? Объект состоит из нескольких элементов, каждый из которых имеет своё название (пример <code>name</code> и <code>age</code> выше), и значение (пример <code>['Bob', 'Smith']</code> и <code>32</code>). Каждая пара название/значение должны быть разделены запятой, а название и значение в каждом случае разделяются двоеточием. Синтаксис всегда следует этому образцу:</p> + +<pre class="brush: js notranslate">const objectName = { + member1Name: member1Value, + member2Name: member2Value, + member3Name: member3Value +};</pre> + +<p>Значение члена объекта может быть чем угодно — в нашем объекте person есть строка, число, два массива, и две функции. Первые четыре элемента это элементы данных, относящиеся к <strong>свойствам</strong> объекта. Последние два элемента являются функциями, которые позволяют объекту что-то сделать с элементами данных, и называются <strong>методами</strong> объекта.</p> + +<p>Такие объекты называются <strong>литералами объекта</strong> (<strong>object literal</strong>) — мы буквально вписали все содержимое объекта для его создания. Этот способ сильно отличается от объектов реализованных классами, которые мы рассмотрим позже.</p> + +<p>Очень часто для создания объекта используется литерал объекта когда вам нужно каким-то образом перенести ряд структурированных, связанных элементов данных, например, отправляя запрос на сервер, для размещения их в базе данных. Отправка одного объекта намного эффективнее, чем отправка нескольких элементов по отдельности, и с ним легче работать чем с массивом, если требуется идентифицировать отдельные элементы по имени. </p> + +<h2 id="Точечная_запись_Dot_notation">Точечная запись (Dot notation)</h2> + +<p>Выше Вы получили доступ к свойствам и методам используя <strong>точечную запись (dot notation). </strong>Имя объекта (person) действует как <strong>пространство имен (namespace) </strong>— оно должно быть введено первым, для того чтобы получить доступ ко всему что заключено (<strong>encapsulated)</strong> внутри объекта. Далее Вы пишете точку, затем элемент, к которому хотите получить доступ — это может быть имя простого свойства, элемент массива, или вызов одного из методов объекта, например:</p> + +<pre class="brush: js notranslate">person.age +person.interests[1] +person.bio()</pre> + +<h3 id="Внутренние_пространства_имен_Sub-namespaces">Внутренние пространства имен (Sub-namespaces)</h3> + +<p>Можно даже сделать значением элемента объекта другой объект. Например, попробуйте изменить значение свойства name с такого</p> + +<pre class="brush: js notranslate">name: ['Bob', 'Smith'],</pre> + +<p>на такое</p> + +<pre class="brush: js notranslate">name : { + first: 'Bob', + last: 'Smith' +},</pre> + +<p>Здесь мы фактически создаем <strong>внутреннее пространство имен (sub-namespace). </strong>Это звучит сложно, но на самом деле это не так — для доступа к этим элементам Вам нужно сделать один дополнительный шаг с еще одной точкой. Попробуйте в консоли браузера следующее: </p> + +<pre class="brush: js notranslate">person.name.first +person.name.last</pre> + +<p><strong>Важно</strong>: На этом этапе вам также нужно будет пересмотреть код метода и изменить все экземпляры с</p> + +<pre class="brush: js notranslate">name[0] +name[1]</pre> + +<p>на</p> + +<pre class="brush: js notranslate">name.first +name.last</pre> + +<p>Иначе ваши методы больше не будут работать.</p> + +<h2 id="Скобочная_запись_Bracket_notation">Скобочная запись (Bracket notation)</h2> + +<p>Существует другой способ получить свойства объекта — использовать скобочную запись (bracket notation). Вместо написания этого кода:</p> + +<pre class="brush: js notranslate">person.age +person.name.first</pre> + +<p>Вы можете использовать следующий</p> + +<pre class="brush: js notranslate">person['age'] +person['name']['first']</pre> + +<p>Это выглядит очень похоже на то, как Вы получаете элементы массива, и в принципе это так и есть — вместо использования числовых индексов для выбора элемента, Вы ассоциируете имя свойства для каждого значения. Ничего удивительного, что эти объекты иногда называют ассоциативными массивами — они сопоставляют строки со значениями так же, как массивы сопоставляют числовые индексы со значениями.</p> + +<h2 id="Запись_элементов_в_объект">Запись элементов в объект</h2> + +<p>До сих пор мы рассмастривали только возврат (или получение) элементов объекта — Вы так же можете установить (обновить) значение элемента объекта просто объявив элемент, который Вы хотите установить (используя точечную или скобочную запись), например:</p> + +<pre class="brush: js notranslate">person.age = 45; +person['name']['last'] = 'Cratchit';</pre> + +<p>Попробуйте ввести эти строки, а затем снова верните элементы, чтобы увидеть, как они изменились</p> + +<pre class="brush: js notranslate">person.age +person['name']['last']</pre> + +<p>Вы можете не просто обновлять и устанавливать значения свойств и методов объекта, а так же устанавливать совершенно новые элементы. Попробуйте их в консоли JS:</p> + +<pre class="brush: js notranslate">person['eyes'] = 'hazel'; +person.farewell = function() { alert("Bye everybody!"); }</pre> + +<p>Теперь Вы можете проверить ваши новые элементы:</p> + +<pre class="brush: js notranslate">person['eyes'] +person.farewell()</pre> + +<p>Одним из полезных аспектов скобочной записи является то, что с ее помощью можно динамически задавать не только значения элементов, но и их имена. Предположим, что мы хотим, чтобы пользователи могли хранить пользовательские типы данных, введя имя и значение элемента в два следующих поля? Мы могли бы получить эти значения следующим образом:</p> + +<pre class="brush: js notranslate">let myDataName = nameInput.value; +let myDataValue = nameValue.value;</pre> + +<p>Затем мы можем добавить имя и значение этого нового элемента в объект <code>person</code> таким образом:</p> + +<pre class="brush: js notranslate">person[myDataName] = myDataValue;</pre> + +<p>Чтобы проверить это, попробуйте добавить следующие строки в свой код, после закрывающей скобки объекта <code>person</code> :</p> + +<pre class="brush: js notranslate">let myDataName = 'height'; +let myDataValue = '1.75m'; +person[myDataName] = myDataValue;</pre> + +<p>Теперь попробуйте сохранить и обновить, затем введите следующее в консоль браузера:</p> + +<pre class="brush: js notranslate">person.height</pre> + +<p>Добавление свойства объекта с использованием вышеописанного метода невозможно с использованием точечной записи, которая может принимать только литеральное имя элемента, а не значение переменной указывающее на имя.</p> + +<h2 id="Что_такое_this">Что такое "this"?</h2> + +<p>Возможно, вы заметили что-то странное в наших методах. Посмотрите на этот пример:</p> + +<pre class="brush: js notranslate">greeting: function() { + alert('Hi! I\'m ' + this.name.first + '.'); +}</pre> + +<p>Вы, вероятно, задаетесь вопросом, что такое "this"? Ключевое слово <code>this</code>, ссылается на текущий объект, внутри которого пишется код — поэтому в нашем случае <code>this</code> равен объекту <code>person</code>. Но почему просто не написать <code>person</code>? Как Вы увидите в статье <a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a> (Объектно-ориентированный JavaScript для начинающих), когда мы начинаем создавать конструкторы и т.д., <code>this</code> очень полезен — он всегда будет гарантировать, что используется верное значение, когда контекст элемента изменяется (например, два разных экземпляра объекта <code>person</code> могут иметь разные имена, но захотят использовать свое собственное имя при приветствии.</p> + +<p>Давайте проиллюстритуем, что мы имеем в виду, с упрощенной парой объектов <code>person</code> :</p> + +<pre class="brush: js notranslate">const person1 = { + name: 'Chris', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +} + +const person2 = { + name: 'Brian', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +}</pre> + +<p>В этом случае, <code>person1.greeting()</code> выведет "Hi! I'm Chris.". <code>person2.greeting()</code>, с другой стороны, выведет "Hi! I'm Brian.", хотя код метода одинаковый в обоих случаях. Как мы сказали ранее, <code>this</code> равен объекту, внутри которого находится код — это не очень полезно, когда Вы пишите литералы объектов вручную, но оно действительно помогает, когда Вы генерируете объекты динамически (например используя конструкторы). Это станет понятнее чуть позже.</p> + +<h2 id="Все_это_время_вы_использовали_объекты">Все это время вы использовали объекты</h2> + +<p>Пока Вы проходили эти примеры, Вы вероятно заметили, что точечная запись, которую Вы использовали, выглядит очень знакомо. Это потому, что Вы использовали ее на протяжении всего курса! Каждый раз, когда мы работаем над примером, использующим встроенный API браузера или объект JavaScript, мы использовали объекты, потому что такие функции построены с использованием тех же структур объектов, которые мы здесь рассматривали, хотя и более сложные, чем наши собственные пользовательские примеры. </p> + +<p>Поэтому, когда Вы использовали строковые методы, такие как:</p> + +<pre class="brush: js notranslate">myString.split(',');</pre> + +<p>Вы использовали метод доступный в экземпляре класса <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code>. Каждый раз создавая строку в вашем коде, эта строка автоматически создается как экземпляр <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code>, и поэтому имеет несколько общих методов/свойств, доступных на нем.</p> + +<p>Когда Вы обращались к объектной модели документа (DOM), используя следующие строки:</p> + +<pre class="brush: js notranslate">const myDiv = document.createElement('div'); +const myVideo = document.querySelector('video');</pre> + +<p>Вы использовали методы доступные в экземпляре класса <code><a href="/en-US/docs/Web/API/Document">Document</a></code>. Для каждой загруженной веб-страницы создается экземпляр <code><a href="/en-US/docs/Web/API/Document">Document</a></code>, называемый <code>document</code>, который представляет всю структуру страницы, ее содержимое и другие функции, такие как URL-адрес. Опять же, это означает, что он имеет несколько общих методов/свойств, доступных на нем.</p> + +<p>То же самое относится и к любому другому встроенному объекту/API, который вы использовали — <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code>, <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math">Math</a></code>, и т. д.</p> + +<p>Обратите внимание, что встроенные объекты/API не всегда создают экземпляры объектов автоматически. Как пример, <a href="/ru/docs/Web/API/Notifications_API">Notifications API</a> — который позволяет новым браузерам запускать системные уведомления, требует, чтобы Вы создавали новый экземпляр объекта с помощью конструктора для каждого уведомления, которое Вы хотите запустить. Попробуйте ввести следующее в консоль JavaScript:</p> + +<pre class="brush: js notranslate">const myNotification = new Notification('Hello!');</pre> + +<p>Опять же, мы рассмотрим конструкторы в следующей статье.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Полезно подумать о том, как объекты взаимодействуют посредством передачи сообщений - когда объекту требуется другой объект для выполнения какого-либо действия, он часто отправляет сообщение другому объекту через один из его методов и ждет ответа, который мы знаем как возвращаемое (return) значение.</p> +</div> + +<h2 id="Резюме">Резюме</h2> + +<p>Поздравляем, Вы достигли конца нашей первой статьи о объектах JS, теперь у вас должно быть хорошее представление о том, как работать с объектами в JavaScript - в том числе создавать свои собственные простые объекты. Вы также должны понимать, что объекты очень полезны в качестве структур для хранения связанных данных и функциональности - если бы мы пытались отслеживать все свойства и методы в нашем объекте <code>person</code> как отдельные переменные и функции, это было неэффективно, и мы бы рисковали столкнуться с другими переменными и функциями с такими же именами. Объекты позволяют нам безопасно хранить информацию в своем собственном блоке, вне опасности.</p> + +<p>В следующей статье мы начнем рассматривать теорию объектно-ориентированного программирования (OOП) и как эти техники могут быть использованны в JavaScript </p> + +<p>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B">Основы объекта</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object-oriented_JS">Объектно-ориентированный JavaScript для начинающих</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object_prototypes">Прототипы объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Inheritance">Наследование в JavaScript</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/JSON">Работа с данными JSON</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Object_building_practice">Практика построения объектов</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D1%8B/Adding_bouncing_balls_features">Добавление функций в нашу демонстрацию прыгающих шаров</a></li> +</ul> diff --git a/files/ru/learn/javascript/первые_шаги/a_first_splash/index.html b/files/ru/learn/javascript/первые_шаги/a_first_splash/index.html new file mode 100644 index 0000000000..b2a811b992 --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/a_first_splash/index.html @@ -0,0 +1,675 @@ +--- +title: Первое погружение в JavaScript +slug: Learn/JavaScript/Первые_шаги/A_first_splash +translation_of: Learn/JavaScript/First_steps/A_first_splash +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/What_is_JavaScript", "Learn/JavaScript/Первые_шаги/Что_пошло_не_так", "Learn/JavaScript/Первые_шаги")}}</div> + +<p class="summary">Теперь, когда вы получили <a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/First_steps/What_is_JavaScript">базовое представление о JavaScript</a> — самое время познакомиться с ним на практике! В данной статье представлен ускоренный практический курс, демонстрирующий основные возможности JavaScript. В этом курсе, шаг за шагом, вы создадите простую игру «Угадай число».</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td>Базовая компьютерная грамотность, знание основ HTML и CSS, понимание что такое и для чего нужен JavaScript.</td> + </tr> + <tr> + <th scope="row">Цели:</th> + <td>Получение первого опыта в программировании на JavaScript.</td> + </tr> + </tbody> +</table> + +<p>Вам не придется сразу понимать весь код — мы только хотим познакомить вас с базовыми концепциями языка и дать представление о том, как работает JavaScript (и другие языки программирования). В дальнейших статьях вы изучите эти концепции более подробно!</p> + +<div class="note"> +<p>Большинство языковых конструкций JavaScript, с которыми вы познакомитесь (функции, циклы и т.д.), имеют аналоги в других языках программирования — т.е. языки имеют разный синтаксис, но концепции в большинстве случаев те же самые.</p> +</div> + +<h2 id="Думай_как_программист">Думай как программист</h2> + +<p>Одним из самых трудных и значимых моментов в обучении программированию является не изучение непосредственно синтаксиса языка, а понимание того как применять его для решения реальных задач. Вам нужно начать думать как программист, обычно это означает следующее:</p> + +<ul> + <li>Сначала вы разрабатываете логику (структуру, алгоритм выполнения) программы — общие задачи, что и в каких случаях она должна делать, как должна завершиться и т.д., т.е. создаете описание полного цикла её работы.</li> + <li>Затем определяете какие конструкции (возможности) языка вам понадобятся и как заставить их работать вместе — для последовательного выполнения всех этапов разработанной логики.</li> +</ul> + +<p>Всё вместе это потребует тяжелой работы, знания языка, практики в написании кода - и немного творчества. Чем больше вы будете заняты решением практических задач, тем быстрее будете расти в программировании. Мы не обещаем, что вы сразу начнете "думать как программист", но предоставим для этого достаточно возможностей в этой статье.</p> + +<p>Учитывая вышесказанное, на примере простой игры, давайте детально разберем каждый этап создания программы и познакомимся с некоторыми конструкциями языка.</p> + +<h2 id="Игра_«Угадай_число»">Игра «Угадай число»</h2> + +<p>В этой статье мы покажем вам как создать простую игру, которую вы видите ниже:</p> + +<div class="hidden"> +<h6 id="Top_hidden_code">Top hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title>Number guessing game</title> + <style> + html { + font-family: sans-serif; + } + + body { + width: 50%; + max-width: 800px; + min-width: 480px; + margin: 0 auto; + } + + .lastResult { + color: white; + padding: 3px; + } + </style> +</head> + +<body> + <h1>Number guessing game</h1> + <p>We have selected a random number between 1 and 100. See if you can guess it in 10 turns or less. We'll tell you if your guess was too high or too low.</p> + <div class="form"> <label for="guessField">Enter a guess: </label><input type="text" id="guessField" class="guessField"> <input type="submit" value="Submit guess" class="guessSubmit"> </div> + <div class="resultParas"> + <p class="guesses"></p> + <p class="lastResult"></p> + <p class="lowOrHi"></p> + </div> +</body> +<script> + // Your JavaScript goes here + var randomNumber = Math.floor(Math.random() * 100) + 1; + var guesses = document.querySelector('.guesses'); + var lastResult = document.querySelector('.lastResult'); + var lowOrHi = document.querySelector('.lowOrHi'); + var guessSubmit = document.querySelector('.guessSubmit'); + var guessField = document.querySelector('.guessField'); + var guessCount = 1; + var resetButton; + + function checkGuess() { + var userGuess = Number(guessField.value); + if (guessCount === 1) { + guesses.textContent = 'Previous guesses: '; + } + + guesses.textContent += userGuess + ' '; + + if (userGuess === randomNumber) { + lastResult.textContent = 'Congratulations! You got it right!'; + lastResult.style.backgroundColor = 'green'; + lowOrHi.textContent = ''; + setGameOver(); + } else if (guessCount === 10) { + lastResult.textContent = '!!!GAME OVER!!!'; + lowOrHi.textContent = ''; + setGameOver(); + } else { + lastResult.textContent = 'Wrong!'; + lastResult.style.backgroundColor = 'red'; + if(userGuess < randomNumber) { + lowOrHi.textContent='Last guess was too low!' ; + } else if(userGuess > randomNumber) { + lowOrHi.textContent = 'Last guess was too high!'; + } + } + + guessCount++; + guessField.value = ''; + } + + guessSubmit.addEventListener('click', checkGuess); + + function setGameOver() { + guessField.disabled = true; + guessSubmit.disabled = true; + resetButton = document.createElement('button'); + resetButton.textContent = 'Start new game'; + document.body.appendChild(resetButton); + resetButton.addEventListener('click', resetGame); + } + + function resetGame() { + guessCount = 1; + var resetParas = document.querySelectorAll('.resultParas p'); + for(var i = 0 ; i < resetParas.length ; i++) { + resetParas[i].textContent=''; + } + + resetButton.parentNode.removeChild(resetButton); + guessField.disabled = false; + guessSubmit.disabled = false; + guessField.value=''; + guessField.focus(); + lastResult.style.backgroundColor='white'; + randomNumber=Math.floor(Math.random() * 100) + 1; + } +</script> + +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Top_hidden_code', '100%', 320) }}</p> + +<p>Поиграйте в нее - познакомьтесь с игрой, прежде чем двигаться дальше.</p> + +<p>Давайте представим, что ваш босс дал вам следующую информацию для создания этой игры:</p> + +<blockquote> +<p>Я хочу чтобы ты создал простую игру по принципу "Угадай число". Игра должна случайным образом генерировать число от 0 до 100, затем игрок должен отгадать это число за 10 попыток. После каждой попытки игроку сообщают угадал он число или не угадал и если он ошибся, то ему сообщается, что загаданное число больше или меньше того, которое он ввел. Так же необходимо показывать игроку числа из его предыдущих попыток. Игра будет окончена, если игрок угадал число верно или если у него кончатся все попытки. После окончания игры игроку будет дана возможность сыграть в игру еще раз.</p> +</blockquote> + +<p>Поглядев на это краткое изложение, первое, что мы можем сделать - это начать разбивать его на простые действия, максимально думая как программист:</p> + +<ol> + <li>Сгенерировать случайное число между 1 и 100.</li> + <li>Начать запись количества попыток игрока угадать число. Начать с 1.</li> + <li>Предоставить попытку угадать игроку загаданное число.</li> + <li>Как только попытка угадать была отправлена, сначала записать ее где-нибудь, чтобы пользователь мог увидеть свои предыдущие попытки</li> + <li>Далее, проверить было ли это число верным.</li> + <li>Если число верное: + <ol> + <li>Показать поздравительное сообщение.</li> + <li>Оградить игрока от дальнейшей возможности ввода чисел (это испортит игру).</li> + <li>Предоставить возможность для перезапуска игры.</li> + </ol> + </li> + <li>Если число не верное и есть попытки: + <ol> + <li>Сказать игроку, что он не угадал.</li> + <li>Разрешить ему использовать еще попытку.</li> + <li>Повысить число попыток на 1.</li> + </ol> + </li> + <li>Если число не верное и попыток нет: + <ol> + <li>Сказать игроку, что игра окончена.</li> + <li>Оградить игрока от дальнейшей возможности ввода чисел (это испортит игру).</li> + <li>Предоставить возможность для перезапуска игры.</li> + </ol> + </li> + <li>Во время перезапуска игры убедиться, что игровая логика и пользовательский интерфейс полностью сбросились на начальные значения и далее перейти обратно к пункту 1.</li> +</ol> + +<p>Давайте теперь перейдем к рассмотрению того, как мы можем превратить эти шаги в код, создавая примеры и исследуя возможности JavaScript по ходу.</p> + +<h3 id="Подготовка">Подготовка</h3> + +<p>В начале этого урока, мы хотели бы, чтобы вы создали локальную копию файла <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">number-guessing-game-start.html</a> (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">см. здесь</a>). Откройте его как в текстовом редакторе, так и в веб-браузере. На данный момент вы увидите простой заголовок, абзац с инструкцией и форму для ввода предположения, но форма в настоящее время ничего не сделает.</p> + +<p>Место, где мы будем добавлять весь наш код, находится внутри элемента {{htmlelement("script")}} в нижней части HTML:</p> + +<pre class="brush: html notranslate"><script> + + // Your JavaScript goes here + +</script> +</pre> + +<h3 id="Добавление_переменных_для_хранения_данных">Добавление переменных для хранения данных</h3> + +<p>Давайте начнем. Прежде всего добавьте следующие строки внутри элемента {{htmlelement("script")}} :</p> + +<pre class="notranslate"><code>var randomNumber = Math.floor(Math.random() * 100) + 1; + +var guesses = document.querySelector('.guesses'); +var lastResult = document.querySelector('.lastResult'); +var lowOrHi = document.querySelector('.lowOrHi'); + +var guessSubmit = document.querySelector('.guessSubmit'); +var guessField = document.querySelector('.guessField'); + +var guessCount = 1; +var resetButton;</code></pre> + +<p>В этом разделе кода устанавливаются переменные, необходимые для хранения данных, которые будет использоваться нашей программой. Переменные - это в основном контейнеры для значений (например, числа или строки текста). Вы создаете переменную с ключевым словом var, за которой следует имя для вашей переменной. Затем вы можете присвоить значение своей переменной знак равенства (=), за которым следует значение, которое вы хотите дать.</p> + +<p>В нашем примере:</p> + +<ul> + <li>Первой переменной - randomNumber - присваивается случайное число от 1 до 100, вычисленное с использованием математического алгоритма.</li> + <li>Следующие три переменные сделаны для хранения ссылок на абзацы результатов в нашем HTML и используются для вставки значений в абзацы, приведенные далее в коде: + <pre class="brush: html notranslate"><p class="guesses"></p> +<p class="lastResult"></p> +<p class="lowOrHi"></p></pre> + </li> + <li>Следующие две переменных хранят ссылки на форму ввода текста и кнопку отправки а позже используются для управления подачи догадки . + <pre class="brush: html notranslate"><label for="guessField">Enter a guess: </label><input type="text" id="guessField" class="guessField"> +<input type="submit" value="Submit guess" class="guessSubmit"></pre> + </li> + <li>Наши последние две переменные сохраняют количество догадок 1 (используется для отслеживания того, сколько догадок у игрока было), и ссылку на кнопку сброса, которая еще не существует (но позже).</li> +</ul> + +<div class="note"> +<p><strong>Заметка</strong>:<strong> </strong>В дальнейшем вы узнаете намного больше о переменных, в следующей статье.</p> +</div> + +<h3 id="Функции_Functions">Функции (Functions)</h3> + +<p>Затем добавьте следующие ниже предыдущего JavaScript:</p> + +<pre class="brush: js notranslate">function checkGuess() { + alert('I am a placeholder'); +}</pre> + +<p>Функции представляют собой многократно используемые блоки кода, написав один раз вы можете запускать их снова и снова, сохраняя нужный постоянно повторяющийся код. Это действительно полезно. Существует несколько способов определить функцию, но пока мы сосредоточимся на одном простом варианте. Здесь мы определили функцию используя ключевое слово <code>function</code>, за ним идет имя с двумя скобками после него. После этого мы добавляем две фигурные скобки (<code>{ }</code>). Внутри фигурных скобок содержится весь код, запускающийся всякий раз, когда вызываем функцию.</p> + +<p>Код запускается вводом имени функции, за которым следуют две скобки.</p> + +<p>Сейчас попробуйте сохранить код и обновить его в браузере.</p> + +<p>Перейдите к <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">консоли JavaScript в инструментах разработчика</a>, и введите следующую строку:</p> + +<pre class="brush: js notranslate">checkGuess();</pre> + +<p>Вы должны увидеть предупреждение, в котором говорится "I am a placeholder"; в нашем коде мы определили функцию, которая создает предупреждение, когда ее вызывают.</p> + +<div class="note"> +<p><strong>Заметка</strong>: В дальнейшем вы намного больше узнаете о функциях.</p> +</div> + +<h3 id="Операторы_Operators">Операторы (Operators)</h3> + +<p>Операторы JavaScript позволяют нам проводить проверки, математические рассчеты, объединять строки вместе и выполнять другие подобные действия.</p> + +<p>Сохраните наш код и обновите страницу показанную в браузере. Откройте <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">консоль JavaScript</a>, если вы еще её не открыли, чтобы попробовать ввести текст из приведенных ниже примеров — введите каждую строчку из столбца "Пример", нажимая Enter после каждого из них, и посмотрите какие результаты они возвращают. Если у вас нет доступа к инструментам разработчика в браузере, вы всегда можете использовать простую встроенную консоль, показанную ниже:</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + + function createInput() { + var inputDiv = document.createElement('div'); + var inputParas = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputParas.textContent = '>'; + inputDiv.appendChild(inputParas); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + inputDiv.focus(); + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputParas = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputParas.textContent = 'Result: ' + result; + outputDiv.appendChild(outputParas); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<p>Сначала давайте посмотрим на арифметические операторы, например:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Оператор</th> + <th scope="col">Имя</th> + <th scope="col">Пример</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>+</code></td> + <td>Сложение</td> + <td><code>6 + 9</code></td> + </tr> + <tr> + <td><code>-</code></td> + <td>Вычитание</td> + <td><code>20 - 15</code></td> + </tr> + <tr> + <td><code>*</code></td> + <td>Умножение</td> + <td><code>3 * 7</code></td> + </tr> + <tr> + <td><code>/</code></td> + <td>Деление</td> + <td><code>10 / 5</code></td> + </tr> + </tbody> +</table> + +<p>Вы также можете использовать оператор <code>+</code> для сложения строк текста (в программировании это называется конкатенацией). Попробуйте ввести следующие строки:</p> + +<pre class="brush: js notranslate">var name = 'Bingo'; +name; +var hello = ' says hello!'; +hello; +var greeting = name + hello; +greeting;</pre> + +<p>Также есть сокращенные операторы, называемые расширенными операторами присваивания. Например, если вы просто хотите добавить новую строку к существующей и вернуть результат, вы можете сделать так:</p> + +<pre class="brush: js notranslate">name += ' says hello!';</pre> + +<p>Это эквивалентно этому:</p> + +<pre class="brush: js notranslate">name = name + ' says hello!';</pre> + +<p>Когда мы запускаем проверку true/false (истина/ложь) (например, внутри условных выражений — смотри {{anch("Conditionals", "ниже")}}), мы используем операторы сравнения, например:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Оператор</th> + <th scope="col">Имя</th> + <th scope="col">Пример</th> + </tr> + <tr> + <td><code>===</code></td> + <td>Строгое равенство (это точно одно и то же?)</td> + <td><code>5 === 2 + 4</code></td> + </tr> + <tr> + <td><code>!==</code></td> + <td>Строгое неравенство (это не одно и то же?)</td> + <td><code>'Chris' !== 'Ch' + 'ris'</code></td> + </tr> + <tr> + <td><code><</code></td> + <td>Меньше чем</td> + <td><code>10 < 6</code></td> + </tr> + <tr> + <td><code>></code></td> + <td>Больше чем</td> + <td><code>10 > 20</code></td> + </tr> + </thead> +</table> + +<h3 id="Условные_выражения_Conditionals">Условные выражения (Conditionals)</h3> + +<p>Вернемся к нашей функции <code>checkGuess()</code>, я думаю, можно с уверенностью сказать, что мы не хотим, чтобы она просто выводила сообщение заполнитель. Мы хотим, чтобы она проверяла сделал игрок правильный выбор или нет, и соответсвующе реагировала.</p> + +<p>Теперь, заменим вашу текущую функцию<code>checkGuess()</code> на эту версию:</p> + +<pre class="brush: js notranslate">function checkGuess() { + var userGuess = Number(guessField.value); + if (guessCount === 1) { + guesses.textContent = 'Previous guesses: '; + } + guesses.textContent += userGuess + ' '; + + if (userGuess === randomNumber) { + lastResult.textContent = 'Congratulations! You got it right!'; + lastResult.style.backgroundColor = 'green'; + lowOrHi.textContent = ''; + setGameOver(); + } else if (guessCount === 10) { + lastResult.textContent = '!!!GAME OVER!!!'; + setGameOver(); + } else { + lastResult.textContent = 'Wrong!'; + lastResult.style.backgroundColor = 'red'; + if(userGuess < randomNumber) { + lowOrHi.textContent = 'Last guess was too low!'; + } else if(userGuess > randomNumber) { + lowOrHi.textContent = 'Last guess was too high!'; + } + } + + guessCount++; + guessField.value = ''; + guessField.focus(); +}</pre> + +<p>Как много кода — фу! Давайте отдельно рассмотрим каждый раздел и объясним, что он делает.</p> + +<ul> + <li>Первая строка (строка под номером 2 в коде выше) объявляет переменную с именем <code>userGuess</code> и устанавливает ее значение на то, что сейчас введено в текстовое поле. Мы также пропускаем это значение через встроенный метод <code>Number()</code>, чтобы убедится, что значение точно является числом.</li> + <li>Затем мы сталкиваемся с нашим первым блоком условного кода (строки 3–5 в коде выше). Блок условного кода позволяет выборочно запускать код в зависимости от того, является определенное условие истинным или нет. Он немного похож на функцию, но это не так. Простейшая форма условного блока начинается с ключевого слова <code>if</code>, за ним круглые скобки, за ними еще фигурные скобки. В круглые скобки мы добавляем проверку. Если проверка возвращает <code>true</code>, запускается код в фигурных скобках. Если нет, этот код пропускается и мы переходим к следующей части кода. В этом случае проверяется равна ли переменая <code>guessCount</code> числу <code>1</code> (то есть является ли это первой попыткой игрока или нет): + <pre class="brush: js notranslate">guessCount === 1</pre> + Если это так, мы выводим параграф с содержанием "Previous guesses: ". Если нет, ничего не делаем.</li> + <li>Строка 6 добавяет текущее знаение <code>userGuess</code> в конец параграфа <code>guesses</code>, плюс пустое пространство поэтому между каждыми показанными предположениями будет пробел.</li> + <li>Следующий блок (строки 8–24 ) делает несколько проверок: + <ul> + <li><code><font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">Первая конструкция </span></font>if(){ }</code> проверяет, совпадает ли предположение пользователя с <code>randomNumber</code> установленному в верхней части нашего JavaScript. Если это так, игрок правильно догадался, и игра выиграна, поэтому мы показываем игроку поздравительное сообщение с приятным зеленым цветом, очищаем содержимое окна информации о минимуме / максимуме и запускаем функцию, называемую setGameOver (), которую мы обсудим позже.</li> + <li>Теперь мы добавили еще одну проверку после пердыдущей, используя конструкцию else if () {}. Эта конструкция проверяет, является ли этот ход последним ходом пользователя. Если это так, программа выполняет то же самое, что и в предыдущем блоке, но выведет сообщение с текстом GAME OVER.</li> + <li>Последний блок, в конце нашего кода (else {}), содержит код, который запускается только в том случае, если ни один из двух других тестов не возвращает true (т. е. Игрок не догадался правильно, но у него еще остались догадки). В этом случае мы говорим игроку, что он ошибся, затем мы выполняем еще один условный тест, чтобы проверить, было ли предположение больше или меньше ответа, показывая дополнительное сообщение.</li> + </ul> + </li> + <li>Последние три строки в функции (строки 26–28 ) готовят нас к следующей попытке. Мы добавляем 1 к переменной <code>guessCount</code> так как игрок использовал свой ход (<code>++</code> оператор инкремента — увеличивает на 1), очищаем значение текстового поля и фокусируемся на нем снова, готовы для ввода следующего ответа.</li> +</ul> + +<h3 id="События_Events">События (Events)</h3> + +<p><span id="result_box" lang="ru"><span>На данный момент у нас есть хорошо реализованная функция <code>checkGuess()</code>, но она ничего не сделает, потому что мы еще не вызвали ее.</span> <span>В идеале мы хотим вызывать её во время нажатия кнопки «</span></span> Submit guess <span lang="ru"><span>», и для этого нам нужно использовать событие.</span> <span>События - это действия, которые происходят в браузере, например, нажатие кнопки или загрузка страницы или воспроизведение видео, в ответ на которые мы можем запускать блоки кода.</span> <span>Конструкции, которые прослушивают событие, называются <strong>прослушивателями событий</strong>, а блоки кода, выполняемые в ответ на срабатывание событий, называются <strong>обработчиками событий</strong>.</span></span></p> + +<p><span id="result_box" lang="ru"><span>Добавьте следующую строку ниже закрывающей фигурной скобки функции <code>checkGuess()</code>:</span></span></p> + +<pre class="brush: js notranslate">guessSubmit.addEventListener('click', checkGuess);</pre> + +<p><span id="result_box" lang="ru"><span>Здесь мы добавляем прослушиватель событий к кнопке <code>guessSubmit</code>.</span> <span>Это метод, который принимает два входных значения (называемые аргументами) - тип события, которое мы выслушиваем (в данном случае <code>click</code>) в виде строки, и код, который мы хотим запустить при возникновении события (в данном случае</span> <span>функция <code>checkGuess()</code> - обратите внимание, что нам не нужно указывать круглые скобки при записи внутри</span></span> {{domxref("EventTarget.addEventListener", "addEventListener()")}}).</p> + +<p><span id="result_box" lang="ru"><span>Попробуйте сохранить и обновить код сейчас, и ваш пример должен теперь работать, но до определенного момента.</span> <span>Единственная проблема в том, что если вы угадаете правильный ответ или исчерпаете догадки, игра сломается, потому что мы еще не определили функцию <code>setGameOver()</code>, которая должна запускаться после завершения игры.</span> <span>Давайте добавим наш недостающий код и завершим пример функциональности.</span></span></p> + +<h3 id="Завершение_игры">Завершение игры</h3> + +<p><span id="result_box" lang="ru"><span>Давайте добавим функцию <code>setGameOver()</code> в конец нашего кода, а затем пройдем по ней.</span> <span>Добавьте это под нижней частью вашего JavaScript:</span></span></p> + +<pre class="brush: js notranslate">function setGameOver() { + guessField.disabled = true; + guessSubmit.disabled = true; + resetButton = document.createElement('button'); + resetButton.textContent = 'Start new game'; + document.body.appendChild(resetButton); + resetButton.addEventListener('click', resetGame); +}</pre> + +<ul> + <li><span id="result_box" lang="ru"><span>Первые две строки отключают ввод текста и кнопку формы, устанавливая их отключенные свойства как <code>true</code>.</span> <span>Это необходимо, потому что, если бы мы этого не сделали, пользователь мог бы представить больше догадок после завершения игры, что испортит ситуацию.</span></span></li> + <li><span id="result_box" lang="ru"><span>Следующие три строки генерируют новый элемент {{htmlelement("button")}}, устанавливают его текстовую метку «</span></span> Start new game<span lang="ru"><span>» и добавляют ее к нижней части нашего HTML.</span></span></li> + <li><span id="result_box" lang="ru"><span>Последняя строка устанавливает прослушиватель событий на нашей новой кнопке, так что при нажатии на нее запускается функция <code>resetGame()</code>.</span></span></li> +</ul> + +<p><span id="result_box" lang="ru"><span>Теперь нам нужно также определить эту функцию!</span> <span>Добавьте следующий код, снова в нижнюю часть вашего JavaScript:</span></span></p> + +<pre class="brush: js notranslate">function resetGame() { + guessCount = 1; + + var resetParas = document.querySelectorAll('.resultParas p'); + for (var i = 0 ; i < resetParas.length ; i++) { + resetParas[i].textContent = ''; + } + + resetButton.parentNode.removeChild(resetButton); + + guessField.disabled = false; + guessSubmit.disabled = false; + guessField.value = ''; + guessField.focus(); + + lastResult.style.backgroundColor = 'white'; + + randomNumber = Math.floor(Math.random() * 100) + 1; +}</pre> + +<p><span id="result_box" lang="ru"><span>Этот довольно длинный блок кода полностью сбрасывает все на то, как это было в начале игры, поэтому у игрока может быть еще один ход.</span> <span>Это:</span></span></p> + +<ul> + <li>Устанавливает значение <code>guessCount</code> на 1.</li> + <li><span class="short_text" id="result_box" lang="ru"><span>Удаляет все пункты информации</span></span>.</li> + <li><span class="short_text" id="result_box" lang="ru"><span>Удаляет кнопку сброса из нашего кода.</span></span></li> + <li>Включает элементы формы, устанавливает фокус, делает поле доступным для следующих угадываний.</li> + <li><span class="short_text" id="result_box" lang="ru"><span>Удаляет цвет фона из абзаца <code>lastResult</code>.</span></span></li> + <li><span id="result_box" lang="ru"><span>Создает новое случайное число, чтобы вы не угадывали одно и тоже!</span></span></li> +</ul> + +<p><strong><span id="result_box" lang="ru"><span>С этого момента у вас есть </span></span><span id="result_box" lang="ru"><span>полностью работающая (простая) игра - поздравляем!</span></span></strong> <span lang="ru"><span> </span></span></p> + +<p><span id="result_box" lang="ru"><span>Все, что нам осталось сделать в этой статье, - это поговорить о нескольких других важных функциях кода, которые вы уже видели, хотя вы, возможно, этого не осознали.</span></span></p> + +<h3 id="Циклы_Loops">Циклы (Loops) </h3> + +<div class="_Ejb"> +<div id="tw-target"> +<div class="tw-nfl tw-compact-ta-container" id="tw-target-text-container">Одна часть вышеприведенного кода, которую мы должны рассмотреть более подробно, - это цикл for. Циклы - очень важная концепция программирования, которая позволяет вам снова и снова запускать кусок кода, пока не будет выполнено определенное условие.</div> + +<div class="tw-nfl tw-compact-ta-container">Для начала перейдите в панель инструментов разработчика JavaScript-консоли и введите следующее:</div> +</div> +</div> + +<pre class="brush: js notranslate">for (var i = 1 ; i < 21 ; i++) { console.log(i) }</pre> + +<p><span lang="ru">Что случилось? Номера с 1 по 20 были напечатаны в консоли. Это из-за цикла. Цикл for принимает три входных значения (аргументы):</span><br> + <span lang="ru">Начальное значение: в этом случае мы начинаем подсчет c 1, но это может быть любое число которое вам нравится. Вы можете заменить i любым другим именем, которое вам нравится, но я использую его как условность, потому что оно короткое и легко запоминается. Условие выхода: Здесь мы указали i <21 - цикл будет продолжаться до тех пор, пока i будет меньше 21. Когда i достигнет 21, цикл больше не будет работать. Инкремент: мы указали i ++, что означает «увеличить i на 1». Цикл будет выполняться один раз для каждого значения i, пока оно не достигнет значения 21 (как обсуждалось выше). В этом случае мы просто печатаем значение i в консоли на каждой итерации с помощью {{domxref ("Console.log", "console.log ()")}}.</span></p> + +<p><span lang="ru">Теперь давайте посмотрим на цикл в нашей игре угадывания чисел - в функции resetGame () можно найти следующее:</span></p> + +<pre class="brush: js notranslate">var resetParas = document.querySelectorAll('.resultParas p'); +for (var i = 0 ; i < resetParas.length ; i++) { + resetParas[i].textContent = ''; +}</pre> + +<p><span lang="ru">Этот код создает переменную, содержащую список всех абзацев внутри <div class = "resultParas">, используя метод {{domxref ("Document.querySelectorAll", "querySelectorAll ()")}}, затем он проходит через каждый из них, удаляя текстовое содержимое каждого из них.</span></p> + +<h3 id="Немного_об_объектах_Objects">Немного об объектах (Objects)</h3> + +<p>Давайте добавим еще одно окончательное улучшение, прежде чем перейти к обсуждению. Добавьте следующую строку чуть ниже <code>var resetButton;</code> в верхней части вашего JavaScript, затем сохраните файл:</p> + +<pre class="brush: js notranslate">guessField.focus();</pre> + +<p>Эта строка использует метод {{domxref("HTMLElement.focus", "focus()")}}, чтобы автоматически помещать текстовый курсор в текстовое поле {{htmlelement("input")}}, как только загрузится страница. Пользователь сможет сразу набрать свою первую догадку, не нажимая поле формы. Это всего лишь небольшое дополнение, но оно улучшает удобство использования - дает пользователю хорошую визуальную подсказку относительно того, что они должны делать в игре.</p> + +<p>Давайте проанализируем, что произошло. В JavaScript все элементы являются объектами. Объект - это набор связанных функций, хранящихся в одной группе<em>. </em>Вы можете создавать собственные объекты, но это требует мастерства, и мы не хотели бы раскрывать эту тему в рамках данного курса. Будет достаточно обсудить встроенные объекты вашего браузера, которые позволяют реализовывать множество полезных вещей.</p> + +<p>В нашем примере мы сначала создали переменную <code>guessField</code>, которая запоминает значение из поля ввода в нашем HTML - следующая строка находится среди первых в нашем коде:</p> + +<pre class="brush: js notranslate">var guessField = document.querySelector('.guessField');</pre> + +<p>Чтобы получить это значение, мы использовали метод {{domxref("document.querySelector", "querySelector()")}} объекта {{domxref("document")}}. <code>querySelector()</code> "берет" одну часть информации - <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors">CSS selector</a>, который выбирает нужный элемент<em>.</em></p> + +<p>Поскольку <code>guessField</code> теперь содержит ссылку на элемент {{htmlelement("input")}}, теперь он будет иметь доступ к ряду свойств (в основном к переменным, хранящимся внутри объектов, некоторые значения которых нельзя изменять) и методы (в основном функции, хранящиеся внутри объектов). Одним из методов, доступных для ввода элементов, является focus (), поэтому мы можем теперь использовать эту строку для фокусировки ввода текста:</p> + +<pre class="brush: js notranslate">guessField.focus();</pre> + +<p>Для переменных, которые не содержат ссылок на элементы формы, не будет доступен <code>focus()</code>. Например, переменная <code>guesses</code> содержит ссылку на элемент {{htmlelement ("p")}}, а <code>guessCount</code> содержит число.</p> + +<h3 id="Поиграем_с_объектами_браузера">Поиграем с объектами браузера</h3> + +<p>Давайте немного поиграем с некоторыми объектами браузера.</p> + +<ol> + <li>Для начала запустите свою программу в браузере.</li> + <li>Далее, откройте <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">инструменты разработчика в вашем браузере</a>, и убедитесь, что вы перешли во вкладку с консолью JavaScript.</li> + <li>Введите <code>guessField</code> и консоль покажет, что переменная содержит элемент {{htmlelement("input")}}. Вы также можете заметить, что консоль автоматически заполняет имена объектов, которые существуют внутри исполняющей среды, включая ваши переменные!</li> + <li>Теперь введите следующее: + <pre class="brush: js notranslate">guessField.value = 'Hello';</pre> + Свойство <code>value</code> представляет текущее значение, введенное в текстовое поле. Заметьте, что, введя эту команду, мы изменили его!</li> + <li>Попробуйте ввести <code>guesses</code> и нажать return. Консоль покажет, что в переменной содержится элемент {{htmlelement("p")}}.</li> + <li>Теперь попробуйте ввести: + <pre class="brush: js notranslate">guesses.value</pre> + Браузер вернет вам <code>undefined</code>, потому что <code>value</code> не существует в параграфах.</li> + <li>Для изменения текста внутри параграфа, взамен используйте свойство {{domxref("Node.textContent", "textContent")}}. Попробуйте: + <pre class="brush: js notranslate">guesses.textContent = 'Where is my paragraph?';</pre> + </li> + <li>Теперь немного повеселимся. Попробуйте ввести следующие строки, одну за другой: + <pre class="brush: js notranslate">guesses.style.backgroundColor = 'yellow'; +guesses.style.fontSize = '200%'; +guesses.style.padding = '10px'; +guesses.style.boxShadow = '3px 3px 6px black';</pre> + Каждый элемент на странице имеет свойство <code>style</code>, которое само по себе содержит объект, свойства которого содержат все встроенные стили CSS, применяемые к этому элементу. Это позволяет нам динамически задавать новые стили CSS для элементов с помощью JavaScript.</li> +</ol> + +<h2 id="Теперь_можно_отдохнуть...">Теперь можно отдохнуть...</h2> + +<p>Итак, на этом пример закончился - отлично, вы добрались до конца! Попробуйте свой финальный код или <a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game.html">поиграйте с нашей готовой версией здесь</a>. Если вы не можете запустить этот пример, сверьтесь с <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">исходным кодом.</a></p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/What_is_JavaScript", "Learn/JavaScript/Первые_шаги/Что_пошло_не_так", "Learn/JavaScript/Первые_шаги")}}</p> diff --git a/files/ru/learn/javascript/первые_шаги/arrays/index.html b/files/ru/learn/javascript/первые_шаги/arrays/index.html new file mode 100644 index 0000000000..7f38ce4a50 --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/arrays/index.html @@ -0,0 +1,678 @@ +--- +title: Массивы +slug: Learn/JavaScript/Первые_шаги/Arrays +tags: + - JavaScript + - Pop + - Push + - shift + - unshift + - Для начинающих + - Массивы + - Статья +translation_of: Learn/JavaScript/First_steps/Arrays +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Useful_string_methods", "Learn/JavaScript/Первые_шаги/Создатель_глуых_историй", "Learn/JavaScript/Первые_шаги")}}</div> + +<p class="summary">В финальной статье этого раздела, мы познакомимся с массивами — лаконичным способом хранения списка элементов под одним именем. Мы поймем, чем они полезны, затем узнаем, как создать массив, получить, добавить и удалить элементы, хранящиеся в массиве.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS, понимание о том, что такое JavaScript.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять, что такое массивы и как использовать их в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_массив">Что такое массив?</h2> + +<p>Массивы обычно описываются как «объекты, подобные спискам»; они представляют собой в основном отдельные объекты, которые содержат несколько значений, хранящихся в списке. Объекты массива могут храниться в переменных и обрабатываться во многом так же, как и любой другой тип значения, причем разница заключается в том, что мы можем получить доступ к каждому значению внутри списка отдельно и делать супер полезные и эффективные вещи со списком, а также делать то же самое для каждого из значений. Представим, что у нас есть список продуктов и их цены, хранящиеся в массиве, и мы хотим их просмотреть и распечатать на счете-фактуре, общая сумма всех цен и распечатка общей цены внизу.</p> + +<p>Если бы у нас не было массивов, мы должны были бы хранить каждый элемент в отдельной переменной, а затем вызывать код, выполняющий печать и добавляющий отдельно каждый элемент. Написание такого кода займет намного больше времени, сам код будет менее эффективным и подверженным ошибкам. Если бы у нас было 10 элементов для добавления в счет-фактуру, это еще куда ни шло, но как насчет 100 предметов? Или 1000? Мы вернемся к этому примеру позже в статье.</p> + +<p><span id="result_box" lang="ru"><span>Как и в предыдущих статьях, давайте узнаем о реальных основах массивов, введя некоторые примеры в консоль JavaScript.</span> <span>Мы предоставили один ниже (вы также можете</span></span> <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">open this console</a> в отдельном окне, или использовать <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">browser developer console</a>, если вам угодно).</p> + +<div class="hidden"> +<h6 id="Спрятанный_код">Спрятанный код</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + if(document.querySelectorAll('div').length > 1) { + inputForm.focus(); + } + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<h3 id="Создание_массива">Создание массива</h3> + +<p>Массивы создаются из квадратных скобок , которые содержат список элементов, разделённых запятыми.</p> + +<ol> + <li>Допустим, мы бы хотели хранить список покупок в массиве — мы бы сделали что-то вроде этого. Введите следующие строчки в вашу консоль: + <pre class="brush: js">var shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles']; +shopping;</pre> + </li> + <li>В данном случае, каждый элемент в массиве — это строка , но имейте в виду, что вы можете хранить любой элемент в массиве — строку, число, объект, другую переменную, даже другой массив. Вы также можете перемешивать типы элементов — они не должны все быть числами, строками, и так далее. Попробуйте это: + <pre class="brush: js">var sequence = [1, 1, 2, 3, 5, 8, 13]; +var random = ['tree', 795, [0, 1, 2]];</pre> + </li> + <li>Попробуйте сами создать несколько массивов, перед тем как двигаться дальше.</li> +</ol> + +<h3 id="Получение_и_изменение_элементов_массива">Получение и изменение элементов массива</h3> + +<p>Вы можете после этого получать доступ к отдельным элементам в массиве, используя квадратные скобки, таким же способом каким вы <a href="/en-US/Learn/JavaScript/First_steps/Useful_string_methods#Retrieving_a_specific_string_character">получаете доступ к буквам в строке</a>.</p> + +<ol> + <li>Введите следующее в вашу консоль: + <pre class="brush: js">shopping[0]; +// возвращает "bread"</pre> + </li> + <li>Вы также можете изменять элемент в массиве, просто дав отдельному элементу массива новое значение. Попробуйте это: + <pre class="brush: js">shopping[0] = 'tahini'; +shopping; +// shopping теперь возвратит [ "tahini", "milk", "cheese", "hummus", "noodles" ]</pre> + + <div class="note"><strong>Заметка</strong>: Мы уже упоминали это прежде, но просто как напоминание — компьютеры начинают считать с нуля!</div> + </li> + <li>Заметьте, что массив внутри массива называется многомерным массивом. <span id="result_box" lang="ru"><span>Вы можете получить доступ к элементу внутри массива, который сам находится внутри другого массива, объединив два набора квадратных скобок.</span> <span>Например, для доступа к одному из элементов внутри массива, который является третьим элементом внутри массива <code>random </code>(см. предыдущую секцию данной статьи), мы могли бы сделать что-то вроде этого:</span></span> + <pre class="brush: js">random[2][2];</pre> + </li> + <li>Попробуйте внести некоторые дополнительные изменения в свои примеры массивов, прежде чем двигаться дальше.</li> +</ol> + +<h3 id="Нахождение_длины_массива">Нахождение длины массива</h3> + +<p>Вы можете найти длину массива (количество элементов в нём) точно таким же способом, как вы находите длину строки (в символах) — используя свойство {{jsxref("Array.prototype.length","length")}}. Попробуйте следующее:</p> + +<pre class="brush: js">sequence.length; +// должно возвратить 7</pre> + +<p>Это свойство имеет и другие применения, но чаще всего используется, чтобы сказать, что цикл продолжается, пока он не зациклится на всех элементах массива. Так, например:</p> + +<pre class="brush: js">var sequence = [1, 1, 2, 3, 5, 8, 13]; +for (var i = 0; i < sequence.length; i++) { + console.log(sequence[i]); +}</pre> + +<p><span id="result_box" lang="ru"><span>В будущих статьях вы узнаете о циклах, но вкратце этот код говорит:</span></span></p> + +<ol> + <li><span class="short_text" id="result_box" lang="ru"><span>Начать цикл с номера позиции 0 в массиве.</span></span></li> + <li>Остановить цикл на номере элемента, равном длине массива. Это будет работать для массива любой длины, но в этом случае он остановит цикл на элементе номер 7 (это хорошо, поскольку последний элемент, который мы хотим, чтобы цикл был закрыт, равен 6).</li> + <li><span id="result_box" lang="ru"><span>Для каждого элемента вернуть его значение в консоли браузера с помощью</span></span> <code><a href="/en-US/docs/Web/API/Console/log">console.log()</a></code>.</li> +</ol> + +<h2 id="Некоторые_полезные_методы_массивов">Некоторые полезные методы массивов</h2> + +<p><span id="result_box" lang="ru"><span>В этом разделе мы рассмотрим некоторые полезные методы, связанные с массивом, которые позволяют нам разбивать строки на элементы массива и наоборот, а также добавлять новые элементы в массивы.</span></span></p> + +<h3 id="Преобразование_между_строками_и_массивами"><span class="short_text" id="result_box" lang="ru"><span>Преобразование между строками и массивами</span></span></h3> + +<p>Часто у Вас могут быть некоторые необработанные данные, содержащиеся в большой длинной строке, и вы можете захотеть разделить полезные пункты до более удобной и полезной формы, а затем сделать что-то для них, например отобразить их в таблице данных. Для этого мы можем использовать метод {{jsxref ("String.prototype.split ()", "split ()")}}. В его простейшей форме он принимает единственный параметр, символ, который вы хотите отделить в строке, и возвращает подстроки между разделителем как элементы в массиве.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Хорошо, технически это строковый метод, не метод массива, <span id="result_box" lang="ru"><span>но мы поместили его в массивы, так как он хорошо подходит для них.</span></span></p> +</div> + +<ol> + <li>Поиграем с этим, посмотрим как это работает. Сначала, создадим строку в вашей консоли: + <pre class="brush: js">var myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';</pre> + </li> + <li>Теперь разделим ee посредством запятой: + <pre class="brush: js">var myArray = myData.split(','); +myArray;</pre> + </li> + <li>Наконец, попробуйте найти длину вашего нового массива и извлечь из него некоторые элементы: + <pre class="brush: js">myArray.length; +myArray[0]; // первый элемент в массиве +myArray[1]; // второй элемент в массиве +myArray[myArray.length-1]; // последний элемент в массиве</pre> + </li> + <li>Вы можете сделать обратное используя метод{{jsxref("Array.prototype.join()","join()")}} . Попробуйте следующее: + <pre class="brush: js">var myNewString = myArray.join(','); +myNewString;</pre> + </li> + <li> Другой способ преобразования массива в строку - использовать метод {{jsxref("Array.prototype.toString()","toString()")}} . <code>toString() ,</code>возможно, проще,чем <code>join()</code> поскольку он не принимает параметр, но это ограничивает его. С <code>join()</code>вы можете указать разные разделители (попробуйте выполнить шаг 4 с другим символом, кроме запятой). + <pre class="brush: js">var dogNames = ["Rocket","Flash","Bella","Slugger"]; +dogNames.toString(); //Rocket,Flash,Bella,Slugger</pre> + </li> +</ol> + +<h3 id="Добавление_и_удаление_элементов_массива">Добавление и удаление элементов массива</h3> + +<p>Мы еще не рассмотрели добавление и удаление элементов массива - давайте посмотрим на это сейчас. Мы будем использовать массив <code>myArray</code> , с которым мы столкнулись в предыдущем разделе. Если вы еще не прошли этот раздел, сначала создайте массив в консоли:</p> + +<pre class="brush: js">var myArray = ['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle'];</pre> + +<p>Прежде всего, чтобы добавить или удалить элемент с конца массива, мы можем использовать {{jsxref("Array.prototype.push()","push()")}} и {{jsxref("Array.prototype.pop()","pop()")}} соответственно.</p> + +<ol> + <li>Давайте сначала используем метод <code>push()</code> — заметьте, что вам нужно указать один или более элементов, которые вы хотите добавить в конец своего массива. Попробуйте это: + + <pre class="brush: js">myArray.push('Cardiff'); +myArray; +myArray.push('Bradford', 'Brighton'); +myArray; +</pre> + </li> + <li>При завершении вызова метода возвращается новая длина массива. Если бы вы хотели сохранить новую длину массива в переменной, вы бы могли сделать что-то вроде этого: + <pre class="brush: js">var newLength = myArray.push('Bristol'); +myArray; +newLength;</pre> + </li> + <li>Удаление последнего элемента массива можно совершить с помощью вызова метода <code>pop()</code>. Попробуйте это: + <pre class="brush: js">myArray.pop();</pre> + </li> + <li>Когда вызов метода завершается, возвращается удалённый элемент. Вы бы могли также сделать такое: + <pre class="brush: js">var removedItem = myArray.pop(); +myArray; +removedItem;</pre> + </li> +</ol> + +<p>{{jsxref("Array.prototype.unshift()","unshift()")}} и {{jsxref("Array.prototype.shift()","shift()")}} работают точно таким же способом, за исключением того что они работают в начале массива, а не в конце.</p> + +<ol> + <li>Сначала, попробуем метод <code>unshift()</code>: + + <pre class="brush: js">myArray.unshift('Edinburgh'); +myArray;</pre> + </li> + <li>Теперь <code>shift()</code>; попробуйте эти! + <pre class="brush: js">var removedItem = myArray.shift(); +myArray; +removedItem;</pre> + </li> +</ol> + +<h2 id="Практика_Печать_продуктов!">Практика: Печать продуктов!</h2> + +<p>Вернемся к описанному выше примеру - распечатываем названия продуктов и цен на счет-фактуру, затем суммируем цены и печатаем их внизу. В приведенном ниже редактируемом примере есть комментарии, содержащие числа - каждая из этих отметок является местом, где вы должны добавить что-то в код. Они заключаются в следующем:</p> + +<ol> + <li>Ниже комментария <code>// number 1</code> имеется ряд строк, каждая из которых содержит название продукта и цену, разделенные двоеточием. Нужно превратить их в массив и сохранить его под названием <code>products</code>.</li> + <li>На строке с комментарием <code>// number 2</code> начинается цикл for. В строке цикла имеется<code> i <= 0</code>, что является условием , которое заставляет цикл for выполняться только один раз, так как это значение i сообщает циклу: «останавливаться, когда <code>i</code> меньше или равен 0», при этом <code>i</code> начинается с 0. Нужно заменить <code>i <= 0</code> условным тестом, который останавливает цикл, когда <code>i</code> перестает быть меньше длины массива <code>products</code> .</li> + <li>Под комментарием <code>// number 3</code> мы хотим, чтобы вы написали строку кода, которая разбивает текущий элемент массива (<code>name:price</code>) на два отдельных элемента: один содержит только имя, а другой - содержащее только цену. Если не знаете, как это сделать, еще раз просмотрите статью <a href="/ru/docs/Learn/JavaScript/Первые_шаги/Useful_string_methods">Полезные строковые методы</a>, а лучше, посмотрите раздел {{anch("Преобразование между строками и массивами")}} этой статьи.</li> + <li>В рамках приведенной выше строки нужно преобразовать цену из строки в число. Если не помните, как это сделать, ознакомьтесь со статьей <a href="/ru/docs/Learn/JavaScript/Первые_шаги/Строки">строки в JavaScript</a>.</li> + <li>В верхней части кода есть переменная с именем <code>total</code> , которая содержит значение <code>0</code>. Внутри цикла (под комментарием <code>// number 4</code>) нужно добавить строку, которая добавляет текущую цену товара к этой сумме на каждой итерации цикла, так чтобы в конце кода была выведена корректная сумма в счет-фактуре. Для этого вам может понадобится <a href="/ru/docs/Learn/JavaScript/Первые_шаги/Math#Операторы_присваивания">оператор присваивания</a>.</li> + <li>Под комментарием <code>// number 5</code> нужно изменить строку так, чтобы переменная <code>itemText</code> была равна "current item name — $current item price", например "Shoes — $23.99" для каждого случая, чтобы корректная информация для каждого элемента была напечатана в счете-фактуре. Здесь обычная конкатенация строк, которая должна быть вам знакома.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html"><!-- Не выделяйте тут ничего, не копируйте, не всавляйте! + Еле починил --> + +<h2>Live output</h2> + +<div class="output" style="min-height: 150px;"> + +<ul> + +</ul> + +<p></p> + +</div> + +<h2>Editable code</h2> + +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="playable-code" style="height: 410px;width: 95%"> +var list = document.querySelector('.output ul'); +var totalBox = document.querySelector('.output p'); +var total = 0; +list.innerHTML = ''; +totalBox.textContent = ''; +// number 1 + 'Underpants:6.99' + 'Socks:5.99' + 'T-shirt:14.99' + 'Trousers:31.99' + 'Shoes:23.99'; + +for (var i = 0; i <= 0; i++) { // number 2 + // number 3 + + // number 4 + + // number 5 + itemText = 0; + + var listItem = document.createElement('li'); + listItem.textContent = itemText; + list.appendChild(listItem); +} + +totalBox.textContent = 'Total: $' + total.toFixed(2); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nvar totalBox = document.querySelector(\'.output p\');\nvar total = 0;\nlist.innerHTML = \'\';\ntotalBox.textContent = \'\';\n\nvar products = [\'Underpants:6.99\',\n \'Socks:5.99\',\n \'T-shirt:14.99\',\n \'Trousers:31.99\',\n \'Shoes:23.99\'];\n\nfor(var i = 0; i < products.length; i++) {\n var subArray = products[i].split(\':\');\n var name = subArray[0];\n var price = Number(subArray[1]);\n total += price;\n itemText = name + \' — $\' + price;\n\n var listItem = document.createElement(\'li\');\n listItem.textContent = itemText;\n list.appendChild(listItem);\n}\n\ntotalBox.textContent = \'Total: $\' + total.toFixed(2);'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> + +<pre class="brush: css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background-color: #f5f9fa; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 730, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Практика_Топ_5_поисовых_запросов">Практика: Топ 5 поисовых запросов</h2> + +<p>Хорошим тоном, является использование методов массива, таких как {{jsxref ("Array.prototype.push ()", "push ()")}} и {{jsxref ("Array.prototype.pop ()", "pop ()") }} - это когда вы ведете запись активных элементов в веб-приложении. Например, в анимированной сцене может быть массив объектов, представляющих текущую отображаемую фоновую графику и вам может потребоваться только 50 одновременных отображений по причинам производительности или беспорядка. Когда новые объекты создаются и добавляются в массив, более старые могут быть удалены из массива для поддержания нужного числа.</p> + +<p>В этом примере мы собираемся показать гораздо более простое использование - ниже мы даем вам поддельный поисковый сайт с полем поиска. Идея заключается в том, что когда в поле поиска вводятся запросы, в списке отображаются 5 предыдущих поисковых запросов. Когда число терминов превышает 5, последний член начинает удаляться каждый раз, когда новый член добавляется в начало, поэтому всегда отображаются 5 предыдущих терминов.</p> + +<div class="note"> +<p><strong>Примечание:</strong> В реальном приложении для поиска вы, вероятно, сможете щелкнуть предыдущие условия поиска, чтобы вернуться к предыдущим поисковым запросам и отобразите фактические результаты поиска! На данный момент мы просто сохраняем его.</p> +</div> + +<p>Чтобы завершить приложение, вам необходимо:</p> + +<ol> + <li>Добавьте строку под комментарием <code>// number 1</code>, которая добавляет текущее значение, введенное в ввод поиска, к началу массива. Его можно получить с помощью <code>searchInput.value</code>.</li> + <li>Добавьте строку под комментарием <code>// number 2</code>, которая удаляет значение, находящееся в конце массива.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html"><!-- Здесь тоже ничего не выделяйте, не копируйте, не всавляйте! + Еле починил --> + +<h2>Live output</h2> +<div class="output" style="min-height: 150px;"> + +<input type="text"><button>Search</button> + +<ul> + +</ul> + +</div> + +<h2>Editable code</h2> + +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + + +<textarea id="code" class="playable-code" style="height: 370px; width: 95%"> +var list = document.querySelector('.output ul'); +var searchInput = document.querySelector('.output input'); +var searchBtn = document.querySelector('.output button'); + +list.innerHTML = ''; + +var myHistory = []; + +searchBtn.onclick = function() { + // we will only allow a term to be entered if the search input isn't empty + if (searchInput.value !== '') { + // number 1 + + // empty the list so that we don't display duplicate entries + // the display is regenerated every time a search term is entered. + list.innerHTML = ''; + + // loop through the array, and display all the search terms in the list + for (var i = 0; i < myHistory.length; i++) { + itemText = myHistory[i]; + var listItem = document.createElement('li'); + listItem.textContent = itemText; + list.appendChild(listItem); + } + + // If the array length is 5 or more, remove the oldest search term + if (myHistory.length >= 5) { + // number 2 + + } + + // empty the search input and focus it, ready for the next term to be entered + searchInput.value = ''; + searchInput.focus(); + } +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div></pre> + +<pre class="brush: css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nvar searchInput = document.querySelector(\'.output input\');\nvar searchBtn = document.querySelector(\'.output button\');\n\nlist.innerHTML = \'\';\n\nvar myHistory= [];\n\nsearchBtn.onclick = function() {\n if(searchInput.value !== \'\') {\n myHistory.unshift(searchInput.value);\n\n list.innerHTML = \'\';\n\n for(var i = 0; i < myHistory.length; i++) {\n itemText = myHistory[i];\n var listItem = document.createElement(\'li\');\n listItem.textContent = itemText;\n list.appendChild(listItem);\n }\n\n if(myHistory.length >= 5) {\n myHistory.pop();\n }\n\n searchInput.value = \'\';\n searchInput.focus();\n }\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 700, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Прочитав эту статью, мы уверены, что вы согласитесь, что массивы кажутся довольно полезными; вы увидите, что они появляются повсюду в JavaScript, часто в сочетании с циклами, чтобы делать то же самое для каждого элемента массива. Мы научим вас всем полезным основам, которые нужно знать о циклах в следующем модуле, но пока вы должны себе похлопать и воспользоваться заслуженным перерывом; вы проработали все статьи в этом модуле!</p> + +<p>Осталось только выполнить тестовую задачу, которая проверит ваше понимание статей, которые Вы прочли до этого момента. Удачи!</p> + +<h2 id="Посмотрите_также">Посмотрите также</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Indexed_collections">Indexed collections</a> — an advanced level guide to arrays and their cousins, typed arrays.</li> + <li>{{jsxref("Array")}} — the <code>Array</code> object reference page — for a detailed reference guide to the features discussed in this page, and many more.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Useful_string_methods", "Learn/JavaScript/Первые_шаги/Создатель_глуых_историй", "Learn/JavaScript/Первые_шаги")}}</p> + +<h2 id="В_этом_разделе">В этом разделе</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">Что такое JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">A first splash into JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">Storing the information you need — Variables</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">Basic math in JavaScript — numbers and operators</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">Handling text — strings in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Массивы</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">Assessment: Silly story generator</a></li> +</ul> diff --git a/files/ru/learn/javascript/первые_шаги/index.html b/files/ru/learn/javascript/первые_шаги/index.html new file mode 100644 index 0000000000..bd435e920f --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/index.html @@ -0,0 +1,56 @@ +--- +title: Первые шаги в JavaScript +slug: Learn/JavaScript/Первые_шаги +tags: + - JavaScript + - Массивы + - Новичкам +translation_of: Learn/JavaScript/First_steps +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">В нашем первом модуле, прежде чем перейти к практике написания кода на языке JavaScript, сначала мы дадим ответы на некоторые фундаментальные вопросы, а именно: "Что же такое JavaScript?", "Что он из себя представляет?" и "Что он может делать?". После этого мы внимательно рассмотрим некоторые из ключевых элементов, такие как переменные, строки, числа и массивы.</p> + +<h2 id="Предисловие">Предисловие</h2> + +<p>Вам не нужно иметь никаких предварительных знаний JavaScript чтобы приступить к этому модулю, но у вас должно быть некоторое представление о HTML и CSS. Рекомендуем ознакомиться со следующими материалами, прежде чем начинать знакомство с JavaScript:</p> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web">Начало работы с Web</a> (которое включает в себя общее <a href="/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics">введение в Javascript</a>)</li> + <li><a href="/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML">Введение в HTML</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/CSS/Introduction_to_CSS">Введение в CSS</a></li> +</ul> + +<div class="note"> +<p><span style="font-size: 14px;"><strong>Примечание:</strong></span> Если Вы работаете на компьютере, планшете или другом устройстве, где нет возможности полноценно работать с файлами, можете использовать такие онлайн сервисы как <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>, для запуска примеров кода. </p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<dl> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/What_is_JavaScript">Что такое JavaScript?</a></dt> + <dd>Добро пожаловать на курс начинающего JavaScript разработчика от MDN! В первой статье мы рассмотрим JavaScript в общем приближении и постараемся ответить на вопросы "Что такое JavaScript?" и "Для чего он предназначен?", и закрепим верное понимание его назначения. </dd> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/A_first_splash">Первое погружение в JavaScript</a></dt> + <dd>Теперь, когда вы знаете кое-что о JavaScript, и что он может делать, мы предлагаем вам пройти интенсивный практический урок по базовой функциональности JavaScript. Здесь вы, шаг за шагом, создадите простую игру "Угадай число".</dd> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/%D0%A7%D1%82%D0%BE_%D0%BF%D0%BE%D1%88%D0%BB%D0%BE_%D0%BD%D0%B5_%D1%82%D0%B0%D0%BA">Что пошло не так? Устранение ошибок JavaScript</a></dt> + <dd>В процессе создания игры "Угадай число" из предыдущего урока, вы могли заметить что она не работала. Не стоит унывать - данная статья научит вас беречь собственные нервы, а так же, даст несколько советов о том как решать такие проблемы, искать и исправлять неполадки в JavaScript коде.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/Variables">Хранение нужной вам информации - Переменные</a></dt> + <dd>После прочтения предыдущих статей вы должны знать что из себя представляет JavaScript, что он может, как взаимодействует с другими web технологиями, и каковы его основные особенности в общем приближении. В этой статье спустимся к самым основам языка и поработаем с <strong>Переменными</strong>.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/Math">Базовая математика в JavaScript — числа и операторы</a></dt> + <dd>Здесь мы обсуждаем математику в JavaScript - каким образом мы можем манипулировать числами и операторами для работы с ними.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/%D0%A1%D1%82%D1%80%D0%BE%D0%BA%D0%B8">Работа с текстом — строки в JavaScript</a></dt> + <dd>Теперь мы обратим своё внимание на строки - так называются кусочки текста в программировании. В этой статье мы рассмотрим то что действительно необходимо знать про строки в JavaScript: как создать строку, делать escape (экранирование) символов с помощью кавычек, и объединять их.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/Useful_string_methods">Полезные строковые методы</a></dt> + <dd>После того как мы рассмотрели основы работы со строками, давайте двинемся дальше и поговорим о том какие полезные операторы и методы существуют для строк, такие как вычисление длины, соединение и разделение строк, замена отдельных символов и многие другие. </dd> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/Arrays">Массивы</a></dt> + <dd>В последней статье этого модуля мы рассмотрим массивы - изящный способ хранения различных наборов информации в имени всего одной переменной. Здесь мы поговорим о том почему это может быть полезным, рассмотрим как создать массив, получить, добавить или удалить элемент массива, и прочее.</dd> +</dl> + +<h2 id="Проверка_полученных_знаний">Проверка полученных знаний</h2> + +<p>Предложенное тестовое задание проверит ваше понимание основ JavaScript, которые вы получили пройдя предложенные выше уроки. </p> + +<dl> + <dt><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D0%B5%D0%BB%D1%8C_%D0%B3%D0%BB%D1%83%D1%8B%D1%85_%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D0%B9">Генератор глупых историй</a></dt> + <dd>Вашим заданием будет применить на практике полученные знания и создать развлекательное приложение которое будет генерировать случайные нелепые истории.</dd> +</dl> diff --git a/files/ru/learn/javascript/первые_шаги/math/index.html b/files/ru/learn/javascript/первые_шаги/math/index.html new file mode 100644 index 0000000000..29ff9258bf --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/math/index.html @@ -0,0 +1,423 @@ +--- +title: Базовая математика в JavaScript — числа и операторы +slug: Learn/JavaScript/Первые_шаги/Math +tags: + - JavaScript + - Гайд + - Математика + - Начинающий + - Операторы + - Руководство + - Скриптинг + - Статья + - кодинг +translation_of: Learn/JavaScript/First_steps/Math +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Variables", "Learn/JavaScript/Первые_шаги/Строки", "Learn/JavaScript/Первые_шаги")}}</div> + +<p class="summary">В этой части курса мы обсуждаем математику в JavaScript — как мы можем использовать {{Glossary("Operator","operators")}} и другие функции, чтобы успешно манипулировать числами для выполнения наших задач.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS, понимание того, что такое JavaScript.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Ознакомление с основами математики в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Все_любят_математику">Все любят математику</h2> + +<p>Хорошо, может быть, не все. Некоторые из нас любят математику, некоторые из нас ненавидели математику с тех пор, как мы изучали таблицу умножения в школе, а некоторые из нас находятся где-то между ними. Но никто из нас не может отрицать, что математика является фундаментальной частью жизни, и мы не можем обойтись без нее. Это особенно актуально, когда мы учимся программировать на JavaScript (или на любом другом языке, если на то пошло) — большая часть того, что мы делаем, опирается на обработку числовых данных, вычисление новых значений и т.д. Так что не удивительно, что JavaScript имеет полнофункциональный набор математических функций.</p> + +<p>В этой статье обсуждаются только основные разделы, которые вам нужно знать сейчас.</p> + +<h3 id="Типы_чисел">Типы чисел</h3> + +<p>В программировании даже скромная система десятичных чисел, которую мы все так хорошо знаем, сложнее, чем вы думаете. Мы используем разные термины для описания различных типов десятичных чисел. Например:</p> + +<ul> + <li><strong>Целые </strong>— это целые числа, такие как: 10, 400, или -5.</li> + <li><strong>С плавающей точкой </strong><em>(или: с плавающей запятой) </em>— имеют целую и дробную части, например: 12.5 или 56.7786543.</li> + <li><strong>Doubles </strong>— тип чисел с плавающей точкой, которые имеют большую точность, чем стандартные числа с плавающей точкой (что означает, что они точны для большего числа десятичных знаков).</li> +</ul> + +<p>У нас даже есть разные типы числовых систем:</p> + +<ul> + <li><strong>Бинарная</strong> — низкоуровневый язык компьютеров; нули и единицы (0 и 1);</li> + <li><strong>Восьмеричная</strong> — 8-ми разрядная, использует 0–7 в каждом столбце;</li> + <li><strong>Десятичная</strong> — 10-ти разрядная, использует 0-9 в каждом столбце;</li> + <li><strong>Шестнадцатеричная</strong> — 16-ти разрядная, используюет 0–9 и потом a–f в каждом столбце. Вы, возможно, уже встречали эти числа, когда задавали <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Hexadecimal_values">цвет в CSS</a>.</li> +</ul> + +<p><strong>Прежде чем взорвется ваш мозг, остановитесь прямо здесь и сейчас!</strong> </p> + +<p>Во-первых, мы просто будем придерживаться десятичных чисел на протяжении всего курса; вы редко когда будете сталкиваться с необходимостью думать в других числовых системах, если вообще когда-либо с ней сталкнетесь.</p> + +<p>Во-вторых, в отличие от некоторых других языков программирования, JavaScript имеет только один тип данных для чисел, как вы догадались это {{jsxref("Number")}}. Это означает, независимо от типа чисел, с которыми вы работаете в JavaScript, обрабатывать вы их будете точно так же.</p> + +<h3 id="Для_меня_всё_—_числа">Для меня всё — числа</h3> + +<p>Давайте быстро поиграем с некоторыми числами, чтобы снова познакомиться с основным синтаксисом, который нам нужен. Введите команды, перечисленные ниже, в вашу консоль (<a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a>), или используйте простую встроенную консоль.</p> + +<ol> + <li>Прежде всего, давайте объявим пару переменных и инициализируем их целым числом и числом с плавающей точкой, соответственно, затем введите имена переменных обратно, чтобы проверить, что все в порядке: + <pre class="brush: js">var myInt = 5; +var myFloat = 6.667; +myInt; +myFloat;</pre> + </li> + <li>Числовые значения набираются без кавычек. Попробуйте объявить и инициализировать еще пару переменных, содержащих числа, прежде чем двигаться дальше.</li> + <li>Теперь давайте убедимся, что обе переменные содержат одинаковый тип данных. Для этого есть оператор {{jsxref("Operators/typeof", "typeof")}}, который позволяет проверить какой тип данных содержит в себе переменная. Введите две приведенные ниже строки: + <pre class="brush: js">typeof myInt; +typeof myFloat;</pre> + В обоих случаях вы должны получить <code>"number"</code> — это все упрощает, чем если бы разные числа имели разные типы данных, и нам приходилось иметь дело с ними по-разному.</li> +</ol> + +<h2 id="Арифметические_операторы">Арифметические операторы</h2> + +<p dir="ltr" id="tw-target-text">Арифметические операторы — это основные операторы, которые мы используем для различных математических операций, например таких, как сложение или вычитание:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Оператор</th> + <th scope="col">Имя</th> + <th scope="col">Функция</th> + <th scope="col">Пример</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>+</code></td> + <td>Сложение</td> + <td>Объединение чисел в одно целое.</td> + <td><code>6 + 9</code></td> + </tr> + <tr> + <td><code>-</code></td> + <td>Вычитание</td> + <td>Вычитает правое число от левого.</td> + <td><code>20 - 15</code></td> + </tr> + <tr> + <td><code>*</code></td> + <td>Умножение</td> + <td>Умножает два числа вместе.</td> + <td><code>3 * 7</code></td> + </tr> + <tr> + <td><code>/</code></td> + <td>Деление</td> + <td>Делит левое число на правое.</td> + <td><code>10 / 5</code></td> + </tr> + <tr> + <td><code>%</code></td> + <td>Модуль числа</td> + <td> + <p>Возвращает значение остатка при делении первого числа на второе. Результат будет иметь тот же знак, что и первое число.</p> + </td> + <td> + <p><code>11 % 3 = 2</code> (поскольку число 3 вмещается три раза, остатком будет число 2)</p> + </td> + </tr> + <tr> + <td><code>**</code></td> + <td>показатель степени</td> + <td>Возводит базовое число в указанную степень, то есть количество базовых чисел, указанных экспонентой, умножается вместе. Впервые он был представлен в EcmaScript 2016.</td> + <td><code>5 ** 5</code> (возвращает 3125, или как: 5*5*5*5*5)</td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Примечание</strong>: Иногда числа участвующие в математических операциях называют операндами ( {{Glossary("Operand", "operands")}} ).</p> +</div> + +<p dir="ltr" id="tw-target-text">Нам, вероятно, не нужно учить вас базовым математическим операциям, но мы хотели бы проверить ваше понимание синтаксиса. Попробуйте ввести приведенные ниже примеры в свою консоль (<a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a>), или используйте встроенную консоль, с которой вы уже знакомы, чтобы ознакомиться с синтаксисом.</p> + +<ol> + <li>Для начала попробуйте ввести простые примеры, такие как: + <pre class="brush: js">10 + 7 +9 * 8 +60 % 3</pre> + </li> + <li>Вы также можете попробовать объявить переменные и присвоить им различные числа. Попробуйте вместо чисел использовать ранее объявленные переменные — переменные будут вести себя точно так же, как значения, которые они хранят. Например: + <pre class="brush: js">var num1 = 10; +var num2 = 50; +9 * num1; +num2 / num1;</pre> + </li> + <li>И напоследок, попробуйте ввести более сложные выражения, например: + <pre class="brush: js">5 + 10 * 3; +num2 % 9 * num1; +num2 + num1 / 8 + 2;</pre> + </li> +</ol> + +<p>Некоторые примеры выше могут дать вам не тот результат, которого вы ожидали; приведенный ниже раздел может дать ответ на вопрос о том, почему.</p> + +<h3 id="Приоритет_операторов">Приоритет операторов</h3> + +<p>Давайте взглянем на последний пример сверху. Предположим, что <code>num2</code> содержит значение 50 и <code>num1</code> содержит значение 10 (как и было обозначено выше):</p> + +<pre class="brush: js">num2 + num1 / 8 + 2;</pre> + +<p>Будучи человеком, вы, вероятно, прочитаете это как <em>"50 плюс 10 равно 60",</em> затем <em>"8 плюс 2 равно 10"</em>, и, наконец, <em>"60 делить на 10 равно 6"</em>.</p> + +<p>Но браузер видит это по-другому: <em>"10 делить на 8 равно 1.25", </em>затем <em>"50 плюс 1.25 плюс 2 равно 53.25".</em></p> + +<p>Это происходит из-за <strong>приоритета операторов</strong> - некоторые операторы будут применены перед другими в процесс вычисления суммы (в программировании ее называют выражением). Приоритет операторов в JavaScript ничем не отличается от приоритета арифметических операций, который вы изучали в школе - умножение и деление всегда выполняются первыми, затем сложение и вычитание (сумма всегда вычисляется слева направо).</p> + +<p>Если вы хотите переопределить порядок выполнения операторов, вы можете окружить парными скобками часть выражения, которая должна быть выполнена первой. Для получения результата 6 вам следует сделать следующее:</p> + +<pre class="brush: js">(num2 + num1) / (8 + 2);</pre> + +<p>Результат этого выражения равен 6.</p> + +<div class="note"> +<p><strong>Заметка</strong>: полный список операторов JavaScript и приоритетов их выполнения можно найти по этой ссылке: <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Operator_precedence">Expressions and operators</a>.</p> +</div> + +<h2 id="Операторы_инкремента_и_декремента">Операторы инкремента и декремента</h2> + +<p>Иногда вам захочется повторно добавить или вычесть единцу к/из значению числовой переменной. Это можно сделать с помощью оператора инкремента (<code>++</code>) и декремента (<code>--</code>). Мы использовали <code>++</code> в нашей игре "Угадай число" в статье <a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/A_first_splash">первое погружение в JavaScript</a>, где мы добавляли 1 к переменной <code>guessCount</code>, в которой хранилось значение количества попыток пользователя после каждого хода.</p> + +<pre class="brush: js">guessCount++;</pre> + +<div class="note"> +<p><strong>Замечание</strong>: инкремент и декремент часто используются в <a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">циклах</a>, о которых вы узнаете позже. Например, если вы захотите пройтись по списку цен и добавить к каждой налог с продаж, вам придется в цикле обойти каждую цену и провести необходимые вычисления для учета налога. Инкремент будет использован для перехода на новую ячейку списка при необходимости. У нас есть несложный пример реализации такого списка - попробуйте и взгляните на код чтобы посмотреть, сможете ли вы найти инкременты! Мы взглянем на циклы поближе позже по ходу курса.</p> +</div> + +<p>Давайте попробуем сыграть с этим в вашей консоли. Для начала заметим, что вы не можете использовать инкремент/декремент непосредсвенно к числу, что может показаться странным. Дело в том, что мы присваиваем к переменной новое обновленное число, а не просто вычисляем значение. Следующий пример приведет к ошибке:</p> + +<pre class="brush: js">3++;</pre> + +<p>Таким образом, вы можете применить инкремент только к существующим переменным:</p> + +<pre class="brush: js">var num1 = 4; +num1++;</pre> + +<p>Так, вторая странность! Если вы сделаете это, вы получите значение 4 - бразуер возвращает текущее число, после чего применяет к нему оператор инкремента. Вы можете удостовериться в том, что инкремент был применен, узнав значение переменной еще раз:</p> + +<pre class="brush: js">num1;</pre> + +<p>То же самое для <code>--</code>: попробуйте пример ниже</p> + +<pre class="brush: js">var num2 = 6; +num2--; +num2;</pre> + +<div class="note"> +<p><strong>Замечание</strong>: вы можете заставить делать это в другом порядке - применить инкремент/декремент и только потом вернуть значение. Для этого необходимо записать оператор слева от переменной, а не справа. Попробуйте пример сверху еще раз, но в этот раз используйте <code>++num1</code> и <code>--num2</code>. </p> +</div> + +<h2 id="Операторы_присваивания">Операторы присваивания</h2> + +<p>Операторы присваивания - операторы, которые присваивают значение переменным. Мы уже много раз использовали самый простой из них, <code>=</code>, он просто приравнивает значение переменной слева к значению справа:</p> + +<pre class="brush: js">var x = 3; // x содержит значение 3 +var y = 4; // y содержит значение 4 +x = y; // x теперь содержит значение y (x == 4)</pre> + +<p>Однако есть еще несколько сложных конструкций, которые позволяют делать ваш код более простым и аккуратным. Наиболее часто используемые перечислены ниже:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Name</th> + <th scope="col">Purpose</th> + <th scope="col">Example</th> + <th scope="col">Shortcut for</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>+=</code></td> + <td>Присваивание сложения</td> + <td>Прибавляет значение справа к переменной слева и возвращает новое значение переменной</td> + <td><code>x = 3;<br> + x += 4;</code></td> + <td><code>x = 3;<br> + x = x + 4;</code></td> + </tr> + <tr> + <td><code>-=</code></td> + <td>Присваивание вычитания</td> + <td>Вычитает значение справа из переменной слева и возвращает новое зачение переменной</td> + <td><code>x = 6;<br> + x -= 3;</code></td> + <td><code>x = 6;<br> + x = x - 3;</code></td> + </tr> + <tr> + <td><code>*=</code></td> + <td> + <p>Присваивание умножения</p> + </td> + <td>Умножает переменную слева на значение справа и возвращает новое зачение переменной</td> + <td><code>x = 2;<br> + x *= 3;</code></td> + <td><code>x = 2;<br> + x = x * 3;</code></td> + </tr> + <tr> + <td><code>/=</code></td> + <td>Присваивание деления</td> + <td>Делит переменную слева на значение справа и возвращает новое зачение переменной</td> + <td><code>x = 10;<br> + x /= 5;</code></td> + <td><code>x = 10;<br> + x = x / 5;</code></td> + </tr> + </tbody> +</table> + +<p>Попробуйте использовать такие конструкции, что понять, как они работают. Сможете ли вы определить значение до того, как напишите вторую строку?</p> + +<p>Замьтете, что значение справа может быть как числом (константой), так и переменной, например:</p> + +<pre class="brush: js">var x = 3; // x содержит значение 3 +var y = 4; // y содержит значение 4 +x *= y; // x содержит значение 12</pre> + +<div class="note"> +<p><strong>Заметка: есть еще <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Expressions_and_Operators">другие операторы присваивания</a></strong>,<strong> в этой статье перечислены только самые базовые.</strong></p> +</div> + +<h2 id="Активное_обучение_меняем_размеры_коробки">Активное обучение: меняем размеры коробки</h2> + +<p>В этом упражнении вы будете пользоваться числами и операторами для работы с размерами коробки. Коробка рисуется с помощью API браузера, которое назывется Canvas API. Вам не следует беспокоиться о том, как это работает - просто сосредоточьтесь на математике. Ширина и высота коробки (в пикселях) определяются переменными <code>x</code> и <code>y</code>, которые изначально равны 50.</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html", '100%', 520)}}</p> + +<p><strong><a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html">Открыть в новом окне</a></strong></p> + +<p>В коде сверху, который вы можете изменять, под комментарием есть две строчки, с помощью которых вы можете увеличивать/уменьшать размеры коробки. Мы хотим, чтобы вы выполнили несколько заданий:</p> + +<ul> + <li>Поменяйте строчку с размером x так, чтобы коробка была шириной 50px, причем 50 должно быть вычислено с помощью чисел 43 и 7 и арифмитического оператора.</li> + <li>Поменяйте строчку с размером y так, чтобы коробка была высотой 75px, причем 75 должно быть вычислено с помощью чисел 25 и 3 и арифметического оператора.</li> + <li>Поменяйте строчку с размером y так, чтобы коробка была высотой 250, при этом 250 вычислено с помощью двух чисел и оператором взятия остатка (модуль).</li> + <li>Поменяйте строчку с размером y так, чтобы коробка была высотой 150px, причем 150 вычилено с помощью трех чисел и операторов вычитания и деления.</li> + <li>Поменяйте строчку с размером x так, чтобы коробка была шириной 200px, при этом 200 вычислено с помощью числа 4 и оператора присваивания.</li> + <li>Поменяйте строчку с размером y так, чтобы коробка была высотой 200px, причем 200 вычислено с помощью чисел 50 и 3 и операторов умножения и присваивания сложения.</li> +</ul> + +<p>Не расстраивайтесть, если вы не поняли код сверху. Нажмите кнопку <em>Reset</em> для запуска программы снова. Если вы смогли ответить верно на все вопросы, попробуйте поэкспериментировать с кодом еще (или, например, предложить друзьям несколько заданий).</p> + +<h2 id="Операторы_сравнения">Операторы сравнения</h2> + +<p>Иногда нам может понадобиться проверить какое-либо условие, а затем поступить в зависимости от результата - для этого мы используем <strong>операторы сравнения</strong>.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Оператор</th> + <th scope="col">Имя</th> + <th scope="col">Назначение</th> + <th scope="col">Пример</th> + </tr> + <tr> + <td><code>===</code></td> + <td>Строгое равенство</td> + <td>Проверяет левое и правое значения на идентичность</td> + <td><code>5 === 2 + 4</code></td> + </tr> + <tr> + <td><code>!==</code></td> + <td>Строгое неравенство</td> + <td>Проверяет левое и правое значения на <strong>не</strong>идентичность</td> + <td><code>5 !== 2 + 3</code></td> + </tr> + <tr> + <td><code><</code></td> + <td>Меньше</td> + <td>Проверяет, меньше ли левое значение правого</td> + <td><code>10 < 6</code></td> + </tr> + <tr> + <td><code>></code></td> + <td>Больше</td> + <td>Проверяет, больше ли левое значение правого</td> + <td><code>10 > 20</code></td> + </tr> + <tr> + <td><=</td> + <td>Меньше или равно</td> + <td>Проверят, меньше ли левое значение правому (или равно ему)</td> + <td><code>3 <= 2</code></td> + </tr> + <tr> + <td>>=</td> + <td>Больше или равно</td> + <td>Проверят, больше ли левое значение левого (или равно ему)</td> + <td><code>5 >= 4</code></td> + </tr> + </thead> +</table> + +<div class="note"> +<p><strong>Заметка</strong>: вы можете заметить, что некоторые люди используют <code>==</code> и <code>!=</code> в их программах для сравнения на равенство и неравенство — это валидные JavaScript-операторы, но они отличаются от <code>===</code>/<code>!==</code> — первая пара проверяет на равенство/неравенство значений, не рассматривая их типы. Вторая пара - строгая версия первой, которая проверяет типы операндов. При использовании строгой версии выявляется больше ошибок, поэтому мы рекомендуем использовать именно ее.</p> +</div> + +<p>Если вы попробуете использовать эти операторы в консоли, вы увидите, что все они возвращают значения <code>true</code>/<code>false</code> — о типе данных <code>boolean</code> мы писали в прошлой статье. С их помощью мы можем принимать решения в нашей программе, например:</p> + +<ul> + <li>Порождать текст на кнопке в зависимости от того, нажата она или нет.</li> + <li>Высвечивать сообщение о поражении при проигрыше или поздравление при победе в игре.</li> + <li>Показывать пользователю верное окно приветствия в зависимости от времени года.</li> + <li>Увеличивать или уменьшать карту при выборе одной из двух опций.</li> +</ul> + +<p>Мы взглянем на то, как реализовать такую логику после знакомства с условными выражениями в следующей статье. Сейчас мы рассмотрим небольшой пример:</p> + +<pre class="brush: html"><button>Запустить машину</button> +<p>Машина остановлена</p> +</pre> + +<pre class="brush: js">var btn = document.querySelector('button'); +var txt = document.querySelector('p'); + +btn.addEventListener('click', updateBtn); + +function updateBtn() { + if (btn.textContent === 'Start machine') { + btn.textContent = 'Stop machine'; + txt.textContent = 'The machine has started!'; + } else { + btn.textContent = 'Start machine'; + txt.textContent = 'The machine id stopped.'; + } +}</pre> + +<p>{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/conditional.html", '100%', 100)}}</p> + +<p><strong><a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/conditional.html">Открыть в новом окне</a></strong></p> + +<p>Мы использовали оператор равенства внутри функции <code>updateBtn()</code>. В этом случае мы не проверяем пару математических выражений на равенcтво значений — мы просто смотрим, является ли текст на кнопке определенной строкой — что по сути является тем же самым. Если кнопка при нажатии содержит "Start machine", мы меняем содержимое метки на "Stop machine" и обновляем метку. Если же текст кнопки — "Stop machine", при нажатии мы возвращем все обратно. </p> + +<div class="note"> +<p><strong>Заметка</strong>: Такой элемент управления, который переключается между двумя состояниями, обычно называется <strong>тумблером</strong>. Он переключается между одним состоянием и другим: свет включен, свет выключен и т. д.</p> +</div> + +<h2 id="Итого">Итого</h2> + +<p>В этой статье мы привели основную информацию, необходимую для работы с числами в JavaScript. Вы постоянно будете использовать числа в процессе обучения языку, поэтому желательно разобраться в этом сейчас. Если вам действительно не нравится математика, пусть вас утешит, что эта статья была сравнительно короткой.</p> + +<p>В следующей статье мы изучим текст и то, как мы работаем с ним в JavaScript.</p> + +<div class="note"> +<p><strong>Примечание</strong>: если вам хочется узнать подробнее о том, как математика реализуется в JavaScript, вы можете посмотерть главный раздел JavaScript MDN. Статьи <a href="/ru/docs/Web/JavaScript/Guide/Numbers_and_dates">Числа и даты</a> и <a href="/ru/docs/Web/JavaScript/Reference/Operators">Выражения и операторы</a> - хороший вариант для начала.</p> +</div> + +<p>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Variables", "Learn/JavaScript/Первые_шаги/Строки", "Learn/JavaScript/Первые_шаги")}}</p> diff --git a/files/ru/learn/javascript/первые_шаги/useful_string_methods/index.html b/files/ru/learn/javascript/первые_шаги/useful_string_methods/index.html new file mode 100644 index 0000000000..1318ee39ac --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/useful_string_methods/index.html @@ -0,0 +1,723 @@ +--- +title: Полезные строковые методы +slug: Learn/JavaScript/Первые_шаги/Useful_string_methods +tags: + - Beginner + - CodingScripting + - JavaScript + - Learn + - length + - lower + - replace + - split + - upper + - Обучение + - Регистр +translation_of: Learn/JavaScript/First_steps/Useful_string_methods +--- +<p>{{LearnSidebar}}</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Строки", "Learn/JavaScript/Первые_шаги/Arrays", "Learn/JavaScript/Первые_шаги")}}</p> + +<p>Мы рассмотрели базовые понятия, касающиеся строк. Давайте пойдем дальше и рассмотрим, какие полезные операции мы можем выполнять со строками, используя встроенные функции, такие как поиск длины текстовой строки, объединение и разделение строк, замена одного символа из строки другим и многое другое.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row" style="background-color: rgb(255, 232, 212);"><strong>Необходимые знания:</strong></th> + <td style="background-color: rgb(255, 232, 212);">Базовая компьютерная грамотность, базовое понимание HTML и CSS, понимание того, что такое JavaScript.</td> + </tr> + <tr> + <th scope="row" style="background-color: rgb(255, 232, 212);"><strong>Задача:</strong></th> + <td style="background-color: rgb(255, 232, 212);">Понять, что строки являются объектами, и изучить, как использовать некоторые из основных методов, доступных для этих объектов для управления строками.</td> + </tr> + </tbody> +</table> + +<h2 id="Строки_как_объекты">Строки как объекты</h2> + +<p id="Useful_string_methods">Почти всё в JavaScript является объектами. Когда вы создаете строку, например: </p> + +<pre class="notranslate">let string = 'This is my string';</pre> + +<p>ваша переменная становится строковым объектом, и, как результат, ей доступно множество свойств и методов. Можете убедиться в этом, перейдя на страницу {{jsxref ("String")}} и просмотрев на ней список свойств и методов!</p> + +<p><strong>Только не волнуйтесь!</strong> Большинство из них вам не нужно знать сейчас на ранней стадии вашего обучения. Но некоторые из них вы, возможно, будете использовать довольно часто. Их мы и рассмотрим.</p> + +<p>Приведем несколько примеров в новой консоли. Ниже вы можете <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">открыть данную консоль</a> в отдельной вкладке или окне, или, если вам так удобней, использовать <a href="https://developer.mozilla.org/ru/docs/Learn/Discover_browser_developer_tools">браузер консоли разработчика</a>.</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Консоль JavaScript</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class', 'input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></code></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="Поиск_длины_строки">Поиск длины строки</h3> + +<p>Это легко — вы просто используете свойство {{jsxref ("String.prototype.length", "length")}}. Попробуйте ввести следующие строки:</p> + +<pre class="notranslate">let browserType = 'mozilla'; +browserType.length;</pre> + +<p>Результатом должно быть число 7, потому что слово «mozilla» состоит из 7 символов. Это свойство можно применить, например, если вы захотите найти длины серии имен, чтобы их можно было отображать по порядку длины или сообщить пользователю, что имя пользователя, которое он ввёл в поле формы, слишком длинное, если оно превышает определённую длину.</p> + +<h3 id="Получение_определенного_строкового_символа">Получение определенного строкового символа</h3> + +<p>Вы можете вернуть любой символ внутри строки, используя <strong>обозначение в квадратных скобках.</strong> Это означает, что вы добавляете квадратные скобки ([ ]) в конце вашего имени переменной. В квадратных скобках вы указываете номер символа, который хотите вернуть. Например, чтобы получить первую букву, нужно написать:</p> + +<pre class="syntaxbox notranslate">browserType[0];</pre> + +<p>Компьютеры считают от 0, а не 1! Чтобы получить последний символ <em>любой</em> строки, мы могли бы использовать следующую строку, объединив эту технику с свойством <code>length</code>:</p> + +<pre class="syntaxbox notranslate"> browserType[browserType.length-1];</pre> + +<p>Длина слова «mozilla» равна 7, но, поскольку счет начинается с 0, позиция последнего символа равна 6, поэтому нам нужна <code>length-1</code>. Такой способ можно использовать, чтобы найти первую букву ряда строк и упорядочить их по алфавиту.</p> + +<h3 id="Поиск_подстроки_внутри_строки_и_ее_извлечение">Поиск подстроки внутри строки и ее извлечение</h3> + +<ol> + <li>Иногда вам может понадобиться выяснить, присутствует ли меньшая строка внутри большей (обычно мы говорим, что внутри строки есть подстрока). Это можно сделать с помощью метода {{jsxref ("String.prototype.indexOf ()", "indexOf ()")}}, который принимает одну {{glossary ("parameter")}} - подстроку, которую вы хотите найти. Введите: + <pre class="notranslate">browserType.indexOf('zilla');</pre> + Это дает нам результат 2, потому что подстрока «zilla» начинается в позиции 2 ("m" — 0, "o" — 1, "z" — 2) внутри «mozilla». Такой код можно использовать для фильтрации строк. Например, если есть список веб-адресов и вы хотите распечатать только те, которые содержат «mozilla».</li> +</ol> + +<ol start="2"> + <li>Это можно сделать по-другому, что, возможно, ещё более эффективно. Введите следующее: + <pre class="notranslate">browserType.indexOf('vanilla');</pre> + Это должно дать вам результат -1. Такое значение возвращается, когда подстрока, в данном случае «vanilla», не найдена в основной строке.<br> + <br> + Вы можете использовать это, чтобы найти все экземпляры строк, которые не содержат подстроку «mozilla» (для обратного эффекта, используйте оператор отрицания): + <pre class="notranslate">if(browserType.indexOf('mozilla') === -1) { + // сделать что-то, если 'mozilla' + // не является частью этой строки +} + +if(browserType.indexOf('mozilla') !== -1) { + // сделать что-то, если 'mozilla' + // является частью этой строки +}</pre> + </li> + <li>Когда вы знаете, где подстрока начинается внутри строки, и вы знаете, на каком символе вы хотите её завершить, можно использовать {{jsxref ("String.prototype.slice ()", "slice ()")}} для извлечения. Попробуйте следующее: + <pre class="notranslate">browserType.slice(0,3);</pre> + Это возвращает «moz». Первым параметром является позиция символа, с которого начинается извлечение, а второй параметр — позиция последнего символа, перед которым нужно отсечь строку<em>.</em> Таким образом, срез происходит с первой позиции, вплоть до последней позиции, но не включая её <em>(</em>помним, что <em>счет идёт с 0, а не с 1)</em>. Также можно сказать, что второй параметр равен длине возвращаемой строки.</li> + <li>Кроме того, если вы знаете, что хотите извлечь все остальные символы в строке после определённого символа, вам не нужно включать второй параметр. Достаточно включить только положение символа, с которого вы хотите начать извлечение оставшихся символов в строке. Введите: + <pre class="notranslate">browserType.slice(2);</pre> + Этот код возвращает «zilla» — это потому, что позиция символа 2 — это буква z, и поскольку вы не указали второй параметр, возвращаемая подстрока состояла из всех остальных символов в строке.</li> +</ol> + +<div class="blockIndicator note"> +<p><strong>Примечание</strong>: второй параметр <code>slice()</code> не обязателен: если вы его не включите в код, обрезание закончится на конце оригинальной строки. Есть и другие варианты; изучите страницу {{jsxref ("String.prototype.slice ()", "slice ()")}}, чтобы узнать, что ещё вы можете узнать.</p> +</div> + +<h3 id="Изменение_регистра">Изменение регистра</h3> + +<p>Строковые методы {{jsxref ("String.prototype.toLowerCase ()", "toLowerCase ()")}} и {{jsxref ("String.prototype.toUpperCase ()", "toUpperCase ()")}} преобразовывают все символы в строке в нижний или верхний регистр соответственно. Этот способ можно применить, если вы хотите нормализовать все введенные пользователем данные перед их сохранением в базе данных.</p> + +<p>Попробуем ввести следующие строки, чтобы узнать, что происходит:</p> + +<pre class="notranslate">var radData = 'My NaMe Is MuD'; +radData.toLowerCase(); +radData.toUpperCase();</pre> + +<h3 id="Обновление_частей_строки">Обновление частей строки</h3> + +<p>Вы можете заменить одну подстроку внутри строки на другую подстроку, используя метод {{jsxref ("String.prototype.replace ()", "replace ()")}}. Этот метод работает очень просто на базовом уровне, но у него есть некоторые продвинутые свойства, но мы пока не будем вдаваться в детали.</p> + +<p>Он принимает два параметра — строку, которую вы хотите заменить, и строку, которую вы хотите вставить вместо заменяемой. Попробуйте этот пример:</p> + +<pre class="notranslate">browserType.replace('moz','van');</pre> + +<p>Обратите внимание, что для фактического получения обновленного значения, отраженного в переменной browserType в реальной программе, вам нужно будет установить значение переменной в результате операции; он не просто обновляет значение подстроки автоматически. Таким образом, вы должны были бы написать это: <code>browserType = browserType.replace('moz','van');</code></p> + +<h2 id="Активные_примеры_обучения">Активные примеры обучения</h2> + +<p>В этом разделе мы дадим вам попробовать набить руку и вместе напишем код строковой манипуляции. В каждом упражнении ниже у нас есть массив строк и цикл, который обрабатывает каждое значение в массиве и отображает его в маркированном списке. Вам не нужно понимать массивы или циклы прямо сейчас — это будет объяснено в будущих статьях. Все, что вам нужно сделать в каждом случае, — написать код, который выводит строки в том формате, в котором мы предлагаем.</p> + +<p>В каждом примере есть кнопка <em>Сбросить</em>, которую вы можете использовать для сброса кода, если вы допустили ошибку и не можете заставить его работать снова, а кнопку <em>Показать решение</em> вы можете нажать, чтобы увидеть потенциальный ответ, если вы действительно застрянете на решении.</p> + +<h3 id="Фильтрация_приветственных_сообщений">Фильтрация приветственных сообщений</h3> + +<p>В первом упражнении мы начнем с простого: у нас есть множество сообщений поздравительных открыток, но мы хотим отсортировать их, чтобы перечислять только рождественские сообщения. Мы хотим, чтобы вы заполнили условный тест внутри структуры if( ... ), чтобы проверить каждую строку и отобразить её в списке, только если это рождественское сообщение.</p> + +<ol> + <li>Сначала подумайте о том, как вы можете проверить, является ли сообщение в каждом случае рождественским сообщением. Какая строка присутствует во всех этих сообщениях и какой метод вы можете использовать для проверки?</li> + <li>Затем вам нужно будет написать условный тест <em>операнд1 оператор операнд2</em>. Соответствует ли результат слева результату справа? Или в этом случае вызов метода слева возвращает результат справа?</li> + <li>Подсказка. В этом случае, вероятно, полезнее проверить, не является ли часть строки не равной (!==) определенному результату.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><h2>Результат</h2> + +<div class="output" style="min-height: 125px;"> + +<ul> + +</ul> + +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label"></code>Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).<code class="language-html"></p> + +<textarea id="code" class="playable-code" style="height: 290px; width: 95%"> +var list = document.querySelector('.output ul'); +list.innerHTML = ''; +var greetings = ['С днём рождения!', + 'С Рождеством, любовь моя', + 'Счастливого Рождества всей твоей семье', + 'Ты — та, кто нужен мне на Рождество', + 'Поправляйся скорее']; + +for (var i = 0; i < greetings.length; i++) { + var input = greetings[i]; + // Ваше решение должно быть в фигурных скобках + // ниже: вы должны что-то добавить + if (greetings[i]) { + var result = input; + var listItem = document.createElement('li'); + listItem.textContent = result; + list.appendChild(listItem); + } +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></code></pre> + +<pre class="brush: css line-numbers language-css notranslate"><code class="language-css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</code></pre> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = '</code><code class="language-html">Показать решение</code><code class="language-js">'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === '</code><code class="language-html">Показать решение</code><code class="language-js">') { + textarea.value = solutionEntry; + solution.value = '</code><code class="language-html">Спрятать решение</code><code class="language-js">'; + } else { + textarea.value = userEntry; + solution.value = '</code><code class="language-html">Показать решение</code><code class="language-js">'; + } + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar greetings = [\'</code><code class="language-html">С днём рождения!</code><code class="language-js">\',\n \'</code><code class="language-html">С Рождеством, любовь моя</code><code class="language-js">\',\n \'</code><code class="language-html">Счастливого Рождества всей твоей семье</code><code class="language-js">\',\n \'</code><code class="language-html">Ты — та, кто нужен мне на Рождество</code><code class="language-js">\',\n \'</code><code class="language-html">Поправляйся скорее</code><code class="language-js">\'];\n\nfor(var i = 0; i < greetings.length; i++) {\n var input = greetings[i];\n if(greetings[i].indexOf(\'Рождеств\') !== -1) {\n var result = input;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n }\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === '</code><code class="language-html">Показать решение</code><code class="language-js">') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</code></pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 590, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="Исправление_регистра_размера_букв_в_тексте—прим._пер.">Исправление регистра (<em>размера букв в тексте—прим. пер.</em>)</h3> + +<p>В этом упражнении у нас есть названия городов в Великобритании, но написанных разным регистром. Мы хотим, чтобы вы изменили их так, чтобы они были в нижнем регистре, за исключением первой буквы. Хороший способ сделать это:</p> + +<ol> + <li>Преобразуйте всю строку, содержащуюся в переменной input, в нижний регистр и сохраните ее в новой переменной.</li> + <li>Возьмите первую букву строки в этой новой переменной и сохраните ее в другой переменной.</li> + <li>Используя эту последнюю переменную в качестве подстроки, замените первую букву строчной строки первой буквой строчной строки, измененной на верхний регистр. Сохраните результат этой процедуры замены в другой новой переменной.</li> + <li>Измените значение переменной <code>result</code> на равную конечному результату (не <code>input</code>).</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Подсказка — параметры строковых методов не обязательно должны быть строковыми литералами; они также могут быть переменными или даже переменными с вызываемым ими методом.</p> +</div> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><h2>Результат</h2> + +<div class="output" style="min-height: 125px;"> + +<ul> + +</ul> + +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label"></code>Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).<code class="language-html"></p> + +<textarea id="code" class="playable-code" style="height: 250px; width: 95%"> +var list = document.querySelector('.output ul'); +list.innerHTML = ''; +var cities = ['лонДон', 'МанЧЕСТер', 'БиРминГЕМ', 'лиВЕРпуЛЬ']; +for(var i = 0; i < cities.length; i++) { + var input = cities[i]; + // пишите код ниже + + var result = input; + var listItem = document.createElement('li'); + listItem.textContent = result; + list.appendChild(listItem); +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></code></pre> + +<pre class="brush: css line-numbers language-css notranslate"><code class="language-css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</code></pre> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = '</code><code class="language-html">Показать решение</code><code class="language-js">'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === '</code><code class="language-html">Показать решение</code><code class="language-js">') { + textarea.value = solutionEntry; + solution.value = 'Спрятать решение'; + } else { + textarea.value = userEntry; + solution.value = '</code><code class="language-html">Показать решение</code><code class="language-js">'; + } + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar cities = [\'</code><code class="language-html">лонДон</code><code class="language-js">\', \'</code><code class="language-html">МанЧЕСТер</code><code class="language-js">\', \'</code><code class="language-html">БиРминГЕМ</code><code class="language-js">\', \'</code><code class="language-html">лиВЕРпуЛЬ</code><code class="language-js">\'];\n\nfor(var i = 0; i < cities.length; i++) {\n var input = cities[i];\n var lower = input.toLowerCase();\n var firstLetter = lower.slice(0,1);\n var capitalized = lower.replace(firstLetter,firstLetter.toUpperCase());\n var result = capitalized;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === '</code><code class="language-html">Показать решение</code><code class="language-js">') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</code></pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 550, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="Создание_новых_строк_из_старых_частей">Создание новых строк из старых частей</h3> + +<p>В этом последнем упражнении массив содержит кучу строк, содержащих информацию о железнодорожных станциях на севере Англии. Строки представляют собой элементы данных, которые содержат трехбуквенный код станции, за которым следуют некоторые машиночитаемые данные, за которыми следует точка с запятой, а затем название станции, пригодное для чтения человеком. Например:</p> + +<pre class="notranslate">MAN675847583748sjt567654;Manchester Piccadilly</pre> + +<p>Мы хотим извлечь код станции и имя и поместить их в строку со следующей структурой:</p> + +<pre class="notranslate">MAN: Manchester Piccadilly</pre> + +<p>Мы бы рекоменовали реализовать это следующим образом:</p> + +<ol> + <li>Извлеките трехбуквенный код станции и сохраните его в новой переменной.</li> + <li>Найдите номер символьного номера точки с запятой.</li> + <li>Извлеките название для чтения человеком, используя номер индекса точки с запятой в качестве контрольной точки и сохраните его в новой переменной.</li> + <li>Объедините две новые переменные и строковый литерал, чтобы сделать финальную строку.</li> + <li>Измените значение переменной <code>result</code> равной конечной строке (не <code>input</code>). </li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code_3">Playable code 3</h6> + +<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><h2>Результат</h2> + +<div class="output" style="min-height: 125px;"> + +<ul> + +</ul> + +</div> + +<h2>Редактируемый код</h2> +<p class="a11y-label"></code>Нажмите Esc, чтобы выйти из поля ввода (Tab вставляет символ табуляции).<code class="language-html"></p> + +<textarea id="code" class="playable-code" style="height: 285px; width: 95%"> +var list = document.querySelector('.output ul'); +list.innerHTML = ''; +var stations = ['MAN675847583748sjt567654;Manchester Piccadilly', + 'GNF576746573fhdg4737dh4;Greenfield', + 'LIV5hg65hd737456236dch46dg4;Liverpool Lime Street', + 'SYB4f65hf75f736463;Stalybridge', + 'HUD5767ghtyfyr4536dh45dg45dg3;Huddersfield']; + +for (var i = 0; i < stations.length; i++) { + var input = stations[i]; + // пишите ваш код ниже + + var result = input; + var listItem = document.createElement('li'); + listItem.textContent = result; + list.appendChild(listItem); +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сбросить"> + <input id="solution" type="button" value="Показать решение"> +</div></code></pre> + +<pre class="brush: css line-numbers language-css notranslate"><code class="language-css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</code></pre> + +<pre class="brush: js line-numbers language-js notranslate"><code class="language-js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = '</code><code class="language-html">Показать решение</code><code class="language-js">'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === '</code><code class="language-html">Показать решение</code><code class="language-js">') { + textarea.value = solutionEntry; + solution.value = '</code><code class="language-html">Спрятать решение</code><code class="language-js">'; + } else { + textarea.value = userEntry; + solution.value = '</code><code class="language-html">Показать решение</code><code class="language-js">'; + } + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar stations = [\'MAN675847583748sjt567654;Manchester Piccadilly\',\n \'GNF576746573fhdg4737dh4;Greenfield\',\n \'LIV5hg65hd737456236dch46dg4;Liverpool Lime Street\',\n \'SYB4f65hf75f736463;Stalybridge\',\n \'HUD5767ghtyfyr4536dh45dg45dg3;Huddersfield\'];\n\nfor(var i = 0; i < stations.length; i++) {\n var input = stations[i];\n var code = input.slice(0,3);\n var semiC = input.indexOf(\';\');\n var name = input.slice(semiC + 1);\n var result = code + \': \' + name;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === '</code><code class="language-html">Показать решение</code><code class="language-js">') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</code></pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_3', '100%', 585, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Нельзя не согласиться с тем, что способность обрабатывать слова и предложения в программировании очень важна — особенно в JavaScript, поскольку веб-сайты — все связаны с людьми. Эта статья дала вам основы, которые вам нужно знать о манипуляции строками на данный момент. Это пойдет вам на пользу, когда вы займётесь более сложными темами в будущем. Далее мы рассмотрим последний важный тип данных, на который нам нужно сосредоточиться в краткосрочной перспективе — массивы.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Строки", "Learn/JavaScript/Первые_шаги/Arrays", "Learn/JavaScript/Первые_шаги")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/What_is_JavaScript">Что такое JavaScript?</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/A_first_splash">Знакомство с JavaScript</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/%D0%A7%D1%82%D0%BE_%D0%BF%D0%BE%D1%88%D0%BB%D0%BE_%D0%BD%D0%B5_%D1%82%D0%B0%D0%BA">Устранение ошибок в JavaScript</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/Variables">Переменные — место хранения необходимой информации</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/Math">Базовая математика в JavaScript</a></li> + <li><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/%D0%A1%D1%82%D1%80%D0%BE%D0%BA%D0%B8">Работа с текстом — строки в JavaScript</a></li> + <li><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/Useful_string_methods">Полезные строковые методы</a></li> + <li><a href="https://wiki.developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/Arrays">Массивы</a></li> + <li><a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D0%B5%D0%BB%D1%8C_%D0%B3%D0%BB%D1%83%D1%8B%D1%85_%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D0%B9">Генератор глупых историй</a></li> +</ul> diff --git a/files/ru/learn/javascript/первые_шаги/variables/index.html b/files/ru/learn/javascript/первые_шаги/variables/index.html new file mode 100644 index 0000000000..e1195effd5 --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/variables/index.html @@ -0,0 +1,372 @@ +--- +title: Переменные - место хранения необходимой информации +slug: Learn/JavaScript/Первые_шаги/Variables +translation_of: Learn/JavaScript/First_steps/Variables +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Что_пошло_не_так", "Learn/JavaScript/Первые_шаги/Math", "Learn/JavaScript/Первые_шаги")}}</div> + +<p class="summary">После прочтения последних двух статей вы знаете, что такое JavaScript, что он может сделать для вас, как использовать его вместе с другими веб-технологиями и какими он обладает функциями высокого уровня. В этой статье мы перейдем к реальным основам, рассмотрим, как работать с большинством базовых блоков JavaScript — Переменными.</p> + +<table class="learn-box"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS, понимание того, что такое JavaScript.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Ознакомиться с основами переменных в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Инструменты_которые_вам_нужны">Инструменты, которые вам нужны</h2> + +<p>В этой статье вам будет предложено ввести строки кода, чтобы проверить ваше понимание материала. Если вы используете браузер для настольных компьютеров, лучшим примером для ввода кода примера является консоль JavaScript вашего браузера (см. <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools</a> для получения дополнительной информации о том, как получить доступ к этому инструменту).</p> + +<p>Также мы предоставили простую консоль JavaScript, встроенную ниже в странице, для ввода кода, если вы не используете браузер с консолью JavaScript или консоль на странице окажется для вас более комфортной.</p> + +<h2 id="Что_такое_переменные">Что такое переменные?</h2> + +<p>Переменные — это контейнер для таких значений, как числа, используемые в сложении, или строка, которую мы могли бы использовать как часть предложения. Но одна из особенностей переменных — их значение может меняться. Давайте взглянем на простой пример:</p> + +<pre class="brush: html notranslate"><button>Нажми на меня</button></pre> + +<pre class="brush: js notranslate">const button = document.querySelector('button'); + +button.onclick = function() { + let name = prompt('Как Вас зовут?'); + alert('Привет ' + name + ', рады видеть Вас!'); +}</pre> + +<p>{{ EmbedLiveSample('What_is_a_variable', '100%', 50, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>В примере, по нажатию кнопки выполнится несколько строк кода. Первая строка в функции покажет пользователю окно, где попросит ввести его имя и сохранит значение в переменной. Вторая строка отобразит приветствие с включенным введенным именем, взятым из значения переменной.</p> + +<p>Чтобы лучше понять действие переменной здесь, давайте подумаем о том, как мы будем писать этот пример без использования переменной. Это будет выглядеть примерно так:</p> + +<pre class="example-bad notranslate">var name = prompt('Как вас зовут?'); + +if (name === 'Адам') { + alert('Привет, Адам, рады тебя видеть!'); +} else if (name === 'Алан') { + alert('Привет, Алан, рады тебя видеть!'); +} else if (name === 'Бэлла') { + alert('Привет, Бэлла, рады тебя видеть!'); +} else if (name === 'Бьянка') { + alert('Привет, Бьянка, рады тебя видеть!'); +} else if (name === 'Крис') { + alert('Привет, Крис, рады тебя видеть!'); +} + +// ... и так далее ...</pre> + +<p>Вам сейчас не обязательно понимать синтаксис, который мы используем (пока!), но вы должны понять идею: если бы у нас не было доступных переменных, нам пришлось бы реализовать гигантский блок кода, который проверял, какое имя было введено, а затем отображал соответствующее сообщение для этого имени. Очевидно, что это неэффективно (код намного больше, даже для четырех вариантов), и он просто не сработает, так как вы не можете хранить все возможные варианты.</p> + +<p>Переменные имеют смысл, и, когда вы узнаете больше о JavaScript, они начнут становиться второй натурой.</p> + +<p>Еще одна особенность переменных заключается в том, что они могут содержать практически все, а не только строки и числа. Переменные могут также содержать сложные данные и даже целые функции. Об этом вы узнаете больше при дальнейшем изучении курса..</p> + +<p>Заметьте: мы говорим, что переменные содержат значения. Это важное различие. Переменные не являются самими значениями; они представляют собой контейнеры для значений. Представьте, что они похожи на маленькие картонные коробки, в которых вы можете хранить вещи.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13506/boxes.png" style="display: block; height: 436px; margin: 0px auto; width: 1052px;"></p> + +<h2 id="Объявление_переменной">Объявление переменной</h2> + +<p>Чтобы использовать переменную, вы сначала должны ее создать, или, если быть точнее, объявить переменную. Чтобы сделать это, мы вводим ключевое слово var, за которым следует имя, которое вы хотите дать своей переменной:</p> + +<pre class="brush: js notranslate">var myName; +var myAge;</pre> + +<p>Здесь мы создаем две переменные myName и myAge. Попробуйте ввести эти строки сейчас в консоли вашего веб-браузера или в консоли ниже (можно открыть эту консоль в отдельной вкладке или в новом окне). После этого попробуйте создать переменную (или две) с вашими именами.</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + if(document.querySelectorAll('div').length > 1) { + inputForm.focus(); + } + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<div class="note"> +<p><strong>Заметка</strong>: в JavaScript все инструкции кода должны заканчиваться точкой с запятой (;) - ваш код может работать правильно для отдельных строк, но, вероятно, не будет, когда вы пишете несколько строк кода вместе. Попытайтесь превратить написание точки с запятой в привычку.</p> +</div> + +<p>Теперь проверим, существуют ли эти значения в среде выполненияв Для этого введем только имя переменной.</p> + +<pre class="brush: js notranslate">myName; +myAge;</pre> + +<p>В настоящее время они не содержат значения, это пустые контейнеры. В этом случае, когда вы вводите имена переменных, вы должны получить значение <code>undefined</code> . Если они не существуют, вы получите сообщение об ошибке - попробуйте сейчас ввести в консоли имя переменной ниже:</p> + +<pre class="brush: js notranslate">scoobyDoo;</pre> + +<div class="note"> +<p><strong>Заметка</strong>: Не путайте переменную, которая существует, но не имеет значения, с переменной, которая вообще не существует - это разные вещи.</p> +</div> + +<h2 id="Присвоение_значения_переменной">Присвоение значения переменной</h2> + +<p>Как только переменная объявлена, ей можно присвоить значение. Для этого пишется имя переменной, затем следует знак равенства (<code>=</code>), а за ним значение, которое вы хотите присвоить. Например:</p> + +<pre class="brush: js notranslate">myName = 'Chris'; +myAge = 37;</pre> + +<p>Попробуйте вернуться в консоль и ввести эти строки. Вы должны увидеть значение, которое вы назначили переменной, возвращаемой в консоли. Чтобы посмотреть значения переменных, нужно набрать их имя в консоли:</p> + +<pre class="brush: js notranslate">myName; +myAge;</pre> + +<p>Вы можете объявить переменную и задать ей значение одновременно:</p> + +<pre class="brush: js notranslate">var myName = 'Chris';</pre> + +<p>Скорее всего, так вы будете писать большую часть времени, так как запись и выполнения кода с одно строки происходит быстрее, чем выполнение двух действий на двух отдельных строках.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Если вы пишете многострочную программу JavaScript, которая объявляет и инициализирует (задает значение) переменную, вы можете объявить ее после ее инициализации, и она все равно будет работать. Это связано с тем, что объявления переменных обычно выполняются первыми, прежде чем остальная часть кода будет выполнена. Это называется <strong>hoisting </strong>- прочитайте <a href="/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting">var hoisting</a> для более подробной информации по этому вопросу.</p> +</div> + +<h2 id="Обновление_переменной">Обновление переменной</h2> + +<p>Когда переменной присваивается значение, вы можете изменить (обновить) это значение, просто указав другое значение. Попробуйте ввести следующие строки в консоль:</p> + +<pre class="brush: js notranslate">myName = 'Bob'; +myAge = 40;</pre> + +<h3 id="Правила_именования_переменных">Правила именования переменных</h3> + +<p>Вы можете назвать переменную как угодно, но есть ограничения. Как правило, вы должны придерживаться только латинских символов (0-9, a-z, A-Z) и символа подчеркивания.</p> + +<ul> + <li>Не рекомендуется использование других символов, потому что они могут вызывать ошибки или быть непонятными для международной аудитории.</li> + <li>Не используйте символы подчеркивания в начале имен переменных - это используется в некоторых конструкциях JavaScript для обозначения конкретных вещей.</li> + <li>Не используйте числа в начале переменных. Это недопустимо и приведет к ошибке.</li> + <li>Общепринято придерживаться так называемый <a href="https://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms">"lower camel case"</a>, где вы склеиваете несколько слов, используя строчные буквы для всего первого слова, а затем заглавные буквы последующих слов. Мы использовали это для наших имен переменных в этой статье.</li> + <li>Делайте имена переменных такими, чтобы было интуитивно понятно, какие данные они содержат. Не используйте только отдельные буквы / цифры или большие длинные фразы.</li> + <li>Переменные чувствительны к регистру, так что <code>myage</code> и <code>myAge</code> - разные переменные.</li> + <li>И последнее - вам также нужно избегать использования зарезервированных слов JavaScript в качестве имен переменных - под этим мы подразумеваем слова, которые составляют фактический синтаксис JavaScript! Таким образом, вы не можете использовать слова типа <code>var</code>, <code>function</code>, <code>let</code>, и <code>for</code> для имен переменных. Браузеры распознают их как разные элементы кода, и поэтому возникают ошибки.</li> +</ul> + +<div class="note"> +<p><strong>Заметка</strong>: По ссылке можно найти довольно полный список зарезервированных ключевых слов: <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords">Lexical grammar — keywords</a>.</p> +</div> + +<p>Примеры хороших имен переменных:</p> + +<pre class="example-good notranslate">age +myAge +init +initialColor +finalOutputValue +audio1 +audio2 +</pre> + +<p>Примеры плохих имен переменных:</p> + +<pre class="example-bad notranslate">1 +a +_12 +myage +MYAGE +var +Document +skjfndskjfnbdskjfb +thisisareallylongstupidvariablenameman</pre> + +<p>Примеры имен переменных, которые вызовут ошибки:</p> + +<pre class="example-invalid notranslate">var +Document +</pre> + +<p>Попытайтесь создать еще несколько переменных прямо сейчас, используя знания, изложенные выше.</p> + +<h2 id="Типы_переменных">Типы переменных</h2> + +<p>Есть несколько различных типов данных, которые мы можем хранить в переменных. В этом разделе мы кратко опишем их, а затем в будущих статьях вы узнаете о них более подробно.</p> + +<h3 id="Числа_Numbers">Числа (Numbers)</h3> + +<p>Вы можете хранить числа в переменных (целые числа, такие как 30, или десятичные числа, такие как 2.456, также называемые числами с плавающей точкой или с плавающей запятой). Вам не нужно объявлять типы переменных в JavaScript, в отличие от некоторых других языков программирования Если давать переменной значение числа,кавычки не используются:</p> + +<pre class="brush: js notranslate">var myAge = 17;</pre> + +<h3 id="Строки_Strings">Строки ('Strings')</h3> + +<p>Строки - это фрагменты текста. Когда вы даете переменной значение строки, вам нужно обернуть ее в одиночные или двойные кавычки, в противном случае JavaScript попытается проиндексировать ее как другое имя переменной.</p> + +<pre class="brush: js notranslate">var dolphinGoodbye = 'So long and thanks for all the fish';</pre> + +<h3 id="Логические_Booleans">Логические (Booleans)</h3> + +<p>Booleans - истинные / ложные значения - они могут иметь два значения: true или false. Они обычно используются для проверки состояния, после чего код запускается соответствующим образом. Вот простой пример:</p> + +<pre class="brush: js notranslate">var iAmAlive = true;</pre> + +<p>В действительности вы чаще будете использовать этот тип переменных так:</p> + +<pre class="brush: js notranslate">var test = 6 < 3; +</pre> + +<p>Здесь используется оператор «меньше» (<), чтобы проверить, является ли 6 меньше 3. В данном примере, он вернет false, потому что 6 не меньше 3! В дальнейшем вы узнаете больше о таких операторах.</p> + +<h3 id="Массивы_Arrays">Массивы (Arrays)</h3> + +<p>Массив - это один объект, который содержит несколько значений, заключенных в квадратные скобки и разделенных запятыми. Попробуйте ввести следующие строки в консоль:</p> + +<pre class="brush: js notranslate">var myNameArray = ['Chris', 'Bob', 'Jim']; +var myNumberArray = [10,15,40];</pre> + +<p>Как только эти массивы определены, можно получить доступ к каждому значению по их местоположению в массиве. Наберите следующие строки:</p> + +<pre class="brush: js notranslate">myNameArray[0]; // should return 'Chris' +myNumberArray[2]; // should return 40</pre> + +<p>Квадратные скобки указывают значение индекса, соответствующее позиции возвращаемого значения. Возможно, вы заметили, что массивы в JavaScript индексируются с нулевой отметкой: первый элемент имеет индекс 0.</p> + +<p>В следующей статье вы узнаете больше о массивах.</p> + +<h3 id="Объекты_Objects">Объекты (Objects)</h3> + +<p>В программировании объект представляет собой структуру кода, который моделирует объект реальной жизни. У вас может быть простой объект, представляющий автостоянку, и содержит информацию о её ширине и длине; или вы можете иметь объект, который представляет человека, и содержит данные о его имени, росте, весе, на каком языке он говорит, как сказать ему привет и многое другое.</p> + +<p>Попробуйте ввести следующую строку в консоль:</p> + +<pre class="brush: js notranslate">var dog = { name : 'Spot', breed : 'Dalmatian' };</pre> + +<p>Чтобы получить информацию, хранящуюся в объекте, вы можете использовать следующий синтаксис:</p> + +<pre class="brush: js notranslate">dog.name</pre> + +<p>Мы больше не будем рассматривать объекты в данном курсе - вы можете больше узнать о них в будущем модуле.</p> + +<h2 id="Свободная_типизация">Свободная типизация</h2> + +<p>JavaScript - это «свободно типизируемый язык», что означает, что в отличие от некоторых других языков вам не нужно указывать, какой тип данных будет содержать переменная (например, числа, строки, массивы и т. д.).</p> + +<p>Например, если вы объявите переменную и присвоите ей значение, заключенное в кавычки, браузер будет обрабатывать переменную как строку:</p> + +<pre class="brush: js notranslate">var myString = 'Привет';</pre> + +<p>Он все равно будет строкой, даже если он содержит числа, поэтому будьте осторожны:</p> + +<pre class="brush: js notranslate">var myNumber = '500'; // упс, это все еще строка (string) +typeof(myNumber); +myNumber = 500; // так-то лучше, теперь это число (number) +typeof(myNumber);</pre> + +<p>Попробуйте ввести четыре строки выше в консоль одну за другой и посмотреть результаты. Вы заметите, что мы используем специальную функцию <code>typeof()</code> - она возвращает тип данных переменной, которую вы передаете в нее. В первый раз, когда она вызывается, она должа возвращать строку, так как переменная <code>myNumber</code> содержит строку <code>'500'</code>. Посмотрите, что она вернет во второй раз, когда вы ее вызовите.</p> + +<h2 id="Подведение_итогов">Подведение итогов</h2> + +<p>К настоящему времени вы должны знать достаточно о переменных JavaScript и о том, как их создавать. В следующей статье мы остановимся на числах более подробно, рассмотрев, как сделать базовую математику в JavaScript.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Что_пошло_не_так", "Learn/JavaScript/Первые_шаги/Math", "Learn/JavaScript/Первые_шаги")}}</p> diff --git a/files/ru/learn/javascript/первые_шаги/what_is_javascript/index.html b/files/ru/learn/javascript/первые_шаги/what_is_javascript/index.html new file mode 100644 index 0000000000..f34dac6902 --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/what_is_javascript/index.html @@ -0,0 +1,339 @@ +--- +title: Что такое JavaScript? +slug: Learn/JavaScript/Первые_шаги/What_is_JavaScript +translation_of: Learn/JavaScript/First_steps/What_is_JavaScript +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Первые_шаги/A_first_splash", "Learn/JavaScript/Первые_шаги")}}</div> + +<p class="summary">Добро пожаловать на курс MDN JavaScript для начинающих! В первой статье курса мы дадим базовое определение JavaScript, ответим на вопросы «Что такое JavaScript?» и «Что он делает?», узнаем как работает JavaScript и как добавить его на веб-страницу.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td>Базовая компьютерная грамотность, знание основ HTML и CSS.</td> + </tr> + <tr> + <th scope="row">Цели:</th> + <td>Знакомство с JavaScript и его возможностями, способами его подключения к веб-странице.</td> + </tr> + </tbody> +</table> + +<h2 id="Определение_высокого_уровня">Определение высокого уровня</h2> + +<p>JavaScript это язык, который позволяет Вам применять сложные вещи на web странице — каждый раз, когда на web странице происходит что-то большее, чем просто её статичное отображение — отображение периодически обновляемого контента, или интерактивных карт, или анимация 2D/3D графики, или прокрутка видео в проигрывателе, и т.д. — можете быть уверены, что скорее всего, не обошлось без JavaScript. Это третий слой слоёного пирога стандартных web технологий, два из которых (<a href="https://developer.mozilla.org/ru/docs/Learn/HTML">HTML</a> и <a href="https://developer.mozilla.org/ru/docs/Learn/CSS">CSS</a>) мы детально раскрыли в других частях учебного пособия.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13502/cake.png" style="display: block; margin: 0 auto;"></p> + +<ul> + <li>{{glossary("HTML")}} - это язык разметки, который мы используем для визуального и смыслового структурирования нашего web контента, например, определяем параграфы, заголовки, таблицы данных, или вставляем изображения и видео на страницу.</li> + <li>{{glossary("CSS")}} - это язык стилей с помощью которого мы придаем стиль отображения нашего HTML контента, например придаем цвет фону (background) и шрифту, придаем контенту многоколоночный вид.</li> + <li>{{glossary("JavaScript")}} язык программирования, который позволяет Вам создать динамически обновляемый контент, управляет мультимедиа, анимирует изображения, впрочем, делает всё, что угодно. Окей, не все, что угодно, но все равно, это удивительно, что можно достичь с помощью нескольких строк JavaScript кода.</li> +</ul> + +<p>Три слоя прекрасно выстраиваются друг над другом. Возьмем простой текст для примера. Для придания структуры и смыслового назначения тексту, разметим его с помощью HTML:</p> + +<pre class="brush: html"><p>Player 1: Chris</p></pre> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13422/just-html.png" style="height: 28px; width: 108px;"></p> + +<p>Затем мы добавим немного CSS, что бы это выглядело симпатичнее:</p> + +<pre class="brush: css">p { + font-family: 'helvetica neue', helvetica, sans-serif; + letter-spacing: 1px; + text-transform: uppercase; + text-align: center; + border: 2px solid rgba(0,0,200,0.6); + background: rgba(0,0,200,0.3); + color: rgba(0,0,200,0.6); + box-shadow: 1px 1px 2px rgba(0,0,200,0.4); + border-radius: 10px; + padding: 3px 10px; + display: inline-block; + cursor:pointer; +}</pre> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13424/html-and-css.png" style="height: 48px; width: 187px;"></p> + +<p>И наконец, добавим немного JavaScript для придания динамического поведения:</p> + +<pre>const para = document.querySelector('p'); + +para.addEventListener('click', updateName); + +function updateName() { + let name = prompt('Enter a new name'); + para.textContent = 'Player 1: ' + name; +}</pre> + +<p>{{ EmbedLiveSample('Определение_высокого_уровня', '100%', 80) }}</p> + +<p>Попробуйте кликнуть по тексту чтобы увидеть, что произойдет (Вы так же можете найти это демо на GitHub — смотрите <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/javascript-label.html">исходный код</a>, или <a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/javascript-label.html">запустите вживую</a>)!</p> + +<p>JavaScript может делать намного больше — давайте выясним это более детально.</p> + +<h2 id="Так_что_же_он_действительно_может_делать">Так что же он <em>действительно</em> может делать?</h2> + +<p>Ядро языка JavaScript состоит из некоторого количества обычных возможностей, которые позволяют делать следующее:</p> + +<ul> + <li>Хранить данные внутри переменных. В примере выше, мы, например, запрашивали ввод нового имени, которое нужно было ввести, затем сохраняли имя в переменной <code>name</code>.</li> + <li>Операции над фрагментами текстов (известными в программировании как "строки"). В примере выше мы брали строку "Player 1: " и присоединили её к значению переменной <code>name</code> для получения полного текста, например: ''Player 1: Chris".</li> + <li>Запускать код в соответствии с определенными событиями происходящими на web странице. В нашем примере выше, мы использовали {{Event("click")}} событие, для определения момента, когда кнопка была кликнута, в соответствии с этим запускался код, который обновлял текст.</li> + <li>И многое другое!</li> +</ul> + +<p>Еще более увлекательным является функциональность, созданная поверх основного языка JavaScript. Так называемые интерфейсы прикладного программирования (API) предоставляют вам дополнительные сверхспособности для использования в вашем коде JavaScript.</p> + +<p>API - это готовые наборы блоков кода, которые позволяют разработчику реализовывать программы, которые в противном случае было бы трудно или невозможно реализовать. Они делают то же самое для программирования, что готовые комплекты мебели делают для домашнего строительства - гораздо проще брать готовые панели и скручивать их вместе, чтобы сделать книжную полку, чем самому разрабатывать дизайн, ходить в поисках правильной древесины, вырезать все панели необходимого размера и формы, найти подходящие винты, а затем собрать их вместе, чтобы сделать книжную полку.</p> + +<p>Они обычно делятся на две категории.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13508/browser.png" style="display: block; height: 511px; margin: 0px auto; width: 815px;"></p> + +<p><strong>API-интерфейсы</strong> браузера встроены в ваш веб-браузер и могут отображать данные из окружающего компьютерного окружения или делать полезные сложные вещи. Например: </p> + +<ul> + <li>API-интерфейс DOM (Document Object Model) позволяет вам манипулировать HTML и CSS, создавать, удалять и изменять HTML, динамически применять новые стили к вашей странице и т. д.. Каждый раз, когда вы видите всплывающее окно на странице или какое-то новое содержимое, Как мы видели выше в нашем простом демо), например, это DOM в действии. </li> + <li>API геолокации извлекает географическую информацию. Так Google Maps может найти ваше местоположение и нанести его на карту. </li> + <li>API Canvas и WebGL позволяют создавать анимированные 2D и 3D-графики. Люди делают некоторые удивительные вещи, используя эти веб-технологии - см. Chrome Experiments и webglsamples. </li> + <li>Аудио и видео API, такие как {{ domxref("HTMLMediaElement")}} и WebRTC, позволяют делать действительно интересные вещи с мультимедиа, такие как проигрывание аудио и видео прямо на веб-странице, или захватывать видео с веб-камеры и отображать его на Чужой компьютер (попробуйте наш простой демонстрационный снимок, чтобы понять идею)</li> +</ul> + +<div class="note"> +<p><strong>Заметка</strong>: Большинство наших демо не будут корректно работать в старых браузерах — поэтому будет хорошей идеей, для запуска вашего кода установить один из современных браузеров , таких как Firefox, Chrome, Edge или Opera . Также понадобится более подробно рассмотреть раздел по <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing">кроссбраузерному тестированию</a>, когда вы приблизитесь к разработке производственного кода (т.е реального кода, который будут использовать клиенты).</p> +</div> + +<p>По умолчанию сторонние API-интерфейсы не встроены в браузер, и вам придётся захватывать их код и информацию из какого-либо места в Сети. Для примера: </p> + +<ul> + <li><a href="https://dev.twitter.com/overview/documentation">Twitter API</a> позволяет вам отображать ваши последние твиты на вашем веб-сайте.</li> + <li><a href="https://developers.google.com/maps/">Google Maps API</a> позволяет вам встраивать пользовательские карты на ваш сайт и другой подобный функционал.</li> +</ul> + +<div class="note"> +<p><strong>Заметка</strong>: Эти API-и <span style="background-color: #f6d5d9;">являются продвинутыми</span>, и мы не будем их рассматривать в нашем курсе, но ссылки, данные выше, предлагают полную документацию, если вы заинтересованы в более подробной информации.</p> +</div> + +<p>Доступно еще больше! Но пока не заостряйте на этом внимание. Вы не сможете создать следующий Facebook, Google Maps или Instagram после 24 часов изучения JavaScript — сначала нужно изучить основы. И именно для этого вы здесь — давайте двигаться дальше!</p> + +<h2 id="Что_JavaScript_делает_на_вашей_странице">Что JavaScript делает на вашей странице?</h2> + +<p>В этой главе мы рассмотрим код и увидим что же действительно происходит, когда на странице запускается JavaScript.</p> + +<p>Давайте составим краткий бриф, что же происхоит когда мы загружаем страничку в браузере (первое упоминание в статье <a href="/en-US/Learn/CSS/Introduction_to_CSS/How_CSS_works#How_does_CSS_actually_work">Как работает CSS</a>). Когда вы загружаете страничку в браузере, вы запускаете ваш код (HTML, CSS и JavaScript) внутри исполняемой среды (внутри вкладки браузера). Это как будто фабрика берет сырьё (некий код) и выдает продукцию (веб-страничку).</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13504/execution.png" style="display: block; margin: 0 auto;"></p> + +<p>Код JavaScript выполняется JavaScript-движком браузера, после того как код HTML и CSS был обработан и сформирован в веб-страницу. Это гарантирует, что структура и стиль страницы уже сформированы к моменту запуска JavaScript.</p> + +<p>Это хорошо, так как часто использование JavaScript заключается в динамическом изменении HTML и CSS в целях обновления пользовательского интерфейса посредством Document Object Model API (как упоминалось выше). Если бы запуск JavaScript осуществлялся прежде загрузки HTML и CSS, то это привело бы к возникновению ошибок. </p> + +<h3 id="Безопасность_браузера">Безопасность браузера</h3> + +<p>Каждая вкладка браузера представляет собой отдельную коробку для запуска кода (в техническом языке, эти коробки называются "средами исполнения") — это значит, что в большинстве случаев код на каждой вкладке запускается полностью отдельно, а код одной вкладки не может напрямую влиять на код другой вкладки или на другом веб-сайте. Это хорошая мера безопасности — если бы это было иначе, пираты могли написать код, который крал информацию с других сайтов или делал другие плохие вещи.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Есть способы отправлять код и данные между разными веб-сайтами/вкладками безопасным способом, но это продвинутые методы, которые мы не будем рассматривать в рамках этого курса.</p> +</div> + +<h3 id="Последовательность_выполнения_JavaScript">Последовательность выполнения JavaScript</h3> + +<p>Обычно, когда браузер сталкивается с блоком JavaScript, он запускает его по порядку, сверху вниз. Это значит, что вам нужно осторожно выбирать порядок. Например, вернемся к блоку JavaScript, который мы видели в первом примере:</p> + +<pre>const para = document.querySelector('p'); + +para.addEventListener('click', updateName); + +function updateName() { + let name = prompt('Enter a new name'); + para.textContent = 'Player 1: ' + name; +}</pre> + +<p>Здесь мы выбираем абзац текста (строка 1), а затем добавляем к нему обнаружение событий (строка 3), чтобы при нажатии на этот абзац выполнялся блок кода <code>updateName()</code> (строки 5–8). Блок кода <code>updateName()</code> (эти типы <span id="result_box" lang="ru"><span>многократно используемых блоков кода</span></span> называются "функции") запрашивает у пользователя новое имя, а затем вставляет это имя в абзац для обновления отображения.</p> + +<p>Если вы поменяете порядок первых двух строк кода, он перестанет работать — вместо этого вы получите ошибку <span id="result_box" lang="ru"><span>возвращаемую в консоль браузера</span></span> — <code>TypeError: para is undefined</code>. Это значит, что объект <code>para</code> еще не существует и вы не можете добавить к нему обнаружение событий.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Это очень частая ошибка — вы должны быть осторожны, чтобы объекты, на которые ссылается ваш код, существовали до того, как вы попытаетесь что-то с ними сделать.</p> +</div> + +<h3 id="Интерпретируемый_против_компилируемого_кода">Интерпретируемый против компилируемого кода</h3> + +<p>В контексте программирования, вы можете услышать термины <strong>интерпретация</strong> и <strong>компиляция</strong>. JavaScript является <span id="result_box" lang="ru"><span>интерпретируемым языком</span></span> — код запускается сверху вниз и результат запуска немедленно возвращается. Вам не нужно преобразовывать код в другую форму, перед запуском в браузере.</p> + +<p><span id="result_box" lang="ru"><span>С другой стороны, к</span></span><span lang="ru"><span>омпилируемые языки преобразуются (компилируются) в другую форму, прежде чем они будут запущены компьютером.</span> <span>Например, C / C ++ компилируются в язык ассемблера, который затем запускается компьютером.</span></span></p> + +<p><span id="result_box" lang="ru"><span>Оба подхода имеют разные преимущества, которые на данном этапе мы обсуждать не будем.</span></span></p> + +<h3 id="Серверный_против_клиентского_кода">Серверный против клиентского кода</h3> + +<p>Вы так же можете услышать термины <strong>серверный</strong> и <strong>клиентский</strong> код, особенно в контексте веб-разработки. Клиентский код — это код, который запускается на компьютере пользователя. При просмотре веб-страницы, клиентский код загружается, а затем запускается и отображается браузером. В этом модуле JavaScript мы явно говорим о <strong>клиентском JavaScript</strong>.</p> + +<p>С другой стороны, серверный код запускается на сервере, затем его результаты загружаются и отображаются в браузере. Примеры популярных серверных веб-языков включают PHP, Python, Ruby и ASP.NET. И JavaScript! JavaScript так же может использоваться, как серверный язык, например в популярной среде Node.js — вы можете больше узнать о серверном JavaScript в нашем разделе <a href="/en-US/docs/Learn/Server-side">Dynamic Websites – Server-side programming</a>.</p> + +<p>Слово <strong>динамический</strong> используется для описания и клиентского JavaScript, и серверного языка — это относится к возможности обновления отображения веб-страницы/приложения, чтобы показывать разные вещи в разных обстоятельствах, генерируя новый контент по мере необходимости. Серверный код динамически генерирует новый контент на сервере, например достает данные из базы данных, тогда как клиентский JavaScript динамически генерирует новое содержание внутри браузера на клиенте, например создает новую HTML таблицу, вставляя в нее данные полученные с сервера, затем отображает таблицу на веб-странице, которую видит пользователь. В этих двух контекстах значение немного отличается, но связано, и обычно оба подхода (серверный и клиентский) работают вместе.</p> + +<p>Веб-страница без динамического обновления контента называется <strong>статической</strong> — она просто показывает один и тотже контент все время.</p> + +<h2 id="Как_добавить_JavaScript_на_вашу_страницу">Как добавить JavaScript на вашу страницу?</h2> + +<p>JavaScript применяется к вашей HTML странице точно так же, как CSS. И если CSS использует элементы {{htmlelement("link")}} для внешних стилей и {{htmlelement("style")}} для встроеных в HTML, то для JavaScript нужен только один друг в HTML мире — элемент {{htmlelement("script")}}. Давайте узнаем, как это работает.</p> + +<h3 id="Внутренний_JavaScript">Внутренний JavaScript</h3> + +<ol> + <li>Сначала, сделайте локальную копию нашего файла-примера <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript.html">apply-javascript.html</a>. Сохраните его в удобное для вас место.</li> + <li>Откройте этот файл в вашем браузере и в вашем текстовом редакторе. Вы увидите, что HTML создает простую веб-страницу с активной кнопкой.</li> + <li>Затем, перейдите в текстовый редактор и добавьте следующие строки перед закрывающим тегом <code></head></code>: + <pre class="brush: html"><script> + + // здесь будет JavaScript + +</script></pre> + </li> + <li>Теперь добавим JavaScript внутрь элемента {{htmlelement("script")}}, чтобы сделать страницу более интересной — добавьте следующий код ниже строки "// здесь будет JavaScript": + <pre>document.addEventListener("DOMContentLoaded", function() { + function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); + } + + const buttons = document.querySelectorAll('button'); + + for(let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); + } +});</pre> + </li> + <li>Сохраните файл и обновите страницу в браузере — теперь вы должны увидеть, что при нажатии на кнопку создается новый абзац и помещается ниже.</li> +</ol> + +<div class="note"> +<p><strong>Заметка</strong>: Если ваш пример не работает, пройдите еще раз все шаги и проверьте, сделали ли вы все правильно. Сохранили ли вы вашу локальную копию начального кода, как <code>.html</code> файл? Добавили ли ваш {{htmlelement("script")}} элемент после тэга <code></body></code>? Ввели ли вы JavaScript именно так, как показано? <strong>JavaScript регистрозависимый, и очень привередливый. Поэтому вам нужно вводить синтаксис именно так, как показано, в противном случае оно может не работать.</strong></p> +</div> + +<div class="note"> +<p><strong>Заметка</strong>: Вы можете увидеть эту версию на GitHub-е как <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript-internal.html">apply-javascript-internal.html</a> (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/apply-javascript-internal.html">посмотреть вживую</a>).</p> +</div> + +<h3 id="Внешний_JavaScript">Внешний JavaScript</h3> + +<p>Это отлично работает, но что если мы хотим поместить наш JavaScript в отдельный файл? Давайте сейчас разберемся с этим.</p> + +<ol> + <li>Сначала, создайте новый файл в той же папке, что и ваш файл-пример HTML. Назовите его <code>script.js</code> — убедитесь, что у имени файла расширение .js, так как оно распознается, как JavaScript.</li> + <li>Замените ваше текущий элемент {{htmlelement("script")}} на следующий: + <pre class="brush: html"><script src="script.js" defer></script></pre> + </li> + <li>Внутри <code>script.js</code> добавьте следующий скрипт: + <pre>function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); +} + +const buttons = document.querySelectorAll('button'); + +for(let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); +}</pre> + </li> + <li>Сохраните и обновите страницу в браузере, и вы увидите то же самое! Все работает точно так же, но теперь у нас есть JavaScript во внешнем файле. Это, как правило, хорошо с точки зрения организации кода и его повторного использования в нескольких HTML файлах. Кроме того, HTML легче читать без огромных кусков кода, который скапливается в нем.</li> +</ol> + +<div class="note"> +<p><strong>Заметка</strong>: Вы можете увидеть эту версию на GitHub-е как <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript-external.html">apply-javascript-external.html</a> и <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/script.js">script.js</a> (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/apply-javascript-external.html">посмотреть вживую</a>).</p> +</div> + +<h3 id="Инлайновые_JavaScript_обработчики">Инлайновые JavaScript обработчики</h3> + +<p>Обратите внимание, что иногда можно столкнуться с частями JavaScript кода, который живет внутри HTML. Это может выглядеть примерно так:</p> + +<div id="Inline_JavaScript_handlers"> +<pre class="brush: js example-bad">function createParagraph() { + var para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); +}</pre> + +<pre class="brush: html example-bad"><button onclick="createParagraph()">Click me!</button></pre> +</div> + +<p>Вы можете попробовать эту версию в нашей демонстрации ниже:</p> + +<p>{{ EmbedLiveSample('Inline_JavaScript_handlers', '100%', 150) }}</p> + +<p>Эта демонстрация имеет те же функциональные возможности, что и в предыдущих двух разделах, за исключением того, что элемент {{htmlelement("button")}} содержит встроенный обработчик <code>onclick</code>, который запускает функцию при нажатии кнопки.</p> + +<p><strong>Но пожалуйста, не делайте этого.</strong> Это плохая практика — загрязнять ваш HTML кодом JavaScript, и она не эффективна — вам нужно будет добавить атрибут <code>onclick="createParagraph()"</code> к каждой кнопке, к которой вы хотите подключить JavaScript.</p> + +<p>Использование чистой JavaScript конструкции, позволит вам выбрать все кнопки, используя одну команду. Код, который можно использовали для этой цели, выглядит следующим образом:</p> + +<pre>const buttons = document.querySelectorAll('button'); + +for(let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); +}</pre> + +<p>Это может выглядеть немного длиннее, чем атрибут <code>onclick</code>, но это будет работать для всех кнопок, независимо от того, сколько их на странице, и сколько их удалят или добавят. JavaScript менять не нужно.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Попробуйте отредактировать вашу версию <code>apply-javascript.html</code> и добавить еще несколько кнопок в файл. После перезагрузки вы должны увидеть, что все кнопки создают параграф, если кликнуть на них. Классно, да?</p> +</div> + +<h3 id="Стратегии_загрузки_скриптов">Стратегии загрузки скриптов</h3> + +<p>Существует ряд проблем, связанных с загрузкой скриптов в нужное время. Всё не так просто, как кажется! Распространённой проблемой является то, что весь HTML-код на странице загружается в том порядке, в котором отображается. Если вы используете JavaScript для манипуляции элементами на странице (или, точнее, в DOM – Объектной Модели Документа), ваш код не будет работать, если JavaScript-код загрузится и распознается раньше HTML-кода, с которым вы пытаетесь взаимодействовать.</p> + +<h2 id="Комментарии">Комментарии</h2> + +<p>Так же, как и в HTML и CSS, возможно писать комментарии в вашем JavaScript коде, что будет проигнорировано браузером, и существует только для того, чтобы давать подсказки вашим друзьям-разработчикам о том, как работает код (и лично вам, если вы вернетесь к коду спустя 6 месяцев и не сможете вспомнить, что вы делали). Комментарии очень полезны, и вы должны часто их использовать, особенно для больших приложений. Вот два типа комментариев:</p> + +<ul> + <li>Однострочный комментарий пишется после двойного слеша (//), например: + <pre class="brush: js">// Я комментарий</pre> + </li> + <li>Комментарий на нескольких строках пишется между строками /* и */, например: + <pre class="brush: js">/* + Я тоже + комментарий +*/</pre> + </li> +</ul> + +<p>Так, например, мы можем описать наш последний демо-пример JavaScript подобными комментариями:</p> + +<pre class="brush: js">// Функция: создает новый параграф и добавляет его вниз тела HTML. + +function createParagraph() { + var para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); +} + +/* + 1. Получаем ссылки на все кнопки на странице в виде массива. + 2. Перебераем все кнопки и добавляем к ним отслеживатель события нажатия. + + При нажатии любой кнопки, будет выполняться функция createParagraph(). +*/ + +var buttons = document.querySelectorAll('button'); + +for (var i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); +}</pre> + +<h2 id="Выводы">Выводы</h2> + +<p>Поздравляем, вы сделали ваш первый шаг в мир JavaScript. Мы начали всего-лишь с теории, чтобы вы привыкли к тому, что вы будете использовать JavaScript, и что именно вы можете делать с его помощью. На этом пути вы увидели несколько примеров кода и выучили, как JavaScript вписывается в остальной код на вашем сайте среди всего прочего.</p> + +<p>JavaScript может показаться немного пугающим в данным момент, но не переживайте - в этом курсе мы проведем вас сквозь него простыми шагами, которые имеют смысл, забегая наперед. В следующей главе мы <a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8/A_first_splash">погрузимся непосредственно в практику</a>, подталкивая вас погрузиться в код и сделать ваши собственные примеры JavaScript.</p> + +<p>{{NextMenu("Learn/JavaScript/Первые_шаги/A_first_splash", "Learn/JavaScript/Первые_шаги")}}</p> diff --git a/files/ru/learn/javascript/первые_шаги/создатель_глуых_историй/index.html b/files/ru/learn/javascript/первые_шаги/создатель_глуых_историй/index.html new file mode 100644 index 0000000000..139e478847 --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/создатель_глуых_историй/index.html @@ -0,0 +1,148 @@ +--- +title: Генератор глупых историй +slug: Learn/JavaScript/Первые_шаги/Создатель_глуых_историй +tags: + - JavaScript + - Задание + - Изучение + - Испытание + - Массивы + - НаписаниеКода + - НачальныйУровень + - Операторы + - Переменные + - Проверка + - Числа +translation_of: Learn/JavaScript/First_steps/Silly_story_generator +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/JavaScript/Первые_шаги/Arrays", "Learn/JavaScript/Первые_шаги")}}</div> + +<p class="summary">В этом испытании вам будет нужно, используя знания, полученные в статьях этого модуля, применить их для создания забавного приложения, создающего случайные глупые истории. Удачно повеселиться!</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Перед началом выполнения этого испытания вам следует проработать все статьи в этом модуле.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Протестировать понимание основ языка JavaScript, таких как переменные, числа, операторы, строки и массивы.</td> + </tr> + </tbody> +</table> + +<h2 id="Начальная_точка">Начальная точка</h2> + +<p>Для начала испытания вам следует:</p> + +<ul> + <li>Перейти и <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/assessment-start/index.html">скопировать файл HTML</a> как пример, сохранив его локальную копию как <code>index.html</code> в новой папке где-то на вашем компьютере. Там же будет храниться и CSS документ нужный для стилизации.</li> + <li>Перейти на <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/assessment-start/raw-text.txt">страницу, содержащую исходный текст, </a>и оставить ее открытой в отдельной вкладке браузера. Она вам понадобится позже.</li> +</ul> + +<div class="note"> +<p><strong>Замечание</strong>: Так же вы можете использовать такие сайты как <a class="external external-icon" href="http://jsbin.com/">JSBin</a> или <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a> для выполнения вашего испытания. Вы можете вставить HTML, CSS и JavaScript в один из этих онлайн редакторов. Если онлайн редактор, который вы используете, не имеет отдельного окна для JavaScript - не стесняйтесь вставить все скрипты в <code><script></code> элемент внутри HTML страницы.</p> +</div> + +<h2 id="Краткое_описание_проекта"><span class="short_text" id="result_box" lang="ru"><span>Краткое описание проекта</span></span></h2> + +<p><span id="result_box" lang="ru"><span>Вам предоставили некоторый необработанный HTML/CSS, несколько текстовых строк и функций JavaScript;</span> <span>вам необходимо написать необходимый JavaScript код, чтобы превратить это в рабочую программу, которая выполняет следующие действия:</span></span></p> + +<ul> + <li>Создает глупую историю по нажатию на кнопку "Generate random story".</li> + <li>Заменяет стандартное имя "Bob" в истории на свое имя, только если оно введено в поле "Enter custom name" перед тем, как нажата создающая кнопка.</li> + <li>Конвертирует изначальные US величины веса и температуры в соответствующие для UK, если выбран соответствующий переключатель.</li> + <li>Будет создавать другую глупую историю если нажать на кнопку снова (и снова... )</li> +</ul> + +<p>Следующий скриншот показывает пример того, что должна выводить законченная программа:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13667/assessment-1.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>Чтобы вы больше поняли идею <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/assessment-finished/">опробуйте готовый пример</a> (<span class="short_text" id="result_box" lang="ru"><span>не заглядывая в исходный код!</span></span>)</p> + +<h2 id="Шаги_к_цели">Шаги к цели</h2> + +<p>Следующие разделы описывают, что вам нужно будет сделать.</p> + +<p>Начальная подготовка:</p> + +<ol> + <li>Создайте новый файл под названием <code>main.js</code> в той же папке, что и <code>index.html</code>.</li> + <li>Подключите данный JavaScript документ в ваш HTML файл с помощью {{htmlelement("script")}} элемента привязки <code>main.js</code>. Разместите его прямо перед закрывающимся <code></body></code> тегом.</li> +</ol> + +<p>Задайте переменные и функции:</p> + +<ol> + <li>В исходном текстовом документе скопируйте весь код под заголовком "1. COMPLETE VARIABLE AND FUNCTION DEFINITIONS" и вставьте в начало файла <code>main.js</code>. Это даст вам три переменные, ссылающиеся на текстовое поле "Enter custom name" (<code>customName</code>), кнопку "Generate random story" (<code>randomize</code>), и элемент снизу HTML страницы, куда будет помещена сама история {{htmlelement("p")}} (<code>story</code>), соответственно. Также у вас должна быть функция<code>randomValueFromArray()</code>, котрая принимает массив и случайным образом возвращает оттуда один из элементов.</li> + <li>Теперь взгляните на второй параграф исходного документа — "2. RAW TEXT STRINGS". Он содержит строки текста, которые будут использоваться как входные данные вашей программы. Вам следует поместить их внутрь переменных в файле <code>main.js</code>: + <ol> + <li>Сохраните первую большую строку текста в переменную <code>storyText</code>.</li> + <li>Сохраните первый блок из трех строк как массив, назвав его <code>insertX</code>.</li> + <li>Сохраните второй блок из трех строк как массив, назвав его <code>insertY</code>.</li> + <li>Сохраните третий блок из трех строк как массив, назвав его <code>insertZ</code>.</li> + </ol> + </li> +</ol> + +<p>Создание обработчика событий и неполной функции:</p> + +<ol> + <li>Теперь возвращаемся к исходному текстовому файлу.</li> + <li>Скопируйте код под заголовком "3. EVENT LISTENER AND PARTIAL FUNCTION DEFINITION" и вставте его в конец файла <code>main.js</code>. Это: + <ul> + <li>Добавит обработчик события кликанья в переменную <code>randomize</code>, Так что, когда кнопка будет нажата - функция <code>result()</code> запустится.</li> + <li>Добавляет в код частично завершенную функцию <code>result()</code>. В течении оставшейся части испытания вам предстоит, заполняя строчки внутри этой функции, завершить ее и заставить работать должным образом.</li> + </ul> + </li> +</ol> + +<p>Завершение функции <code>result()</code>:</p> + +<ol> + <li>Создайте новую переменную <code>newStory</code> и установите ее значение равным <code>storyText</code>. Это необходимо, чтобы мы могли создавать новую случайную историю каждый раз, когда нажимается кнопка, и функция запускается. Если бы мы внесли изменения непосредственно в <code>storyText</code>, мы могли бы генерировать новую историю только один раз.</li> + <li>Создайте три новые переменные, называемые <code>xItem</code>, <code>yItem</code> и <code>zItem</code>, и сделайте их равными результату вызова <code>randomValueFromArray()</code> на трех ваших массивах (результат в каждом случае будет случайным элементом из каждого массива, на который он вызывается). Например, вы можете вызвать функцию и получить ее, чтобы вернуть одну случайную строку из <code>insertX</code>, записав <code>randomValueFromArray (insertX)</code>.</li> + <li>Затем мы хотим заменить три заполнителя строки <code>newStory</code> - <code>:insertx:</code>, <code>:inserty :</code> и <code>:insertz:</code> - со строками, хранящимися в <code>xItem</code>, <code>yItem</code> и <code>zItem</code>. Здесь вам поможет определенный строковый метод - в каждом случае сделать вызов метода равным <code>newStory</code>, при этом каждый раз, когда он вызывается, <code>newStory</code> делается равным самому себе, но с выполненными заменами. Поэтому каждый раз, когда нажимается кнопка, эти заполнители заменяются случайной строкой. Подсказка: рассматриваемый метод заменяет только первый экземпляр найденной подстроки, поэтому вам, возможно, придется сделать один из вызовов дважды.</li> + <li>Внутри первого блока <code>if</code> добавьте другой метод замены строки, чтобы заменить имя «Боб», найденное в строке <code>newStory</code>, с помощью переменной <code>name</code>. В этом блоке мы говорим: «Если значение введено в текстовый ввод <code>customName</code>, замените Боба в истории этим пользовательским именем».</li> + <li>Внутри второго блока <code>if</code> мы проверяем, была ли выбрана радиокнопка <code>uk</code>. Если это так, мы хотим преобразовать значения веса и температуры в историю из фунтов и Фаренгейта в метры и по Цельсию. Что вам нужно сделать, так это: + <ol> + <li>Посмотрите формулу преобразования фунтов в стоуны и Фаренгейта в по Цельсию.</li> + <li>Внутри линии, которая определяет <code>weight</code> переменную, замените 300 на расчет, который преобразует 300 фунтов в стоуны. Добавьте <code>'stone'</code> в конце результата общего вызова <code>Math.round()</code>.</li> + <li>Внутри линии, определяющей <code>temperature</code> переменную, замените 94 на расчет, который преобразует 94 градуса по Фаренгейту в по Цельсию. Добавьте <code>'centigrade'</code> в конце результата общего вызова <code>Math.round()</code>.</li> + <li>Просто под двумя определениями переменных добавьте еще две строки замены строк, которые заменяют «94 farenheit» на содержимое переменной <code>temperature</code> и«300 pounds» на содержимое <code>weight</code> переменной.</li> + </ol> + </li> + <li>Наконец, в предпоследней строке функции сделайте свойство <code>textContent</code> переменной <code>story</code> (которая ссылается на абзац) равным <code>newStory</code>.</li> +</ol> + +<h2 id="Советы_и_подсказки">Советы и подсказки</h2> + +<ul> + <li>Вам не нужно каким-либо образом редактировать HTML, кроме как применять JavaScript к вашему HTML.</li> + <li>Если вы не уверены, правильно ли применяется JavaScript для вашего HTML-кода, попробуйте временно удалить все остальное из файла JavaScript, добавив в него простой кусочек JavaScript, который, как вы знаете, создаст очевидный эффект, а затем сохраните и обновите. Следующий, например, делает фон элемента {{htmlelement ("html")}} красного цвета - поэтому все окно браузера должно быть красным, если JavaScript применяется правильно: + <pre class="brush: js notranslate">document.querySelector('html').style.backgroundColor = 'red';</pre> + </li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round">Math.round()</a> - это встроенный метод JavaScript, который просто округляет результат вычисления до ближайшего целого числа.</li> +</ul> + +<h2 id="Оценка_и_помощь">Оценка и помощь</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Если вы хотите, чтобы ваша работа была оценена, или застряли и хотите обратиться за помощью:</span></span></p> + +<ol> + <li>Разместите свою работу в онлайн-редакторе, таком как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle </a>или <a href="https://glitch.com/">Glitch</a>.</li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Напишите сообщение с просьбой об оценке и / или помощи на форуме <a href="https://discourse.mozilla.org/c/mdn">MDN Discourse</a>.</span> <span title="">Добавьте тег «learning» к своему сообщению, чтобы мы могли легче его найти.</span> <span title="">Ваш пост должен включать:</span></span> + <ul> + <li><span class="tlid-translation translation" lang="ru"><span title="">Описательное название, такое как «Требуется оценка для генератора глупых историй».</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Подробная информация о том, что вы хотели бы, чтобы мы делали, например, что вы уже пробовали, если вы застряли и нуждаетесь в помощи.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Ссылка на пример, который вы хотите оценить или нуждаетесь в помощи, в онлайн-редакторе.</span> <span title="">Это хорошая практика - очень сложно помочь кому-то с проблемой кодирования, если вы не видите его код.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Ссылка на актуальную задачу или страницу оценки, чтобы мы могли найти вопрос, с которым вы хотите помочь.</span></span></li> + </ul> + </li> +</ol> + +<p>{{PreviousMenu("Learn/JavaScript/Первые_шаги/Arrays", "Learn/JavaScript/Первые_шаги")}}</p> diff --git a/files/ru/learn/javascript/первые_шаги/строки/index.html b/files/ru/learn/javascript/первые_шаги/строки/index.html new file mode 100644 index 0000000000..583e29182e --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/строки/index.html @@ -0,0 +1,284 @@ +--- +title: Работа с текстом — строки в JavaScript +slug: Learn/JavaScript/Первые_шаги/Строки +translation_of: Learn/JavaScript/First_steps/Strings +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Math", "Learn/JavaScript/Первые_шаги/Useful_string_methods", "Learn/JavaScript/Первые_шаги")}}</div> + +<p class="summary">Теперь мы обратим внимание на строки — в программировании так называют части текста. В этой статье мы рассмотрим все распростанённые вещи, которые вы должны действительно знать о строках при изучении JavaScript, например, создание строк, <span id="result_box" lang="ru"><span>экранирование кавычек в строках и объединение строк вместе.</span></span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS, понимание что такое JavaScript.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td><span class="short_text" id="result_box" lang="ru"><span>Знакомство с основами строк в JavaScript.</span></span></td> + </tr> + </tbody> +</table> + +<h2 id="Сила_слов">Сила слов</h2> + +<p><span id="result_box" lang="ru"><span>Слова очень важны для людей </span></span>—<span lang="ru"><span> это основа нашего общения.</span></span> <span class="short_text" id="result_box" lang="ru"><span>Интернет</span></span> <span id="result_box" lang="ru"><span>представляет собой преимущественно текстовую среду, предназначенную для</span></span> того что бы люди общались и делились информацией, поэтому <span id="result_box" lang="ru"><span>нам полезно иметь контроль над словами, которые появляются в нем.</span></span> {{glossary ("HTML")}} предоставляет визуальную и смысловую структуру для нашего текста, {{glossary ("CSS")}} позволяет нам стилизовать его, а JavaScript содержит ряд функций для управления строками, создания пользовательских приветственных сообщений, при необходимости отображая нужные текстовые метки, сортируя элементы в желаемом порядке и многое другое.</p> + +<p>Практически во всех программах, которые мы показали вам на данный момент, были задействованы некоторые манипуляции со строками.</p> + +<h2 id="Строки_—_основы">Строки — основы</h2> + +<p>С первого взгляда строки обрабатываются аналогично числам, но если копнуть глубже, вы увидите некоторые заметные отличия. Давайте начнем с ввода некоторых основных строк в консоль, чтобы ознакомиться с ними. Мы предоставили одну ниже (вы также можете <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">открыть эту консоль</a> в отдельной вкладке или окне или использовать <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">консоль разработчика браузера</a>, если хотите).</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + if(document.querySelectorAll('div').length > 1) { + inputForm.focus(); + } + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<h3 id="Создание_строки">Создание строки</h3> + +<ol> + <li>Для начала введите следующие строки: + <pre class="brush: js notranslate">var string = 'The revolution will not be televised.'; +string;</pre> + </li> + <li>Как и в случае с числами, мы объявляем переменную, инициализируя ее строковым значением, а затем возвращаем значение. Единственное различие здесь в том, что при написании строки вам нужно окружить значение кавычками. </li> + <li>Если вы не сделаете этого или пропустите одну из кавычек, вы получите сообщение об ошибке. Попробуйте ввести следующие строки: + <pre class="brush: js example-bad notranslate">var badString = This is a test; +var badString = 'This is a test; +var badString = This is a test';</pre> + Эти строки не работают, потому что любая текстовая строка без кавычек считается именем переменной, именем свойства, зарезервированным словом или чем-то подобным. Если браузер не может найти его, возникает ошибка (например, «missing, before statement»). Если браузер может видеть, где начинается строка, но не может найти конец строки, как указано во 2-й строке, она жалуется на ошибку (с «unterminated string literal»). Если ваша программа выявляет такие ошибки, вернитесь назад и проверьте все свои строки, чтобы убедиться, что у вас нет пропущенных кавычек.</li> + <li>Следующий код будет выполнен только в том случае, если ранее была объявлена переменная <code>string</code> — убедитесь сами: + <pre class="brush: js notranslate">var badString = string; +badString;</pre> + В настоящее время строка <code>badString</code> имеет то же значение, что и строка <code>string</code>.</li> +</ol> + +<h3 id="Одиночные_кавычки_vs._Двойные_кавычки">Одиночные кавычки vs. Двойные кавычки</h3> + +<ol> + <li>В JavaScript вы можете выбрать одинарные кавычки или двойные кавычки, чтобы обернуть ваши строки. Оба варианта будут работать нормально: + <pre class="brush: js notranslate">var sgl = 'Single quotes.'; +var dbl = "Double quotes"; +sgl; +dbl;</pre> + </li> + <li>Существует очень мало различий между одиночными и двойными кавычками, и решение какие из них использовать в коде остается на ваше усмотрение. Однако вы должны выбрать один вариант и придерживаться его, иначе ваш код может выдать ошибку, особенно если вы используете разные кавычки в одной строке! Ниже приведен пример: + <pre class="brush: js example-bad notranslate">var badQuotes = 'What on earth?";</pre> + </li> + <li>Браузер будет считать, что строка не была закрыта, потому что в строке может появиться другой тип цитаты, который вы не используете, чтобы хранить ваши строки в переменных. Из примера можно понять, о чем идет речь (в коде ошибок нет): + <pre class="brush: js notranslate">var sglDbl = 'Would you eat a "fish supper"?'; +var dblSgl = "I'm feeling blue."; +sglDbl; +dblSgl;</pre> + </li> + <li>Однако вы не можете включить один и тот же знак кавычки внутри строки, если он используется для их хранения. Ниже приведена ошибка, браузер ошибочно определяет место, где строка кончается: + <pre class="brush: js example-bad notranslate">var bigmouth = 'I've got no right to take my place...';</pre> + Что приводит нас к следующей теме.</li> +</ol> + +<h3 id="Экранирование_кавычек_в_строках">Экранирование кавычек в строках</h3> + +<p>Чтобы исправить нашу предыдущую строку кода, нам нужно дать понять браузеру, что кавычка в середине строки не является меткой ее конца. Экранирование символов означает, что мы делаем что-то с ними, чтобы убедиться, что они распознаются как текст, а не часть кода. В JavaScript мы делаем это, помещая обратную косую черту непосредственно перед символом. Введите эти строки:</p> + +<pre class="brush: js notranslate">var bigmouth = 'I\'ve got no right to take my place...'; +bigmouth;</pre> + +<p>Так лучше. Таким же образом можно экранировать и другие символы, например <code>"\</code>. Кроме того существуют специальные коды. Для дополнительной информации см. <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation">Escape notation</a>.</p> + +<h2 id="Конкатенация_строк">Конкатенация строк</h2> + +<ol> + <li>Конкатенация — это новомодное программистское слово, которое означает «объединить». Объединение строк в JavaScript использует оператор плюс (+), тот же, который мы используем для сложения чисел, но в этом контексте он делает кое-что другое. Попробуем пример в нашей консоли.</li> + <li> + <pre class="brush: js notranslate">var one = 'Hello, '; +var two = 'how are you?'; +var joined = one + two; +joined;</pre> + Результат этой программы - это переменная <code>joined</code>, содержащая значение "Hello, how are you?".</li> + <li>В последнем случае мы просто объединим две строки вместе, но на самом деле, вы можете объединить столько строк, сколько хотите, до тех пор, пока вы ставите <code>+</code> между ними. Попробуйте это: + <pre class="brush: js notranslate">var multiple = one + one + one + one + two; +multiple;</pre> + </li> + <li>Вы также можете использовать сочетание переменных и фактических строк. Попробуйте это: + <pre class="brush: js notranslate">var response = one + 'I am fine — ' + two; +response;</pre> + </li> +</ol> + +<div class="note"> +<p><strong>Примечание: </strong>Когда вы вводите фактическую строку в свой код, заключенную в одинарные или двойные кавычки, она называется <strong>строковым литералом.</strong></p> +</div> + +<h3 id="Конкатенация_строк_в_контексте">Конкатенация строк в контексте</h3> + +<p>Давайте посмотрим на конкатенацию строк в действии — вот пример из предыдущего курса:</p> + +<pre class="brush: html notranslate"><button>Press me</button></pre> + +<pre class="brush: js notranslate">var button = document.querySelector('button'); + +button.onclick = function() { + var name = prompt('What is your name?'); + alert('Hello ' + name + ', nice to see you!'); +}</pre> + +<p>{{ EmbedLiveSample('Concatenation_in_context', '100%', 50) }}</p> + +<p>Здесь мы используем функцию {{domxref ("Window.prompt ()", "Window.prompt ()")}} в строке 4, которая просит пользователя ответить на вопрос через всплывающее диалоговое окно, а затем сохраняет введенный текст внутри заданной переменной — в этом случае <code><strong>name</strong></code>. Затем мы используем функцию {{domxref ("Window.alert ()", "Window.alert ()")}} в строке 5 для отображения другого всплывающего окна, содержащего строку, которую мы собрали из двух строковых литералов и переменной <code>name</code>.</p> + +<h3 id="Числа_vs._строки">Числа vs. строки</h3> + +<ol> + <li>Итак, что происходит, когда мы пытаемся добавить (или конкатенировать) строку и число? Попробуем это в нашей консоли: + <pre class="brush: js notranslate">'Front ' + 242; +</pre> + Вы можете ожидать, что это вызовет ошибку, но все работает отлично. Попытка представить строку как число на самом деле не имеет смысла, но число как строку — имеет, поэтому браузер довольно умно преобразует число в строку и объединяет две строки вместе.</li> + <li>Вы даже можете сделать это с двумя числами, вы можете заставить число стать строкой, обернув ее в кавычки. Попробуйте следующее (мы используем оператор <code>typeof</code> для того, чтобы установить является ли переменная числом или строкой): + <pre class="brush: js notranslate">var myDate = '19' + '67'; +typeof myDate;</pre> + </li> + <li>Если у вас есть числовая переменная, которую вы хотите преобразовать в строчную без внесения каких-либо иных изменений или строковую переменную, которую вы хотите преобразовать в число, вы можете использовать следующие две конструкции: + <ul> + <li>Объект {{jsxref ("Number")}} преобразует всё переданное в него в число, если это возможно. Попробуйте следующее: + <pre class="brush: js notranslate">var myString = '123'; +var myNum = Number(myString); +typeof myNum;</pre> + </li> + <li>С другой стороны, каждое число имеет метод, называемый <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString">toString()</a></code>, который преобразует его в эквивалентную строку. Попробуй это: + <pre class="brush: js notranslate">var myNum = 123; +var myString = myNum.toString(); +typeof myString;</pre> + </li> + </ul> + Эти конструкции могут быть действительно полезны в некоторых ситуациях. Например, если пользователь вводит число в текстовое поле формы, данные будут распознаны как строка. Однако, если вы хотите добавить это число к чему-то, вам понадобится его значение, поэтому вы можете передать его через <code>Number()</code>, чтобы справиться с этим. Именно это мы сделали в нашей <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game.html#L63">Number Guessing Game, </a>в строке 61.</li> +</ol> + +<h2 id="Заключение">Заключение</h2> + +<p>Итак, это основы строк, используемых в JavaScript. В следующей статье мы рассмотрим некоторые из встроенных методов, доступных для строк в JavaScript и то, как мы можем использовать их для управления нашими строками только в той форме, в которой мы хотим.</p> + +<div>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/Math", "Learn/JavaScript/Первые_шаги/Useful_string_methods", "Learn/JavaScript/Первые_шаги")}}</div> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">What is JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">A first splash into JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">Storing the information you need — Variables</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">Basic math in JavaScript — numbers and operators</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">Handling text — strings in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">Assessment: Silly story generator</a></li> +</ul> diff --git a/files/ru/learn/javascript/первые_шаги/что_пошло_не_так/index.html b/files/ru/learn/javascript/первые_шаги/что_пошло_не_так/index.html new file mode 100644 index 0000000000..dbb0a4577a --- /dev/null +++ b/files/ru/learn/javascript/первые_шаги/что_пошло_не_так/index.html @@ -0,0 +1,249 @@ +--- +title: Что пошло не так? Устранение ошибок JavaScript +slug: Learn/JavaScript/Первые_шаги/Что_пошло_не_так +translation_of: Learn/JavaScript/First_steps/What_went_wrong +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/A_first_splash", "Learn/JavaScript/Первые_шаги/Variables", "Learn/JavaScript/Первые_шаги")}}</div> + +<p class="summary">Когда вы создали игру «Угадай номер» в предыдущей статье, вы, возможно, обнаружили, что она не работает. Не бойтесь — эта статья призвана избавить вас от разрыва волос над такими проблемами, предоставив вам несколько простых советов о том, как найти и исправить ошибки в программах JavaScript.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row"> + <p>Нужно:</p> + </th> + <td>базовая компьютерная грамотность, базовое понимание HTML и CSS, понимание того, что такое JavaScript.</td> + </tr> + <tr> + <th scope="row">Цель</th> + <td>получить способность и уверенность в том, чтобы приступить к исправлению простых проблем в вашем собственном коде.</td> + </tr> + </tbody> +</table> + +<h2 id="Типы_ошибок">Типы ошибок</h2> + +<p>Когда вы делаете что-то не так в коде, есть два основных типа ошибок, с которыми вы столкнетесь:</p> + +<ul> + <li> + <p><strong>Синтаксические ошибки:</strong> Это орфографические ошибки в коде, которые фактически заставляют программу вообще не запускаться, или перестать работать на полпути — вам также будут предоставлены некоторые сообщения об ошибках. Обычно они подходят для исправления, если вы знакомы с правильными инструментами и знаете, что означают сообщения об ошибках!</p> + </li> + <li><strong>Логические ошибки:</strong> Это ошибки, когда синтаксис действительно правильный, но код не тот, каким вы его предполагали, что означает, что программа работает успешно, но дает неверные результаты. Их часто сложнее находить, чем синтаксические ошибки, так как обычно не возникает сообщение об ошибке, которое направляет вас к источнику ошибки.</li> +</ul> + +<p>Ладно, все <em>не так</em> просто — есть и другие отличия, которые вы поймете, пока будете изучать язык JavaScript глубже. Однако вышеуказанной классификации достаточно на раннем этапе вашей карьеры. Мы рассмотрим оба эти типа в дальнейшем.</p> + +<h2 id="Ошибочный_пример">Ошибочный пример</h2> + +<p>Чтобы начать работу, давайте вернемся к нашей игре с угадыванием чисел — за исключением того, что мы будем изучать версию с некоторыми преднамеренными ошибками. Перейдите в Github и сделайте себе локальную копию <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html">number-game-errors.html</a> (см. здесь <a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html">как это работает</a>).</p> + +<ol> + <li>Чтобы начать работу, откройте локальную копию внутри вашего любимого текстового редактора и вашего браузера.</li> + <li>Попробуйте сыграть в игру — вы заметите, что когда вы нажимаете кнопку «Submit guess», она не работает!</li> +</ol> + +<div class="note"> +<p><strong>Примечание:</strong> Возможно, у вас может быть собственная версия игрового примера, которая не работает, которую вы можете исправить! Мы по-прежнему хотели бы, чтобы вы работали над статьей с нашей версией, чтобы вы могли изучать методы, которые мы здесь преподаем. Затем вы можете вернуться и попытаться исправить ваш пример.</p> +</div> + +<p>На этом этапе давайте рассмотрим консоль разработчика, чтобы увидеть, можем ли мы видеть какие-либо синтаксические ошибки, а затем попытаемся их исправить. Вы узнаете, как это сделать, ниже.</p> + +<h2 id="Исправление_синтаксических_ошибок">Исправление синтаксических ошибок</h2> + +<p>Раньше в курсе мы заставили вас набрать некоторые простые команды JavaScript в <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">консоль разработчика JavaScript</a> (если вы не можете вспомнить, как открыть это в своем браузере, следуйте предыдущей ссылке, чтобы узнать, как это сделать). Что еще более полезно, так это то, что консоль предоставляет вам сообщения об ошибках всякий раз, когда существует синтаксическая ошибка внутри JavaScript, которая подается в механизм JavaScript браузера. Теперь пойдем на охоту.</p> + +<ol> + <li>Перейдите на вкладку, в которой у вас есть number-game-errors.html, и откройте консоль JavaScript. Вы должны увидеть сообщение об ошибке в следующих строках: <img alt="" src="https://mdn.mozillademos.org/files/13496/not-a-function.png" style="display: block; margin: 0 auto;"></li> + <li>Это довольно простая ошибка для отслеживания, и браузер дает вам несколько полезных бит информации, которые помогут вам (скриншот выше от Firefox, но другие браузеры предоставляют аналогичную информацию). Слева направо, у нас есть: + <ul> + <li>Красный «x» означает, что это ошибка.</li> + <li>Сообщение об ошибке, указывающее, что пошло не так: «TypeError: guessSubmit.addeventListener не является функцией»</li> + <li>Ссылка «Узнать больше», которая ссылается на страницу MDN, которая объясняет, что эта ошибка означает в огромных количествах деталей.</li> + <li>Имя файла JavaScript, который ссылается на вкладку «Отладчик» консоли разработчика. Если вы перейдете по этой ссылке, вы увидите точную строку, где подсвечивается ошибка.</li> + <li>Номер строки, в которой находится ошибка, и номер символа в этой строке, где первая ошибка. В этом случае у нас есть строка 86, символ номер 3.</li> + </ul> + </li> + <li>Если мы посмотрим на строку 86 в нашем редакторе кода, мы найдем эту строку: + <pre class="brush: js"><font><font>guessSubmit.addeventListener('click', checkGuess);</font></font></pre> + </li> + <li>В сообщении об ошибке говорится, что «guessSubmit.addeventListener не является функцией», поэтому мы, вероятно, где-то ошиблись. Если вы не уверены в правильности написания синтаксиса, часто бывает полезно найти функцию на MDN. Лучший способ сделать это в настоящее время — поиск «mdn <em>имя-функции</em>» в вашей любимой поисковой системе. Вот ссылка, которая поможет сократить вам некоторое время в данном случае: <code><a href="/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>.</li> + <li>Итак, глядя на эту страницу, кажется, что ошибка в том, что мы неправильно назвали имя функции! Помните, что JavaScript чувствителен к регистру, поэтому любые незначительные отличия в орфографии или регистре текста могут вызвать ошибку. Изменение этого параметра в addEventListener должно быть исправлено. Сделайте это сейчас.</li> +</ol> + +<div class="note"> +<p><strong>Примечание: </strong>См. наш <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_a_function">TypeError: «x»</a> не является справочной страницей функций для получения дополнительной информации об этой ошибке.</p> +</div> + +<h3 id="Синтаксические_ошибки_второй_раунд">Синтаксические ошибки: второй раунд</h3> + +<div class="note"> +<p><strong>Примечание</strong>: <code><a href="/en-US/docs/Web/API/Console/log">console.log()</a></code> это часто используемая функция отладки, которая выводит значение в консоль. Поэтому она будет выводить значение <code>lowOrHi</code> в консоли, как только мы попытаемся установить его в строке 48.</p> +</div> + +<ol> + <li>Сохраните и обновите страницу, и вы увидите, что ошибка исчезла.</li> + <li>Теперь, если вы попробуете ввести значение и нажать кнопку "Submit guess", вы увидите ... другую ошибку! <img alt="" src="https://mdn.mozillademos.org/files/13498/variable-is-null.png" style="display: block; margin: 0 auto;"></li> + <li>На этот раз сообщается об ошибке: "TypeError: lowOrHi is null", в строке 78. + <div class="note"><strong>Примечание</strong>: <code><a href="/en-US/docs/Glossary/Null">Null</a></code> — это специальное значение, которое означает "ничего" или "не значение". Поэтому <code>lowOrHi</code> был объявлен и инициализирован без значения — у него нет типа или значения.</div> + + <div class="note"><strong>Примечание</strong>: Эта ошибка не появилась, как только страница была загружена, потому что эта ошибка произошла внутри функции (внутри <code>checkGuess() { ... }</code> block). Об этом вы узнаете более подробно в нашей более поздней статье о функциях, код внутри функций выполняется в отдельной области для кода внешних функций. В этом случае код не был запущен, и ошибка не была брошена до тех пор, пока функция <code>checkGuess()</code> не была запущена строкой 86.</div> + </li> + <li>Посмотрите на строку 78, и вы увидите следующий код: + <pre class="brush: js"><font><font>lowOrHi.textContent = «Последнее предположение было слишком высоко!»;</font></font></pre> + </li> + <li>Эта строка пытается установить свойство <code>textContent</code> переменной <code>lowOrHi</code> как текстовую строку, но это не работает, поскольку <code>lowOrHi</code> не содержит того, что должна. Давайте посмотрим, почему так происходит — попробуйте найти другие экземпляры <code>lowOrHi</code> в коде. Самый ранний экземпляр, который вы найдете в JavaScript, находится в строке 48: + <pre class="brush: js"><font><font>var lowOrHi = document.querySelector('lowOrHi');</font></font></pre> + </li> + <li>На этом этапе мы пытаемся заставить переменную содержать ссылку на элемент документа HTML. Давайте проверим, является ли значение <code>null</code> после выполнения этой строки. Добавьте следующий код в строку 49: + <pre class="brush: js">console.log(lowOrHi); +</pre> + </li> + <li>Сохраните и обновите, и вы должны увидеть результат работы <code>console.log()</code> в консоли браузера. <img alt="" src="https://mdn.mozillademos.org/files/13494/console-log-output.png" style="display: block; margin: 0 auto;"> Разумеется, значение <code>lowOrHi</code> на данный момент равно <code>null</code>, поэтому определенно существует проблема в строке 48.</li> + <li>Давайте подумаем о том, что может быть проблемой. Строка 48 использует метод <code><a href="/en-US/docs/Web/API/Document/querySelector">document.querySelector()</a></code> для получения ссылки на элемент, выбирая его с помощью селектора CSS. Посмотрев далее наш файл, мы можем найти обсуждаемый элемент <code><p></code>: + <pre class="brush: js"><p class="lowOrHi"></p> +</pre> + </li> + <li>Поэтому нам нужен селектор классов, который начинается с точки (.), но селектор, передаваемый в метод <code>querySelector()</code> в строке 48, не имеет точки. Возможно, это и есть проблема! Попробуйте изменить <code>lowOrHi</code> на <code>.lowOrHi</code> в строке 48.</li> + <li>Повторите попытку сохранения и обновления, и ваш вызов <code>console.log()</code> должен вернуть элемент <code><p></code>, который мы хотим. Уф! Еще одна ошибка исправлена! Вы можете удалить строку с <code>console.log()</code> сейчас, или оставить для дальнейшего применения — выбирайте сами.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Загляните на справочную страницу <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_type">TypeError: "x" is (not) "y"</a>, чтобы узнать больше об этой ошибке.</p> +</div> + +<h3 id="Синтаксические_ошибки_третий_раунд">Синтаксические ошибки: третий раунд</h3> + +<ol> + <li>Теперь, если вы снова попробуете сыграть в игру, вы должны добиться большего успеха — игра должна играть абсолютно нормально, пока вы не закончите игру, либо угадав нужное число, либо потеряв жизни.</li> + <li>На данном этапе игра снова слетает, и выводится такая же ошибка, как и в начале — "TypeError: resetButton.addeventListener is not a function"! Однако, теперь она происходит из-за строки 94.</li> + <li>Посмотрев на строку 94, легко видеть, что здесь сделана такая же ошибка. Нам просто нужно изменить <code>addeventListener</code> на <code>addEventListener</code>.</li> +</ol> + +<h2 id="Логическая_ошибка">Логическая ошибка</h2> + +<p>На этом этапе игра должна проходить отлично, однако, поиграв несколько раз, вы, несомненно заметите, что случайное число, которое вы должны угадать, всегда 0 или 1. Определенно не совсем так, как мы хотим, чтобы игра была разыграна!</p> + +<p>Безусловно, где-то в игре есть логическая ошибка — игра не возвращает ошибку, она просто работает неправильно.</p> + +<ol> + <li>Найдем переменную <code>randomNumber</code> , и строку где в первый раз устанавливали случайное число. Пример, в котором мы храним случайное число, которое должны угадать, на строке 44: + + <pre class="brush: js">var randomNumber = Math.floor(Math.random()) + 1; +</pre> + И на строке 113, где мы генерируем случайное число, каждый раз после окончания игры: + + <pre class="brush: js">randomNumber = Math.floor(Math.random()) + 1; +</pre> + </li> + <li>Чтобы проверить, действительно ли проблема в этом, давайте обратимся к нашему другу <code>console.log()</code> снова — вставьте ее ниже строк с ошибками: + <pre class="brush: js">console.log(randomNumber); +</pre> + </li> + <li>Сохраните и обновите, а дальше попробуйте пару раз сыграть — в консоли вы увидите что <code>randomNumber</code> равна 1 в каждой точке, где вы ее записали после строк с ошибками.</li> +</ol> + +<h3 id="Работаем_через_логику">Работаем через логику</h3> + +<p>Чтобы исправить это, давайте рассмотрим как работает строка. Первое, мы вызываем <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a></code>, котрый генерирует случайное десятичное число, между 0 и 1, например 0.5675493843.</p> + +<pre class="brush: js"><font><font>Math.random()</font></font></pre> + +<p>Дальше, мы передаем результат вызова <code>Math.random()</code> через <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor">Math.floor()</a></code>, который округляет число вниз, до ближайшего целого числа. Затем мы добавляем 1 к данному результату:</p> + +<pre><font><font>Math.floor(Math.random()) + 1;</font></font></pre> + +<p>Округление случайного десятичного числа к меньшему, всегда будет возвращать 0, так что добавление к нему единицы будет возвращать всегда 1. Нам нужно умножить случайное число на 100, прежде чем мы округлим его к меньшему. Следующая строка вернет нам случайное число между 0 и 99:</p> + +<pre class="brush: js"><font><font>Math.floor(Math.random() * 100);</font></font></pre> + +<p>поэтому нам нужно добавить 1, чтоб нам возвращалось случайное число между 1 и 100:</p> + +<pre class="brush: js"><font><font>Math.floor(Math.random() * 100) + 1;</font></font></pre> + +<p>А теперь, исправьте обе строки с ошибками, затем сохраните и обновите, игра должна работать так, как мы и планировали!</p> + +<h2 id="Другие_распространенные_ошибки">Другие распространенные ошибки</h2> + +<p>Существуют и другие распространенные ошибки, которые вы обнаружите в своем коде. В этом разделе показано большинство из них.</p> + +<h3 id="SyntaxError_отсутствует_перед_постановкой"><font><font>SyntaxError: отсутствует ; </font><font>перед постановкой</font></font></h3> + +<p>Эта ошибка обычно означает что вы упустили точку с запятой в конце одной из ваших строк кода, но иногда ошибка может быть более загадочной. Например, если мы изменим эту строку внутри функции <code>checkGuess()</code> :</p> + +<pre class="brush: js"><font><font>var userGuess = Number(guessField.value);</font></font></pre> + +<p>на эту</p> + +<pre class="brush: js"><font><font>var userGuess === Number(guessField.value);</font></font></pre> + +<p>Это вызовет данную ошибку, потому что браузер подумает, что вы пытались сделать что-то другое. Вы должны быть уверены, что вы не перепутали оператор присваивания (<code>=</code>), который присваивает значение переменной — с оператором сравнения (<code>===</code>), который строго сравнивает операнды, и возвращает <code>true</code>/<code>false</code> .</p> + +<div class="note"> +<p><strong>Примечание</strong>: Загляните на справочную страницу <a href="/ru/docs/Web/JavaScript/Reference/Errors/Missing_semicolon_before_statement">Синтаксическая ошибка: пропущен символ ; до объявления инструкции</a> для получения дополнительной информации об этой ошибке.</p> +</div> + +<h3 id="В_программе_всегда_говорится_что_вы_выиграли_независимо_от_того_что_вы_ввели">В программе всегда говорится, что вы выиграли, независимо от того, что вы ввели</h3> + +<p>Причиной этому является все то же перепутывание оператора присваивания (<code>=</code>) со строгим сравнением (<code>===</code>). Например, если мы изменим внутри <code>checkGuess()</code> эту строку кода:</p> + +<pre class="brush: js"><font><font>if (userGuess === randomNumber) {</font></font></pre> + +<p>на эту</p> + +<pre class="brush: js"><font><font>if (userGuess = randomNumber) {</font></font></pre> + +<p>мы всегда будем получать <code>true</code>, заставляя программу сообщать, что игра была выиграна. Будьте осторожны!</p> + +<h3 id="SyntaxError_отсутствует_после_списка_аргументов"><font><font>SyntaxError: отсутствует ) после списка аргументов</font></font></h3> + +<p>Эта ошибка проста — обычно она означает, что вы пропустили закрывающую скобку с конца вызова функции / метода.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Загляните на справочную страницу <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Missing_parenthesis_after_argument_list">SyntaxError: missing ) after argument list</a> для получения дополнительной информации об этой ошибке.</p> +</div> + +<h3 id="SyntaxError_missing_after_property_id">SyntaxError: missing : after property id</h3> + +<p dir="ltr">Эта ошибка обычно связана с неправильно сформированным объектом JavaScript, но в этом случае нам удалось получить ее, изменив</p> + +<pre class="brush: js"><font><font>function checkGuess() {</font></font></pre> + +<p>на</p> + +<pre class="brush: js"><font><font>function checkGuess( { +</font></font></pre> + +<p dir="ltr" id="tw-target-text">Это заставило браузер думать, что мы пытаемся передать содержимое функции в функцию в качестве аргумента. Будьте осторожны с этими скобками!</p> + +<h3 id="SyntaxError_missing_after_function_body">SyntaxError: missing } after function body</h3> + +<p>Это легко — обычно это означает, что вы пропустили одну из ваших фигурных скобок из функции или условной структуры. Мы получили эту ошибку, удалив одну из закрывающих фигурных скобок возле нижней части функции <code>checkGuess()</code>.</p> + +<h3 id="SyntaxError_expected_expression_got_string_or_SyntaxError_unterminated_string_literal">SyntaxError: expected expression, got '<em>string</em>' or SyntaxError: unterminated string literal</h3> + +<p><font><font>Эти ошибки обычно означает, что вы пропустили открывающую или закрывающую кавычку для строковых значений. </font><font>В первой ошибки выше, </font></font><em><font><font>строка</font></font></em><font><font> будет заменена на неожиданный персонаж (ей) , </font><font>что браузер нашел вместо кавычек в начале строки. </font><font>Вторая ошибка означает , </font><font>что строка не закончилась кавычки.</font></font></p> + +<p>При всех этих ошибках действуйте так, как в наших примерах, которые мы рассмотрели в пошаговом руководстве. Когда возникает ошибка, посмотрите полученный номер строки, перейдите к этой строке и посмотрите, можете ли вы определить, что случилось. Имейте в виду, что ошибка не обязательно будет на этой строке, а также, что ошибка может быть вызвана не такой же проблемой, которую мы привели выше!</p> + +<div class="note"> +<p><strong><font><font>Примечание</font></font></strong><font><font> : Смотрите наш </font></font><a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_token"><font><font>SyntaxError: Неожиданный токен</font></font></a><font><font> и </font></font><a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unterminated_string_literal"><font><font>SyntaxError: незавершенная строка</font></font></a><font><font> эталонных страниц для получения </font><font>более подробной информации об этих ошибках.</font></font></p> +</div> + +<h2 id="Резюме"><font><font>Резюме</font></font></h2> + +<p>Итак, мы научились основам выяснения ошибок в простых программах JavaScript. Не всегда так просто разобраться, что не так в вашем коде, но, по крайней мере, это сэкономит вам несколько часов сна и позволит вам продвигаться немного быстрее, когда что-либо заработает не так, как ожидалось, в вашем учебном путешествии.</p> + +<h2 id="Смотрите_также"><font><font>Смотрите также</font></font></h2> + +<div> +<ul> + <li><font><font>Есть много других типов ошибок, которые не перечислены здесь; </font><font>мы составляем ссылку , </font><font>которая объясняет , </font><font>что они означают подробно - см. </font></font><a href="/en-US/docs/Web/JavaScript/Reference/Errors"><font><font>ссылку ошибки JavaScript</font></font></a><font><font> .</font></font></li> + <li><font><font>Если вы столкнетесь с любыми ошибками в коде, </font><font>которые вы не знаете , </font><font>как исправить после прочтения этой статьи, вы можете получить помощь! </font><font>Спросите на </font></font><a class="external external-icon" href="https://discourse.mozilla-community.org/t/learning-web-development-marking-guides-and-questions/16294"><font><font>нить обучения Область дискурсе</font></font></a><font><font> , или в </font></font><a href="irc://irc.mozilla.org/mdn"><font><font>#mdn</font></font></a><font><font> IRC канал на </font></font><a class="external external-icon" href="https://wiki.mozilla.org/IRC"><font><font>Mozilla IRC</font></font></a><font><font>. </font><font>Расскажите нам, какая</font><font> у вас ошибка, и мы постараемся вам помочь. </font><font>Приложите пример своего кода для большей ясности проблемы.</font></font></li> +</ul> +</div> + +<p>{{PreviousMenuNext("Learn/JavaScript/Первые_шаги/A_first_splash", "Learn/JavaScript/Первые_шаги/Variables", "Learn/JavaScript/Первые_шаги")}}</p> diff --git a/files/ru/learn/pages_sites_servers_and_search_engines/index.html b/files/ru/learn/pages_sites_servers_and_search_engines/index.html new file mode 100644 index 0000000000..0a9b7a643f --- /dev/null +++ b/files/ru/learn/pages_sites_servers_and_search_engines/index.html @@ -0,0 +1,118 @@ +--- +title: 'Веб-страницы, веб-сайты, веб серверы и поисковики' +slug: Learn/Pages_sites_servers_and_search_engines +tags: + - ActiveLearning + - Beginner + - WebMechanics + - Активное изучение + - Новичку + - Программисту +translation_of: Learn/Common_questions/Pages_sites_servers_and_search_engines +--- +<div class="summary"> +<p><span class="seoSummary">В этой статье мы расскажем о различных понятиях связанных с Веб: о веб-страницах, веб-сайтах, веб-серверах и о поисковых системах. Эти термины часто ставят в тупик как начинающих работу с Веб, так и людей, редко пользующихся сетью. Давайте же разберемся, что именно эти понятия означают!</span></p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Вы должны знать, <a href="/en-US/Learn/How_the_Internet_works">как работает Интернет</a>.</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Изучить различия между веб-страницами, веб-сайтами, веб-серверами и поисковыми системами.</td> + </tr> + </tbody> +</table> + +<h2 id="В_двух_словах">В двух словах</h2> + +<p>Как и любая другая область знаний, Веб полон специфичных терминов. Но не волнуйтесь, мы не хотим перегружать Вас в самом начале Вашего пути (а если любопытство всё же берёт верх, то у нас есть <a href="/ru/docs/MDN/Doc_status/Glossary">словарь</a>). Однако, для начала несколько базовых терминов всё же придётся усвоить, так как Вы будете встречать их в наших статьях довольно часто. Иногда эти термины легко перепутать, так как они связаны между собой, но имеют разные функции. Вы, наверное, не раз замечали их неправильное употребление в новостях или где-либо ещё.</p> + +<p>Мы разберём эти понятия и технологии чуть позже, а сейчас краткие определения ниже станут для Вас очень хорошим началом:</p> + +<dl> + <dt>Веб-страница</dt> + <dd>Документ, который может быть отображён веб-браузерами, такими как: Firefox, Google Chrome, Microsoft Internet Explorer / Edge или Safari от Apple. Само понятие "веб-страница" для краткости будем называть просто "страница".</dd> + <dt>Веб-сайт</dt> + <dd>Коллекция веб-страниц, связанных между собой какими-либо способами. Употребление в лексике: "веб-сайт" или просто "сайт".</dd> + <dt>Веб-сервер</dt> + <dd>Компьютер, предоставляющий компьютерное и программное обеспечение, необходимое для функционирования веб-сайта.</dd> + <dt>Поисковая система</dt> + <dd>Веб-сайт, помогающий в поиске других веб-страниц, например такие как: Google, Bing или Yahoo.</dd> +</dl> + +<h2 id="Активное_изучение">Активное изучение</h2> + +<p><em>Пока что активное изучение не доступно. Если Вы можете предоставить полезную информацию, то, <a href="https://developer.mozilla.org/en-US/docs/MDN/Getting_started">пожалуйста, окажите нам содействие</a>. </em></p> + +<h2 id="Погружаемся_глубже">Погружаемся глубже</h2> + +<p>Итак, давайте копнем чуть глубже и узнаем, как эти 4 термина связаны между собой, и почему данные понятия зачастую путают друг с другом.</p> + +<h3 id="Веб-страница">Веб-страница</h3> + +<p><strong>Веб-страница</strong> - простой документ, отображаемый на экране компьютера посредством <a href="https://ru.wikipedia.org/wiki/%D0%91%D1%80%D0%B0%D1%83%D0%B7%D0%B5%D1%80">браузера</a>. Такой документ написан языком <a href="https://ru.wikipedia.org/wiki/HTML">HTML</a> (который мы рассмотрим более детально <a href="https://developer.mozilla.org/en-US/docs/Web/HTML">в других статьях</a>). Веб-страница может содержать множество различных материалов, таких как:</p> + +<ul> + <li><em>стилевая информация</em> — контролирование страницы по восприятию и ощущению</li> + <li><em>скрипты </em>— которые делают страницу более динамичной и удобной в использовании для пользователей</li> + <li><em>медиа</em> — изображения, музыка и видео.</li> +</ul> + +<div class="note"> +<p><strong>Примечание: </strong>браузеры зачастую могут отображать некоторые документы в формате <a href="https://ru.wikipedia.org/wiki/Portable_Document_Format">PDF</a> файла или изображения, но термин <strong>веб-страница</strong> больше относится непосредственно к HTML-документам. До конца статьи, в данном случае, мы будем использовать понятие <strong>документ</strong>.</p> +</div> + +<p>Все веб-страницы в сети имеют свой уникальный адрес. Чтобы получить доступ к нужной странице просто наберите ее адрес в адресной строке Вашего браузера:</p> + +<p style="text-align: center;"><img alt="Example of a web page address in the browser address bar" src="https://mdn.mozillademos.org/files/8529/web-page.jpg" style="float: left; height: 239px; width: 650px;"></p> + + + + + + + + + + + + + +<p><em>Веб-сайт</em> - это коллекция страниц, связанных между собой какими-либо способами (включая их связи с иными ресурсами), которые доступны под единым доменным именем. Каждая страница сайта содержит прямые ссылки (практически всегда выделенные части текста, по которым можно кликнуть мышью), что позволяет пользователю быстро переходить от одной страницы веб-сайта к другой.</p> + +<p>Чтобы получить доступ к веб-сайту, наберите его доменное имя в адресной строке браузера, и Ваш браузер отобразит главную страницу сайта или, по-другому, домашнюю страницу:</p> + +<p><img alt="Example of a web site domain name in the browser address bar" src="https://mdn.mozillademos.org/files/8531/web-site.jpg" style="height: 365px; width: 650px;"></p> + +<p><em>Веб-страницу </em>и<em> веб-сайт </em>особенно легко спутать между собой, когда <em>сайт</em> содержит всего одну <em>страницу. </em>Такой сайт иногда называют <em>одностраничным веб-сайтом.</em></p> + +<h3 id="Веб-сервер">Веб-сервер</h3> + +<p><em>Веб-сервер</em> - это компьютер, предоставляющий в сеть один или множество <em>веб-сайтов (хостинг)</em>. Понятие "хостинг" - означает, что все <em>страницы </em>и прикрепленные к ним файлы содержатся на данном компьютере. Т.е. <em>Веб-сервер</em> будет отправлять любую <em>страницу</em> с <em>сайта</em> по запросу любого пользователя, что и будет хостингом для браузера пользователя.</p> + +<p>Не путайте понятия <em>веб-сайта</em> и <em>веб-сервера</em>. Например, если Вы слышите, что кто-либо говорит: "Мой веб-сайт не отвечает", на самом деле это означает, что это <em>веб-сервер</em> не отвечает на запрос, и поэтому недоступен и сам <em>сайт.</em> Более того, так как веб-сервер может разместить несколько сайтов, термин веб-сервер никогда не используется для обозначения веб-сайта, так как это могло бы привести к большой путанице. Вернемся к предыдущему примеру: если бы мы сказали: "Мой веб-сервер не отвечает", это значило бы, что на этом сервере нет доступных сайтов в данный момент.</p> + +<h3 id="Поисковая_система">Поисковая система</h3> + +<p><em>Поисковые системы</em> являются распространенной причиной путаницы в сети. <em>Поисковая система</em> - это специальный вид веб-сайта, который помогает пользователям найти нужные страницы <em>других</em> сайтов.</p> + +<p>Наиболее популярные поисковые системы: <a href="https://www.google.com/">Google</a>, <a href="https://www.bing.com/">Bing</a>, <a href="https://www.yandex.com/">Yandex</a>, <a href="https://duckduckgo.com/">DuckDuckGo</a>, и многие другие. Некоторые из них универсальны, а какие-то ориентированы на определенную область. Используйте тот поисковик, который удобен Вам.</p> + +<p>Многие начинающие пользователи сети путают между собой поисковую систему и браузер. Давайте поясним: <em><strong>браузер</strong></em> - это программное обеспечение, которое находит и отображает веб-страницы; <strong><em>поисковая система</em></strong> - это специальный вид сайта, который помогает пользователям найти нужные страницы <em>других</em> сайтов. Путаница возникает из-за того, что когда кто-либо впервые запускает браузер, тот отображает домашнюю страницу поисковой системы. Это именно так, ведь первое, что Вы делаете, запуская браузер, это находите веб-страницу и открываете ее. Но не путайте инфраструктуру (т.е. браузер) с сервисом (т.е. поисковой системой). Это отличие несколько поможет Вам, но даже некоторые специалисты произвольно употребляют данные понятия, так что из-за этого не следует особо переживать. </p> + +<p>Ниже пример того, как браузер Firerox по умолчанию отображает окно поиска Google на стартовой (домашней) странице:</p> + +<p><img alt="Example of Firefox nightly displaying a custom Google page as default" src="https://mdn.mozillademos.org/files/8533/search-engine.jpg" style="height: 399px; width: 650px;"></p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li>Погружаемся глубже: <a href="https://developer.mozilla.org/ru/docs/Learn/What_is_a_web_server">что такое Веб-сервер</a></li> + <li>Рассмотрим, как веб-страницы связаны с веб-сайтом: <a href="https://developer.mozilla.org/ru/docs/Learn/Understanding_links_on_the_web">Разбираемся с веб-ссылками</a></li> +</ul> diff --git a/files/ru/learn/performance/business_case_for_performance/index.html b/files/ru/learn/performance/business_case_for_performance/index.html new file mode 100644 index 0000000000..2d7ffc7203 --- /dev/null +++ b/files/ru/learn/performance/business_case_for_performance/index.html @@ -0,0 +1,82 @@ +--- +title: Производительность веб-приложений в бизнесе +slug: Learn/Performance/business_case_for_performance +translation_of: Learn/Performance/business_case_for_performance +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/Performance/Mobile", "Learn/Performance")}}</div> + +<p>{{draft}}</p> + +<p>Мы обсудили важность производительности веб-приложений. Вы изучили, что вам нужно для того, чтобы её оптимизировать. Но как убедить ваших клиентов и/или менеджмент в том, что нужно инвестировать в производительность? В этом разделе мы обсудим создание такой аргументации, чтобы ответственные за принятие решений менеджеры согласились на инвестиции.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимо:</th> + <td>Базовое понимание компьютерной терминологии, знание <a href="/en-US/docs/Learn/Getting_started_with_the_web">клиентской части веб-технологий</a>, понимание базовых принципов <a href="/en-US/docs/Web/Performance">оптимизации производительности</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td> + <p>Стать уверенным при объяснении клиентам и менедженту важности оптимизации производительности.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Делайте_производительность_приоритетом">Делайте производительность приоритетом</h2> + +<p>Мы уже обсудили, как приоритезация производительности может улучшить пользовательский опыт и доход компании. Мы также знаем, что игнорирование проблем производительности может привести к потери доходности. Эта статья объясняет, какие конкретные бизнес-показатели напрямую связаны с производительностью веб-приложений и как применить сервисное проектирование для улучшения пользовательского опыта. В статье подчеркивается важность понимания, как сумма всех небольших улучшений влияет на конверсию и удержание клиентов.</p> + +<dl> +</dl> + +<h3 id="Бюджеты_производительности">Бюджеты производительности</h3> + +<p>Установка бюджетов веб-производительности поможет вам быть уверенным в том, что команда придерживается верного пути и содержит приложение в хорошем состоянии. Бюджет производительности - это набор ограничний, которые, например, указывают максимальное количество HTTP запросов с клиента, максимальный размер всех ресурсов, минимально допустимую частоту кадров на конкретных устройствах и т.д. Бюджет может быть применён к определенному ресурсу, типу ресурсов, всем ресурсам на странице, конкретному показателю или пороговому показателю за какой-то период времени. Бюджет отражает достижимые цели, будь то время, количество или правило.</p> + +<p>Создание и продвижение бюджета помогает вам защищать интересы пользователя в борьбе с конкурирующими интересами: маркетингом, продажами или даже другими разработчиками, которые хотят добавить видео, сторонние скрипты или поиграться с новым фреймворком. Бюджеты помогают командам разраотчиков защищать оптимальную производительность для пользователей, в то время как бизнес может заниматься расширением рынков.</p> + +<h3 id="Ключевые_показатели"><strong>Ключевые показатели</strong></h3> + +<p>Установка ключевых показателей (Key Performance Indicators, KPI) целями может привести к тому, что цели производительности также станут целями бизнеса. KPI может быть одновременно и набором важных бизнес-показателей, которые объясняют влияние производительности на цели бизнеса, так и способом демонстрации преимущества такого подхода. Вот несколько примеров KPI:</p> + +<dl> + <dt><strong>Уровень конверсии </strong></dt> + <dd>Процент от общего траффика, который выполняет какое-то конкретное действие, например, покупает товар или подписывается на новости. Когда приложение работает медленно, пользователи не могут завершить эти задачи. Это приводит к низкому показателю конверсии.</dd> + <dt><strong>Время на сайте</strong></dt> + <dd>Среднее время, которое пользователь проводит на вашем сайте. Когда производительность низкая, высока вероятность того, что пользователи закроют сайт прежде, чем он выдаст нужные результаты.</dd> + <dt><strong>Уровень лояльности клиентов</strong></dt> + <dd>Этот показатель также называется "The net promoter score (NPS)". Он позволяет понять, будет ли пользователь рекомендовать ваш сервис / бизнес своим знакомым.</dd> +</dl> + +<p>Установка уровня конверсии, времени на сайте и/или уровня лояльности клиентов в виде KPI даёт другим департаментам наглядный пример того, зачем нужно тратить усилия на производительность.</p> + +<div class="hidden"> +<h2 id="Ожидание_и_реальность_в_производительности">Ожидание и реальность в производительности</h2> + +<p>Производительность бизнеса (в доходе, количестве транзакий и т.д.) напрямую связана с веб-производительностью.</p> + +<p>Зона конфликта - не заниматься производительностью, но ожидать хороших бизнес-показателей.</p> +</div> + +<div>{{PreviousMenu("Learn/Performance/Mobile", "Learn/Performance")}}</div> + +<h2 id="См._также">См. также:</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Performance/why_web_performance">The "why" of web performance</a></li> + <li><a href="/en-US/docs/Learn/Performance/What_is_web_performance">What is web performance?</a></li> + <li><a href="/en-US/docs/Learn/Performance/Perceived_performance">How do users perceive performance?</a></li> + <li><a href="/en-US/docs/Learn/Performance/Measuring_performance">Measuring performance</a></li> + <li><a href="/en-US/docs/Learn/Performance/Multimedia">Multimedia: images</a></li> + <li><a href="/en-US/docs/Learn/Performance/video">Multimedia: video</a></li> + <li><a href="/en-US/docs/Learn/Performance/JavaScript">JavaScript performance best practices</a>.</li> + <li><a href="/en-US/docs/Learn/Performance/HTML">HTML performance features</a></li> + <li><a href="/en-US/docs/Learn/Performance/CSS">CSS performance features</a></li> + <li><a href="/en-US/docs/Learn/Performance/Fonts">Fonts and performance</a></li> + <li><a href="/en-US/docs/Learn/Performance/Mobile">Mobile performance</a></li> + <li><a href="/en-US/docs/Learn/Performance/business_case_for_performance">Focusing on performance</a></li> +</ul> diff --git a/files/ru/learn/performance/index.html b/files/ru/learn/performance/index.html new file mode 100644 index 0000000000..74187cfbf7 --- /dev/null +++ b/files/ru/learn/performance/index.html @@ -0,0 +1,83 @@ +--- +title: Web performance +slug: Learn/Performance +tags: + - CSS + - HTML + - HTTP + - JavaScript + - Learn + - NeedsTranslation + - Performance + - TopicStub + - Web Performance +translation_of: Learn/Performance +--- +<p>{{LearnSidebar}}</p> + +<p class="summary">Для разработки веб-сайтов необходимы HTML, CSS и JavaScript. Чтобы создавать веб-сайты и приложения, которые люди хотят использовать, которые привлекают и удерживают пользователей, вам нужно создать ?? хороший пользовательский опыт. Частью такого пользовательского опыта является обеспечение быстрой загрузки контента и отзывчивости на взаимодействие с пользователем. Это известно как веб-performance, и в этом разделе вы сосредоточитесь на основах создания эффективных веб-сайтов.</p> + +<p class="summary">В наших учебных о<span>ставшихся частях учебного материала для новичков мы старались максимально придерживаться лучших практик Интернета, таких как performance и </span><a href="/en-US/docs/Learn/Accessibility">accessibility</a><span>, однако было бы хорошо сосредоточиться и на таких темах. Убедиться, что вы знакомы с ними.</span></p> + +<h2 id="Путь_Обучения">Путь Обучения</h2> + +<p>Хотя знание HTML, CSS и JavaScript необходимо для реализации многих рекомендаций по повышению производительности сети, знание того, как создавать приложения, не является необходимым предварительным условием для понимания и измерения perfomance сети. Однако мы рекомендуем, чтобы перед тем, как вы приступили к работе с этим модулем, вы получили хотя бы общее представление о веб-разработке, проработав наше <a href="/en-US/docs/Learn/Getting_started_with_the_web">Начало работы с сетью </a>модулем.</p> + +<p>Также было бы полезно углубиться в эти темы с помощью таких модулей, как:</p> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps">CSS первые шаги</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript первые шаги</a></li> +</ul> + +<p>После того, как вы проработаете этот модуль, вы, вероятно, захотите глубже изучить веб-производительность - вы можете найти много дополнительных учений в нашем <a href="/en-US/docs/Web/Performance">Раздел веб-производительности</a>, включая обзоры API performance, инструментов тестирования и анализа, а также ошибки, связанные с узкими местами performance. </p> + +<h2 id="Guides">Guides</h2> + +<p>This topic contains the following guides. The following is a suggested order for working through them; you should definitely start with the first one.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/Performance/why_web_performance">The "why" of web performance</a></dt> + <dd>This article discusses why web performance is important for accessibility, user experience and your business goals.</dd> + <dt><a href="/en-US/docs/Learn/Performance/What_is_web_performance">What is web performance?</a></dt> + <dd>You know web performance is important, but what is constitutes web performance? This article introduces the components of performance, from web page loading and rendering, including how your content makes it into your users browser to be viewed, to what groups of people we need to consider when thinking about performance,</dd> + <dt><a href="/en-US/docs/Learn/Performance/Perceived_performance">How do users perceive performance?</a></dt> + <dd>More important than how fast your website is in milliseconds, is how fast your users perceive your site to be. These perceptions are impacted by actual p<span>age load time, idling, responsiveness to user interaction, and the smoothness of scrolling and other animations. In this article, we discuss the various loading metrics, animation, and responsiveness metrics, along with best practices to improve user perception, if not the actual timings.</span></dd> +</dl> + +<dl> + <dt><a href="/en-US/docs/Learn/Performance/Measuring_performance">Measuring performance</a></dt> + <dd>Now that you understand a few performance metrics, we take a deeper dive into performance tools, metrics, and APIs and how we can make performance part of the web development workflow.</dd> + <dt><a href="/en-US/docs/Learn/Performance/Multimedia">Multimedia: images</a></dt> + <dd>The lowest hanging fruit of web performance is often media optimization. Serving different media files based on each user agent's capability, size, and pixel density is possible. In this article we discuss the impact images have on performance, and the methods to reduce the number of bytes sent per image.</dd> + <dt></dt> + <dt><a href="/en-US/docs/Learn/Performance/video">Multimedia: video</a></dt> + <dd>The lowest hanging fruit of web performance is often media optimization. In this article we discuss the impact video content has on performance, and cover tips like removing audio tracks from background videos can improve performance.</dd> + <dt><a href="/en-US/docs/Learn/Performance/JavaScript">JavaScript performance best practices</a></dt> + <dd>JavaScript, when used properly, can allow for interactive and immersive web experiences — or it can significantly harm download time, render time, in-app performance, battery life, and user experience. This article outlines some JavaScript best practices that should be considered to ensure even complex content is as performant as possible.</dd> + <dt><a href="/en-US/docs/Learn/Performance/HTML">HTML performance features</a></dt> + <dd>Some attributes and the source order of your mark-up can impact the performance or your website. By minimizing the number of DOM nodes, making sure the best order and attributes are used for including content such as styles, scripts, media, and third-party scripts, you can drastically improve the user experience. This article looks in detail at how HTML can be used to ensure maximum performance.</dd> + <dt><a href="/en-US/docs/Learn/Performance/CSS">CSS performance features</a></dt> + <dd>CSS may be a less important optimization focus for improved performance, but there are some CSS features that impact performance more than others. In this article we look at some CSS properties that impact performance and suggested ways of handling styles to ensure performance is not negatively impacted.</dd> + <dt><a href="/en-US/docs/Learn/Performance/Fonts">Fonts and performance</a></dt> + <dd>A look at whether you need to include external fonts and, if you do, how to include the fonts your design requires with the least impact on your sites performance. </dd> +</dl> + +<dl> + <dt><a href="/en-US/docs/Learn/Performance/Mobile">Mobile performance</a></dt> + <dd>With web access on mobile devices being so popular, and all mobile platforms having fully-fledged web browsers, but possibly limited bandwidth, CPU and battery life, it is important to consider the performance of your web content on these platforms. This article looks at mobile-specific performance considerations.</dd> + <dt><a href="/en-US/docs/Learn/Performance/business_case_for_performance">Focusing on performance</a></dt> + <dd>There are many different things a developer can do to improve performance, but how fast is fast enough? How can you convince powers that be of the importance of these efforts? Once optimized, how can you ensure bloat doesn't come back? In this article we look at convincing managements, developing a performance culture and performance budget, and introduce ways to ensure regressions don't sneak into your code base.</dd> +</dl> + +<h2 id="See_also">See also</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/Performance/Web_Performance_Basics">Web performance resources</a></dt> + <dd>In addition to the front end components of HTML, CSS, JavaScript, and media files, there are features that can make applications slower and features that can make applications subjectively and objectively faster. There are many APIs, developer tools, best practices, and bad practices relating to web performance. Here we'll introduce many of these features ad the basic level and provide links to deeper dives to improve performance for each topic.</dd> + <dt><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></dt> + <dd>In this article, we'll learn about the concept of responsive images — images that work well on devices with widely differing screen sizes, resolutions, and other such features — and look at what tools HTML provides to help implement them. This helps to improve performance across difference devices. Responsive images are just one part of <a href="/en-US/docs/Learn/CSS/CSS_layout/Responsive_Design">responsive design</a>, a future CSS topic for you to learn.</dd> + <dt><a href="/en-US/docs/Web/Performance">Main web performance section on MDN</a></dt> + <dd>Our main web performance section — here you'll find much more detail on web performance including overviews of performance APIs, testing and analysis tools, and performance bottleneck gotchas.</dd> +</dl> diff --git a/files/ru/learn/server-side/apache_configuration_htaccess/index.html b/files/ru/learn/server-side/apache_configuration_htaccess/index.html new file mode 100644 index 0000000000..fafabc17f8 --- /dev/null +++ b/files/ru/learn/server-side/apache_configuration_htaccess/index.html @@ -0,0 +1,38 @@ +--- +title: .htaccess ( hypertext access ) +slug: Learn/Server-side/Apache_Configuration_htaccess +translation_of: Learn/Server-side/Apache_Configuration_htaccess +--- +<p>Название .htaccess происходит от "hypertext access". Это файл с расширением HTACCESS, который содержит различные настройки сервера apache. Он позволяет настраивать для текущей директории защиту паролем, редиректы и многое другое.</p> + +<p><strong>Доступ к файлу</strong>: файл htaccess может быть открыт для редактивания любым текстовым редактором, таким как стандартный блокнот Windows, Vin, Sublime text editor или любым другим. Подсветка синтаксиса для файлов .htaccess встречается редко.</p> + +<h2 id="Применение">Применение</h2> + +<p><strong>Перенаправления</strong>: htaccess файлы часто используют для перенаправления трафика между веб-страницами, а также между разными доменами. Это простой и эффективный способ перенаправления трафика, так как перенаправление происходит до обработки запроса на стороне сервера. Перенаправление может быть временным и постоянным, с установкой соответствующего кода статуса.</p> + +<pre>Redirect 301 / http://example.com/ # Постоянное перенаправление на example.com +Redirect 302 / http://example.com/ # Временное перенаправление на example.com +</pre> + +<p><strong>Блокирование</strong>: htaccess также может блокировать доступ с определенного IP адреса или диапазопа IP адресов. Блокирование часто используется, чтобы запретить доступ к директории для различных ботов и поисковых пауков.</p> + +<pre>deny from 146.0.74.205 # Блокирует все запросы с адреса 146.0.74.205</pre> + +<p><strong>SSI или Server Side Include</strong> : С помощью файла .htaccess можно настроить автоматическое подключение файлов в документ. При каждом запросе пользователя, указанные файлы автоматически будут подключены в начало или в конец документа. При этом в самом документе их подключать не нужно.</p> + +<pre>php_value auto_prepend_file "/real/path/to/file/functions.php" # Подключит файл function.php в начало документа +php_value auto_append_file "/real/path/to/file/footer.php" # Подключит файл footer.html в конец документа +</pre> + +<p><strong>Настройка страниц с ошибками:</strong> с помощью .htaccess можно перенаправлять пользователя на определенные страницы, при возникновении ошибок на сервере.</p> + +<pre>ErrorDocument 404 /notfound.html # Перенаправит пользователя на страницу notfound.html , при возникновении ошибки с кодом 404 +ErrorDocument 500 /serverr.html # Перенаправит пользователя на страницу serverr.html , при возникновении ошибки с кодом 500 +</pre> + +<p>Для дополнительной информации читайте статью <a href="http://techstream.org/Web-Development/HTACCESS/Error-Documents">Redirect your Traffic for Error Handling</a>.</p> + +<p><strong>Кэширование: </strong>файл <span style="line-height: 1.572;">.htaccess может управлять кэшированием данных веб-браузером пользователя. Это ускорит загрузку страниц и сократит количество передаваемой информации меджу сервером и клиентом.</span></p> + +<p><strong>MIME типы</strong>: смотрите статью <a href="/en-US/docs/Properly_Configuring_Server_MIME_Types" title="Properly_Configuring_Server_MIME_Types">correct MIME types</a> для большей информации.</p> diff --git a/files/ru/learn/server-side/django/admin_site/index.html b/files/ru/learn/server-side/django/admin_site/index.html new file mode 100644 index 0000000000..e8094df592 --- /dev/null +++ b/files/ru/learn/server-side/django/admin_site/index.html @@ -0,0 +1,340 @@ +--- +title: 'Руководство Django часть 4: административная панель Django' +slug: Learn/Server-side/Django/Admin_site +translation_of: Learn/Server-side/Django/Admin_site +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</div> + +<p class="summary">Теперь, когда модели для сайта <a href="https://developer.mozilla.org/ru-RU/docs/Learn/Server-side/Django/Tutorial_local_library_website">местной библиотеки</a> созданы, добавим некоторые "настоящие" данные о книгах, используя административную панель Django Admin. Для начала мы покажем, как зарегистрировать в ней модели, потом как войти и создать какие-нибудь данные. В конце статьи мы покажем некоторые способы дальнейшего улучшения вида админ-панели.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предусловия:</th> + <td>Сначала завершите: <a href="/ru-RU/docs/Learn/Server-side/Django/Models">Руководство часть 3: </a>использование моделей.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Уяснить преимущества и ограничения админ-панели Django, научиться использовать её для создания записей для наших моделей.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p><em>Приложение</em> Django admin может использовать ваши модели для автоматического создания части сайта, предназначенной для создания, просмотра, обновления и удаления записей. Это может сэкономить вам много времени в процессе разработки, упрощая тестирование ваших моделей на предмет <em>правильности</em> данных. Оно также может быть полезным для управления данными на стадии публикации, в зависимости от типа веб-сайта. Проект Django рекомендует это приложение только для управления внутренними данными (т.е.для использования администраторами, либо людьми внутри вашей организации), так как модельно-ориентированный подход не обязательно является наилучшим интерфейсом для всех пользователей и раскрывает много лишних подробностей о моделях.</p> + +<p>Все необходимые настройки, которые необходимо включить в admin приложение вашего веб-сайта, были сделаны автоматически, когда вы <a href="/ru-RU/docs/Learn/Server-side/Django/skeleton_website">создали каркас проекта</a> ( информацию о необходимых актуальных зависимостях смотрите здесь - <a href="https://docs.djangoproject.com/en/1.10/ref/contrib/admin/">Django docs</a>) . В результате все, что необходимо сделать для того, чтобы добавить модели в приложение admin, это <em>зарегистрировать</em> их. В конце этой статьи мы представим краткую демонстрацию того, каким образом можно дополнительно настроить админ-панель для лучшего отображения данные наших моделей.</p> + +<p>После регистрации моделей мы покажем как создать нового суперпользователя , войти на сайт от его имени и создать книги, авторов, экземпляры книг и жанры. Это будет полезным для тестирования представлений и шаблонов, которые мы начнем создавать в следующей части руководства.</p> + +<h2 id="Регистрация_моделей">Регистрация моделей </h2> + +<p>Вначале откройте файл <strong>admin.py </strong>в папке приложения (<strong>/locallibrary/catalog/admin.py</strong>). Пока он выглядит так (заметьте, что он уже содержит импорт <code>django.contrib.admin)</code>:</p> + +<pre class="brush: python">from django.contrib import admin + +# Register your models here. +</pre> + +<p>Зарегистрируйте модели путем вставки следующего текста в нижнюю часть этого файла. Этот код просто импортирует модели и затем вызывает <code>admin.site.register</code> для регистрации каждой из них.</p> + +<pre class="brush: python">from .models import Author, Genre, Book, BookInstance + +admin.site.register(Book) +admin.site.register(Author) +admin.site.register(Genre) +admin.site.register(BookInstance) +</pre> + +<div class="note"><strong>Примечание</strong>: Если вы приняли участие в создании модели для представления естественного языка книги (<a href="/ru-RU/docs/Learn/Server-side/Django/Models">см. обучающую статью о моделях</a>), импортируйте и зарегистрируйте её тоже!</div> + +<p>Это самый простой способ регистрации модели или моделей. Админ-панель имеет множество настроек. Мы рассмотрим другие способы регистрации ваших моделей ниже.</p> + +<h2 id="Создание_суперпользователя">Создание суперпользователя</h2> + +<p>Для того, чтобы войти в админ-панель, нам необходимо иметь учетную запись пользователя со статусом <em>Staff (сотрудники). </em>Для просмотра и создания записей, пользователю также понадобится разрешение для управления всеми нашими объектами. Вы можете создать учетную запись "superuser", которая дает полный доступ к сайту и все необходимые разрешения, используя <strong>manage.py</strong>.</p> + +<p>Для создания суперпользователя вызовите следующую команду из той же папки, где расположен <strong>manage.py</strong>. Вас попросят ввести имя пользователя, адрес электронной почты и надежный пароль. </p> + +<pre class="brush: bash">python3 manage.py createsuperuser +</pre> + +<p>После выполнения этой команды новый суперпользователь будет добавлен в базу данных. Теперь перезапустите сервер, чтобы можно было протестировать вход на сайт:</p> + +<pre class="brush: bash">python3 manage.py runserver + +</pre> + +<h2 id="Вход_в_админ-панель_и_ее_использование">Вход в админ-панель и ее использование</h2> + +<p>Для входа в админ-панель откройте ссылку<em> /admin</em> (например <a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin</a>) и введите логин и пароль вашего нового суперпользователя (вас перенаправят на login-страницу и потом обратно на /admin после ввода всех деталей).</p> + +<p>В этой части сайта отображаются все наши модели, сгрупированные по установленному приложению. Вы можете кликнуть на названии модели, чтобы получить список всех связанных записей, далее можете кликнуть на этих записях, для их редактирования . Также можно непосредственно кликнуть на ссылку <strong>Add</strong>, расположенную рядом с каждой моделью, чтобы начать создание записи этого типа. </p> + +<p><img alt="Admin Site - Home page" src="https://mdn.mozillademos.org/files/13975/admin_home.png" style="display: block; height: 634px; margin: 0px auto; width: 998px;"></p> + +<p>Кликните на ссылке <strong>Add</strong> справа от <em>Books</em>, чтобы создать новую книгу (появится диалоговое окно как на картинке внизу). Заметьте, что заголовок каждого поля - это тип используемого виджета, и <code>help_text</code> (если есть) совпадает со значением, которое вы указали в модели. </p> + +<p>Введите значение для полей. Вы можете создавать новых авторов или жанры, нажимая на значок "+ ", расположенный рядом с соответствующим полем (или выберите существующее значение из списков, если вы уже создали их). Когда вы закончили, нажмите на <strong>SAVE,</strong> <strong>Save and add another</strong>, или <strong>Save and continue editing,</strong> чтобы сохранить записи.</p> + +<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: А сейчас, хотелось бы, чтобы вы добавили несколько книг, авторов и жанров (например, Фэнтези) в ваше приложение. Удостоверьтесь, что каждый автор и жанр включает пару различных книг (позже, когда мы реализуем представления "list" и "detail", это сделает их более интересными).</p> +</div> + +<p>После того, когда книги добавлены, для перехода на главную страницу админ-панели кликните на ссылке <strong>Home </strong>в верхней части страницы. Потом кликните на ссылке <strong>Books</strong> для отображения текущего списка книг (или на одной из других ссылок, чтобы увидеть список соответствующей модели). После добавления нескольких книг список может выглядеть наподобие скриншота ниже. Отображается название каждой из книг. Его возвращает метод <code>__str__() </code>в модели Book, созданной в предыдущей статье.</p> + +<p><img alt="Admin Site - List of book objects" src="https://mdn.mozillademos.org/files/13935/admin_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 407px; margin: 0px auto; width: 1000px;"></p> + +<p>Для удаления книги из этого списка выберите чекбокс рядом с ней и действие <em>delete...</em> из выпадающего списка <em>Action</em>, а затем нажмите кнопку <strong>Go</strong>. Также можно добавить новую книгу, нажав на кнопку <strong>ADD BOOK</strong>. </p> + +<p>Вы можете редактировать книгу, кликнув по ссылке с ее названием. Страница редактирования книги, приведенная ниже, практически идентична странице добавления новой книги. Основные отличия - это заголовок страницы (<em>Change book</em>) и наличие кнопок <strong>Delete</strong>, <strong>HISTORY</strong> и <strong>VIEW ON SITE. </strong>Последняя присутствует, так как мы определили метод <code>get_absolute_url() </code>в нашей модели.</p> + +<p><img alt="Admin Site - Book Edit" src="https://mdn.mozillademos.org/files/13977/admin_book_modify.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p> + +<p>Теперь перейдите назад на страницу <strong>Home </strong>(используя ссылку <em>Home</em> в навигационной цепочке вверху страницы) и просмотрите списки <strong>Author</strong> и <strong>Genre</strong>. В них уже должно быть несколько элементов, созданных при добавлении новых книг. Если хотите, добавьте еще.</p> + +<p>Однако у вас не будет ни одного экземпляра книги, потому что они не создаются из модели <code>Book </code>(хотя можно создать книгу из модели <code>BookInstance</code> — такова природа поля <code>ForeignKey</code>). Для отображения страницы <em>Add book instance </em>(см. рисунок ниже)<em> </em>вернитесь на страницу <em>Home</em> и нажмите кнопку <strong>Add</strong>. Обратите внимание на длинный уникальный Id для идентификации конкретного экземпляра книги в библиотеке.</p> + +<p><img alt="Admin Site - BookInstance Add" src="https://mdn.mozillademos.org/files/13981/admin_bookinstance_add.png" style="border-style: solid; border-width: 1px; display: block; height: 514px; margin: 0px auto; width: 863px;"></p> + +<p>Создайте несколько экземпляров для каждой из ваших книг. Установите статус <em>Available (доступен) </em>для некоторых экземплров и <em>On loan (выдан)</em> для остальных. Если статус экземпляра <strong>not</strong> <em>Available (недоступен)</em>, то также установите дату возврата (<em>Due back)</em>.</p> + +<p>Вот и все! Вы изучили как запустить и использовать админ-панель. Также были созданы записи для <code>Book</code>, <code>BookInstance</code>, <code>Genre</code> и <code>Author</code>, которые можно будет использовать после создания наших собственных представлений и шаблонов.</p> + +<h2 id="Продвинутая_конфигурация">"Продвинутая" конфигурация</h2> + +<p>Django выполняет неплохую работу по созданию базовой админ-панели используя информацию из зарегистрированых моделей:</p> + +<ul> + <li>каждая модель имеет список записей, каждая из которых идентифицируется строкой, создаваемой методом <code>__str__()</code> модели, и связана с представлением для ее редактирования. По умолчанию, в верхней части этого представления находится меню действий, которое может быть использовано для удаления нескольких записей за раз</li> + <li>Формы для редактирования и добавления записей содержат все поля модели, которые расположены вертикально в порядке их объявления в модели. </li> +</ul> + +<p>Можно настроить интерфейс пользователя для упрощения его использования. Некоторые доступные настройки:</p> + +<ul> + <li>List views: + <ul> + <li>добавление дополнительных отображаемых полей или информации для каждой записи. </li> + <li>добавление фильтров для отбора записей по разным критериям (например, статус выдачи книги).</li> + <li>добавление дополнительных вариантов выбора в меню действий и места расположения этого меню на форме.</li> + </ul> + </li> + <li>Detail views + <ul> + <li>выбор отображаемых полей, их порядка, группирования и т.д. </li> + <li>добавление связанных полей к записи (например, возможности добавления и редактирования записей книг при создании записи автора).</li> + </ul> + </li> +</ul> + +<p>В этом разделе рассмотрим некоторые изменения для совершенствования интерфейса пользователя нашей местной библиотеки, а именно: добавление дополнительной информации в списки моделей <code>Book</code> и <code>Author</code> , а также улучшение расположения элементов соответствующих представлений редактирования. Пользовательский интерфейс моделей <code>Language</code> and <code>Genre</code> изменять не будем, так как это не даст заметного улучшения, поскольку он содержит только по одному полю!</p> + +<p>Полное руководство по всем возможным вариантам настройки админ-панели можно найти в <a href="https://docs.djangoproject.com/en/1.10/ref/contrib/admin/">The Django Admin site</a> (документация Django).</p> + +<h3 id="Регистрация_класса_ModelAdmin">Регистрация класса ModelAdmin</h3> + +<p>Для измененения отображения модели в пользовательском интерфейсе админ-панели, необходимо определить класс <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#modeladmin-objects">ModelAdmin</a> (он описывает расположение элементов интерфейса, где Model - наименование модели) и зарегистрировать его для использования с этой моделью.</p> + +<p>Давайте начнем с модели Author. Откройте файл <strong>admin.py</strong> в каталоге приложения (<strong>/locallibrary/catalog/admin.py</strong>). Закомментируйте исходную регистрацию (используя префикс #) этой модели:</p> + +<pre class="brush: js"># admin.site.register(Author)</pre> + +<p>Теперь добавьте новый класс <code>AuthorAdmin</code> и зарегистрируйте его как показано ниже:</p> + +<pre class="brush: python"># Define the admin class +class AuthorAdmin(admin.ModelAdmin): + pass + +# Register the admin class with the associated model +admin.site.register(Author, AuthorAdmin) +</pre> + +<p>Сейчас мы добавим классы <code>ModelAdmin</code> для моделей <code>Book </code> <code>BookInstance</code>. Нам снова нужно закомментировать исходную регистрацию:</p> + +<pre class="brush: js">#admin.site.register(Book) +#admin.site.register(BookInstance)</pre> + +<p>В этот раз для создания и регистрации новых моделей используем декоратор <code>@register</code> (он делает то же самое, что и метод <code>admin.site.register()</code>):</p> + +<pre class="brush: python"># Register the Admin classes for Book using the decorator + +@admin.register(Book) +class BookAdmin(admin.ModelAdmin): + pass + +# Register the Admin classes for BookInstance using the decorator + +@admin.register(BookInstance) +class BookInstanceAdmin(admin.ModelAdmin): + pass +</pre> + +<p>Пока что все наши admin-классы пустые (см. "<code>pass"</code>), поэтому ничего не изменится ! Добавим код для задания особенностей интерфейса моделей.</p> + +<h3 id="Настройка_отображения_списков">Настройка отображения списков</h3> + +<p>Сейчас приложение <em>LocalLibrary</em> отображает всех авторов, используя имя объекта, возвращаемое методом <code>__str__()</code> модели. Это приемлемо, когда есть только несколько авторов, но, если их количество значительно, возможны дубликаты. Чтобы различить их или просто отобразить более интересную информацию о каждом авторе, можно использовать <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display">list_display</a> (для добавления дополнительных полей). </p> + +<p>Замените класс <code>AuthorAdmin</code> кодом, приведенным ниже. Названия полей, которые будут отображаться в списке, перечислены в кортеже list_display в требуемом порядке (это те же имена, что и в исходной модели).</p> + +<pre class="brush: python">class AuthorAdmin(admin.ModelAdmin): + list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death') +</pre> + +<p>Перезапустите сайт и перейдите к списку авторов. Указанные поля должны отображаться следующим образом:</p> + +<p><img alt="Admin Site - Improved Author List" src="https://mdn.mozillademos.org/files/14023/admin_improved_author_list.png" style="border-style: solid; border-width: 1px; display: block; height: 302px; margin: 0px auto; width: 941px;"></p> + +<p>Для нашей модели <code>Book</code> добавим отображение полей <code>author</code> и <code>genre</code>. Поле <code>author</code> - это внешний ключ (<code>ForeignKey</code> ) связи один к одному, поэтому оно будет представлено значением <code>__str()__</code> для связанной записи. Замените класс <code>BookAdmin</code> на версию, приведенную ниже.</p> + +<pre class="brush: python">class BookAdmin(admin.ModelAdmin): + list_display = ('title', 'author', 'display_genre') +</pre> + +<p>К сожалению, мы не можем напрямую поместить поле <font face="Consolas, Liberation Mono, Courier, monospace">genre в</font> <code>list_display</code>, так как оно является <code>ManyToManyField</code> (Django не позволяет это из-за большой "стоимости" доступа к базе данных). Вместо этого мы определим функцию <code>display_genre</code> для получения строкового представления информации (вызов этой функции есть в <code>list_display</code>, ее определение см. ниже).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Получение здесь значения поля <code>genre</code> возможно не самая хорошая идея вследствие "стоимости" операции базы данных. Мы показываем это, потому что вызов функций в ваших моделях может быть очень полезен по другим причинам, например, для добавления ссылки <em>Delete </em>рядом с каждым пунктом списка.</p> +</div> + +<p>Добавьте следующий код в вашу модель <code>Book</code> (<strong>models.py</strong>). В нем создается строка из первых трех значений поля <code>genre</code> (если они существуют) и <code>short_description</code>, которое может быть использовано в админ-панели.</p> + +<pre class="brush: python"> def display_genre(self): + """ + Creates a string for the Genre. This is required to display genre in Admin. + """ + return ', '.join([ genre.name for genre in self.genre.all()[:3] ]) + display_genre.short_description = 'Genre' +</pre> + +<p>После сохранения модели и обновления админ-панели, перезапустите ее и перейдите на страницу списка <em>Books</em>. Вы должны увидеть список книг, наподобие приведенного ниже:</p> + +<p><img alt="Admin Site - Improved Book List" src="https://mdn.mozillademos.org/files/14025/admin_improved_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 337px; margin: 0px auto; width: 947px;"></p> + +<p>Модель <code>Genre</code> (и модель <code>Language</code>, если вы ее определили) имеет единственное поле. Поэтому нет необходимости создания для них дополнительных моделей с целью отображения дополнительных полей.</p> + +<div class="note"> +<p><strong>Примечание</strong>: целесообразно, чтобы в списке модели <code>BookInstance</code> отображались хотя бы статус и ожидаемая дата возврата. Мы добавили это в качестве "испытания" в конце этой статьи!</p> +</div> + +<h3 id="Добавление_фильтров_списка">Добавление фильтров списка</h3> + +<p>Если в вашем списке есть множество элементов, может быть полезной возможность фильтрации отображаемых пунктов. Это выполняется путем перечисления их в атрибуте <code>list_filter</code>. Замените класс <code style="font-style: normal; font-weight: normal;">BookInstanceAdmin</code> на следующий:</p> + +<pre class="brush: python">class BookInstanceAdmin(admin.ModelAdmin): +<strong> list_filter = ('status', 'due_back')</strong> +</pre> + +<p>Представление списка теперь будет содержать панель фильтрации справа. Обратите внимание, как выбирать даты и статус для фильтрации:</p> + +<p><img alt="Admin Site - BookInstance List Filters" src="https://mdn.mozillademos.org/files/14037/admin_improved_bookinstance_list_filters.png" style="height: 528px; width: 960px;"></p> + +<h3 id="Формирование_макета_с_подробным_представлением">Формирование макета с подробным представлением</h3> + +<p>По умолчанию в представлениях деталей отображаются все поля по вертикали в порядке их объявления в модели. Вы можете изменить порядок декларации, какие поля отображаются (или исключены), используются ли разделы для организации информации, отображаются ли поля горизонтально или вертикально, и даже какие виджеты редактирования используются в админ-формах.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Модели LocalLibrary относительно просты, поэтому нам не нужно менять макет, но мы все равно внесем некоторые изменения, просто чтобы показать вам, как это сделать.</p> +</div> + +<h4 id="Управление_отображаемыми_и_вложенными_полями">Управление отображаемыми и вложенными полями</h4> + +<p>Обновите ваш AuthorAdmin класс, чтобы добавить строку полей, как показано ниже (выделено полужирным шрифтом):</p> + +<pre class="brush: python">class AuthorAdmin(admin.ModelAdmin): + list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death') +<strong> fields = ['first_name', 'last_name', ('date_of_birth', 'date_of_death')]</strong> +</pre> + +<p>Атрибут полей перечисляет только те поля, которые должны отображаться в форме, по порядку. Поля отображаются по вертикали по умолчанию, но будут отображаться горизонтально, если вы дополнительно группируете их в кортеже (как показано в полях «date» выше).</p> + +<p>Перезагрузите приложение и перейдите к подробному представлению автора - он должен теперь отображаться, как показано ниже:</p> + +<p><img alt="Admin Site - Improved Author Detail" src="https://mdn.mozillademos.org/files/14027/admin_improved_author_detail.png" style="border-style: solid; border-width: 1px; display: block; height: 282px; margin: 0px auto; width: 928px;"></p> + +<div class="note"> +<p><strong>Примечание</strong>: Так же, вы можете использовать <code>exclude</code> атрибут для объявления списка атрибутов, которые будут исключены из формы (все остальные атрибутыв модели, будут отображаться). </p> +</div> + +<h4 id="Разделение_на_секцииВыделение_подробного_представления">Разделение на секции/Выделение подробного представления</h4> + +<p>Вы можете добавлять "разделы" (sections) для группировки связанной информации в модели в форме детализации, используя атрибут <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets">fieldsets</a> .</p> + +<p>В модели <code>BookInstance</code> мы имеем информацию соответствия конкретной книги (т.е. <code>name</code>, <code>imprint</code>, and <code>id</code>) и датой когда она вновь станет доступной (<code>status</code>, <code>due_back</code>). Мы можем добавить их в разные секции, добавив текст жирным шрифтом в наш <code>BookInstanceAdmin</code> класс. </p> + +<pre class="brush: python">@admin.register(BookInstance) +class BookInstanceAdmin(admin.ModelAdmin): + list_filter = ('status', 'due_back') + +<strong> fieldsets = ( + (None, { + 'fields': ('book','imprint', 'id') + }), + ('Availability', { + 'fields': ('status', 'due_back') + }), + )</strong></pre> + +<p>Каждая секция имеет свой заголовок (или <code>None</code>, если заголовок не нужен) и ассоциированный кортеж полей в словаре - формат сложный для описания, но относительно простой для понимания, если вы посмотрите на фрагмент кода, представленный выше.</p> + +<p>Перезапустите сайт и перейдите к списку экземпляров; форма должна отображаться следующим образом:</p> + +<p><img alt="Admin Site - Improved BookInstance Detail with sections" src="https://mdn.mozillademos.org/files/14029/admin_improved_bookinstance_detail_sections.png" style="border-style: solid; border-width: 1px; display: block; height: 580px; margin: 0px auto; width: 947px;"></p> + +<h3 id="Встроенное_редактирование_связанных_записей">Встроенное редактирование связанных записей</h3> + +<p>Иногда бывает полезно иметь возможность добавлять связанные записи одновременно. Например, имеет смысл иметь как информацию о книге, так и информацию о конкретных копиях, которые вы получили на той же странице подробностей. К примеру, вполне логично получить и информацию о книге, и информацию о конкретных копиях, зайдя на страницу детализации.</p> + +<p>Вы можете это сделать, объявив <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.inlines">inlines</a>, и указав тип <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> (горизонтальное расположение) или <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.StackedInline">StackedInline</a> (вертикальное расположение, так же как и в модели по умолчанию). Вы можете добавить <code>BookInstance</code> информацию в подробное описание <code>Book</code> , добавив строки, представленные ниже и распологающиеся рядом с <code>BookAdmin</code>: </p> + +<pre class="brush: python"><strong>class BooksInstanceInline(admin.TabularInline): + model = BookInstance</strong> + +@admin.register(Book) +class BookAdmin(admin.ModelAdmin): + list_display = ('title', 'author', 'display_genre') +<strong> inlines = [BooksInstanceInline]</strong> +</pre> + +<p>Попробуйте перезапустить приложение, а затем взгляните на представление книги — внизу вы должны увидеть экземпляры книги, относящиеся к этой книге:</p> + +<p><img alt="Admin Site - Book with Inlines" src="https://mdn.mozillademos.org/files/14033/admin_improved_book_detail_inlines.png" style="border-style: solid; border-width: 1px; display: block; height: 889px; margin: 0px auto; width: 937px;"></p> + +<p>В этом случае, всё, что мы сделали - объявили наш встроенный класс tablular, который просто добавляет все поля из <em>встроенной</em> модели. Вы можете указать все виды дополнительной информации для макета, включая отображаемые поля, их порядок, независимо от того, являются ли они только для чтения или нет, и т. д. (См. <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> для получения дополнительной информации). </p> + +<div class="note"> +<p><strong>Примечание</strong>: В этой функции есть некоторые неприятные ограничения! На скриншоте выше у нас есть три существующих экземпляра книги, за которыми следуют три поля для новых экземпляров книги (которые очень похожи!). Было бы лучше НЕ иметь лишних экземпляров книг по умолчанию и просто добавить их с помощью ссылки <strong>Add another Book instance</strong> или иметь возможность просто перечислять <code>BookInstance</code>s как нечитаемые здесь ссылки. Первый вариант можно сделать, установив <code>extra</code> атрибут в 0 в модели <code>BookInstanceInline</code>, попробуйте сами.</p> +</div> + +<h2 id="Проверьте_себя">Проверьте себя</h2> + +<p>Мы многое изучили в этом разделе и теперь настало время вам самостоятельно попробовать несколько вещей:</p> + +<ol> + <li>Для представления списка <code>BookInstance</code> , добавьте код для отображения книги, статуса, даты возврата, и id (вместо значения по умолчанию возвращаемого <code>__str__()</code> ).</li> + <li>Добавьте встроенный список перечня <code>Book</code> в представление списка <code>Author</code> , используя тот же самый подход, который мы применили для <code>Book</code>/<code>BookInstance</code>.</li> +</ol> + +<ul> +</ul> + +<h2 id="Заключение">Заключение</h2> + +<p>Вот и всё! Теперь вы узнали, как настроить сайт администрирования как в самой простой, так и в улучшенной форме, о создании суперпользователя и о том, как перемещаться по сайту администратора, просматривать, удалять и обновлять записи. По пути вы создали множество книг, экземпляров, жанров и авторов, которые мы сможем перечислить и отобразить, как только мы создадим собственный вид и шаблоны.</p> + +<h2 id="Дополнительные_материалы">Дополнительные материалы</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/intro/tutorial02/#introducing-the-django-admin">Writing your first Django app, part 2: Introducing the Django Admin</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/contrib/admin/">The Django Admin site</a> (Django Docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/django/development_environment/index.html b/files/ru/learn/server-side/django/development_environment/index.html new file mode 100644 index 0000000000..6173f67714 --- /dev/null +++ b/files/ru/learn/server-side/django/development_environment/index.html @@ -0,0 +1,398 @@ +--- +title: Setting up a Django development environment +slug: Learn/Server-side/Django/development_environment +translation_of: Learn/Server-side/Django/development_environment +--- +<p>{{LearnSidebar}}</p> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}</p> + +<p>Теперь, когда вы знаете, что такое Django, мы покажем вам, как настроить и протестировать среду разработки Django для Windows, Linux (Ubuntu) и Mac OS X - какую бы операционную систему вы не использовали, эта статья должна дать вам все, что необходимо для возможности начать разрабатывать приложения Django.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Знание как открыть терминал / командную строку, как устанавливать программные пакеты в операционной системе вашего компьютера.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Создать среду разработки для Django (1.10) и запустить её на вашем компьютере.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор_среды_разработки_Django">Обзор среды разработки Django</h2> + +<p>Django упрощает настройку собственного компьютера, чтобы вы могли начать разработку веб-приложений. В этом разделе объясняется, что входит в состав среды разработки, и дается обзор некоторых параметров настройки и конфигурации. В оставшейся части статьи объясняется рекомендуемый метод установки среды разработки Django на Ubuntu, Mac OS X и Windows, и как вы можете ее протестировать.</p> + +<h3 id="Что_такое_среда_разработки_Django">Что такое среда разработки Django?</h3> + +<p>Среда разработки - это установка Django на вашем локальном компьютере, которую вы можете использовать для разработки и тестирования приложений Django до их развертывания в производственной среде.<br> + <br> + Основными инструментами, которые предоставляет сам Django, является набор скриптов Python для создания и работы с проектами Django, а также простой веб-сервер <em>разработки</em>, который можно использовать для тестирования локальных (то есть на вашем компьютере, а не на внешнем веб-сервере) веб-приложений Django на веб-браузере вашего компьютера.<br> + <br> + Существуют и другие периферийные инструменты, являющиеся частью среды разработки, которые мы не будем освещать здесь. К ним относятся такие вещи, как текстовый редактор или IDE для редактирования кода, и инструмент управления исходным кодом, например Git, для безопасного управления различными версиями вашего кода. Мы предполагаем, что у вас уже установлен текстовый редактор.</p> + +<h3 id="Какие_есть_разновидности_установки_Django">Какие есть разновидности установки Django ?</h3> + +<p>Django очень гибок с точки зрения способа и места установки и настройки. Django может быть:</p> + +<ul> + <li>установлен на различных операционных системах,</li> + <li>установлен из исходного кода, из Python Package Index (PyPi) и во многих случаях из любого менеджера пакетов,</li> + <li>настроен на использование различных баз данных, которые должны быть установлены и настроены отдельно,</li> + <li>запущен в основной системе окружения Python или в отдельном виртуальном окружении Python.</li> +</ul> + +<p>Каждый из этих вариантов требует немного разной настройки и установки. Следующие подразделы объяснят некоторые аспекты вашего выбора. Далее мы покажем вам, как установить Django на некоторые операционные системы, и эта установка будет предполагаться на всём протяжении данного модуля.</p> + +<div class="note"> +<p><strong>Замечание</strong>: Другие возможные способы установки можно найти в официальной документации Django. Мы ссылаемся на <a href="#furtherreading">соответствующие документы</a>.</p> +</div> + +<h4 id="Какие_операционные_системы_поддерживаются">Какие операционные системы поддерживаются?</h4> + +<p>Веб-приложения Django можно запускать почти на любых машинах, которые поддерживают язык программирования Python 3, среди прочих: Windows, Mac OS X, Linux/Unix, Solaris. Почти любой компьютер имеет необходимую производительность для запуска Django во время разработки.</p> + +<p>В этой статье мы предоставляем инструкции для Windows, Mac OS X, and Linux/Unix.</p> + +<h4 id="Какую_версию_Python_стоит_использовать">Какую версию Python стоит использовать?</h4> + +<p>Мы рекомендуем использовать самую последнюю доступную версию - на момент написания статьи это Python 3.6.</p> + +<div class="note"> +<p><strong>Замечание</strong>: Python 2.7 не может быть использован вместе с Django 2.0 (последние поддерживаемые серии для Python 2.7 - Django 1.11.x).</p> +</div> + +<h4 id="Откуда_можно_скачать_Django">Откуда можно скачать Django?</h4> + +<p>Для загрузки Django можно воспользоваться 3 источниками:</p> + +<ul> + <li>The Python Package Repository (PyPi), при помощи инструмента <em>pip</em>. Это лучший способ получения последней стабильной версии Django.</li> + <li>Использование версии из менеджера пакетов вашего компьютера. Такие дистрибутивы Django, собранные для конкретных операционных систем, предлагают знакомый механизм установки. Однако обратите внимание на то, что пакетные версии могут быть достаточно старыми и установлены только в системную среду Python (что может отличаться от ваших желаний).</li> + <li>Установка из исходного кода. Вы можете получить и установить последний выпуск Django из исходного кода. Этот способ не рекомендован для новичков, но необходим в случае, когда вы готовы начать вносить собственный вклад в проект Django.</li> +</ul> + +<p>Данный материал описывает способ установки Django из PyPi с целью получения последней стабильной версии.</p> + +<h4 id="Какую_базу_данных_выбрать">Какую базу данных выбрать?</h4> + +<p>Django поддерживает 4 основных базы данных (PostgreSQL, MySQL, Oracle и SQLite), также есть публичные библиотеки, которые предоставляют разные уровни поддержки других SQL и NoSQL баз данных. Мы рекомендуем вам выбрать одинаковую БД для обеих рабочей и разрабатываемой сред (несмотря на то, что Django нивелирует множество различий баз данных при помощи Object-Relational Mapper (ORM), все равно возможны потенциальные <a href="https://docs.djangoproject.com/en/2.0/ref/databases/">проблемы</a>, которых лучше избегать.</p> + +<p>Для данной статьи (и большей части модуля) мы будем использовать базу данных <em>SQLite</em>, которая сохраняет свои данные в файл. SQLite предназначен для использования в качестве облегченной базы данных и не может поддерживать высокий уровень параллелизма. Это, однако, отличный выбор для приложений, которые в основном предназначены только для чтения.</p> + +<div class="note"> +<p><strong>Замечание</strong>: Django сконфигурирован для использования SQLite по умолчанию, при создании вашего проекта с использованием стандартных инструментов (django-admin). Это отличный выбор для начала работы, потому что он не требует дополнительной настройки.</p> +</div> + +<h4 id="Глобальная_установка_или_установка_в_виртуальную_среду_Python">Глобальная установка или установка в виртуальную среду Python?</h4> + +<p>Когда вы устанавливаете Python 3 на свой компьютер, вы получаете единую глобальную среду (набор установленных пакетов) для вашего кода Python, которая доступна любому коду на компьютере. Вы можете установить любые пакеты Python, необходимые вам в этой среде, но только одну конкретную версию конкретного пакета.</p> + +<div class="note"> +<p><strong>Замечание</strong>: Установленные в глобальную среду приложения Python потенциально могут конфликтовать друг с другом (т.е. если они зависят от разных версий одного и того же пакета).</p> +</div> + +<p>Если вы устанавливаете Django в среду по умолчанию (глобальную), то будете способны сфокусироваться на одной версии Django на вашем компьютере. Это может быть проблемой в случае, если вы захотите создать новые вебсайты (при помощи новой версии Django) во время поддержки вебсайтов со старой версией.</p> + +<p>По этой причине опытные разработчики Python / Django часто предпочитают вместо этого запускать свои приложения Python в независимых <em>виртуальных средах Python</em>. Это позволяет разработчикам иметь несколько разных сред Django на одном компьютере. Команда разработчиков Django сама рекомендует использовать виртуальные среды Python!</p> + +<p>Этот модуль предполагает вашу установку Django в виртуальную среду, и мы покажем, как это сделать.</p> + +<h2 id="Установка_Python_3">Установка Python 3</h2> + +<p>Для использования Django вам необходимо установить <em>Python 3</em> на свою операционную систему. Вам также понадобится инструмент <a href="https://pypi.python.org/pypi">Python Package Index</a> — <em>pip3</em> — который используется для управления (установка, обновление и удаление) библиотек/пакетов Python, используемых Django и другими вашими приложениями Python.</p> + +<p>Этот раздел коротко описывает то, как вы можете проверить имеющиеся версии и при необходимости установить новые для Ubuntu Linux 16.04, Mac OS X, and Windows 10.</p> + +<div class="note"> +<p><strong>Замечание</strong>: В зависимости от платформы, вы можете иметь возможность установки Python/pip из собственного менеджера пакетов операционной системы или при помощи других инструментов. Для большинства платформ вы можете скачать необходимые установочные файлы из <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a> и установить их при помощи соответствующего специфичного для платформы метода.</p> +</div> + +<h3 id="Ubuntu_16.04">Ubuntu 16.04</h3> + +<p>Ubuntu Linux включает в себя Python 3 по умолчанию. Вы можете удостовериться в этом, выполнив следующую команду в терминале:</p> + +<pre class="notranslate">python3 -V + Python 3.5.2</pre> + +<p>Однако, инструмент Python Package Index, при помощи которого вам нужно будет установаить пакеты для Python 3 (включая Django), по умолчанию <strong>не установлен</strong>. Вы можете установить pip3 через терминал bash при помощи:</p> + +<pre class="notranslate">sudo apt-get install python3-pip +</pre> + +<h3 id="Mac_OS_X">Mac OS X</h3> + +<p>Mac OS X "El Capitan" не включает Python 3. Вы можете удостовериться в этом, выполнив следующую команду в терминале:</p> + +<pre class="notranslate">python3 -V + -bash: python3: command not found</pre> + +<p>Вы можете легко установить Python 3 (вместе с инструментом <em>pip3</em>) с<a href="https://www.python.org/"> python.org</a>:</p> + +<ol> + <li>Скачайте нужный установочный файл: + <ol> + <li>Перейдите в <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></li> + <li>Нажмите на кнопку <strong>Скачать Python 3.6.4</strong> (точная основная версия может отличаться).</li> + </ol> + </li> + <li>Найдите файл при помощи <em>Finder</em>, дважды кликните по нему и следуйте подсказкам по установке.</li> +</ol> + +<p>Удостовериться в успешной установке вы можете проверкой на наличие <em>Python 3</em>, как показано ниже:</p> + +<pre class="notranslate">python3 -V + Python 3.5.20 +</pre> + +<p>Подобным образом вы можете проверить установку <em>pip3</em>, отобразив список доступных пакетов:</p> + +<pre class="notranslate">pip3 list</pre> + +<h3 id="Windows_10">Windows 10</h3> + +<p>Windows не включает Python по умолчанию, но вы можете легко установить его (вместе с инструментом <em>pip</em>) с<a href="https://www.python.org/"> python.org</a>:</p> + +<ol> + <li>Скачайте нужный установочный файл: + <ol> + <li>Перейдите в <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></li> + <li>Нажмите на кнопку <strong>Скачать Python 3.6.4</strong> (точная основная версия может отличаться).</li> + </ol> + </li> + <li>Установите Python, дважды кликнув на скачанный файл и следуя инструкциям по установке.</li> +</ol> + +<p>После этого вы сможете подтвердить успешную установку Python путем выполнения следующего текста в командной строке:</p> + +<pre class="notranslate">py -3 -V + Python 3.5.2 +</pre> + +<p>Установщик Windows включает в себя <em>pip3</em> (менеджер пакетов Python) по умолчанию. Вы можете отобразить список установленных пакетов, как показано далее:</p> + +<pre class="notranslate">pip list +</pre> + +<div class="note"> +<p><strong>Замечание</strong>: Установщик должен сделать все, что необходимо для корректной работы указанной команды. Однако, если вы видите сообщение о том, что Python не может быть найден, вам может потребоваться добавить его в системный путь.</p> +</div> + +<h2 id="Использование_Django_внутри_виртуальной_среды_Python">Использование Django внутри виртуальной среды Python</h2> + +<p>Для создания виртуальных сред мы будем использовать библиотеки <a href="https://virtualenvwrapper.readthedocs.io/en/latest/index.html">virtualenvwrapper</a> (Linux и macOS X) и <a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a> (Windows), которые в свою очередь обе используют инструмент <a href="https://developer.mozilla.org/en-US/docs/Python/Virtualenv">virtualenv</a>. Инструмент обертки предоставляет совместимый интерфейс для управления интерфейсами на всех платформах.</p> + +<h3 id="Установка_ПО_виртуальной_среды">Установка ПО виртуальной среды</h3> + +<h4 id="Установка_виртуальной_среды_для_Ubuntu">Установка виртуальной среды для Ubuntu</h4> + +<p>После установки Python и pip вы можете установить <em>virtualenvwrapper </em>(который включает в себя <em>virtualenv</em>). Вы можете либо воспользоваться официальной инструкций по установке <a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">отсюда</a>, либо следовать следующим инструкциям:</p> + +<p>Установите инструмент при помощи pip3:</p> + +<pre class="notranslate"><code>sudo pip3 install virtualenvwrapper</code> +</pre> + +<p>Затем добавьте следующие строки в конец файла загрузки программной оболочки (shell) (это скрытый файл в вашей домашней директории с именем <strong>.bashrc</strong>). Они устанавливают расположение виртуальных сред, расположение каталога разрабатываемого проекта и расположение установленного с этим пакетом скрипта.</p> + +<pre class="notranslate"><code>export WORKON_HOME=$HOME/.virtualenvs +export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 +export VIRTUALENVWRAPPER_VIRTUALENV_ARGS=' -p /usr/bin/python3 ' +export PROJECT_HOME=$HOME/Devel +source /usr/local/bin/virtualenvwrapper.sh</code> +</pre> + +<p>Затем перезагрузите файл загрузки, выполнив в терминале следующую команду:</p> + +<pre class="notranslate"><code>source ~/.bashrc</code> +</pre> + +<p>В этот момент вы должны увидеть запуск группы скриптов, как показано ниже:</p> + +<pre class="notranslate"><code>virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/premkproject +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postmkproject +... +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/preactivate +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postactivate +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/get_env_details</code> +</pre> + +<p>Теперь вы можете создать новую виртуальную среду при помощи команды <code>mkvirtualenv</code>.</p> + +<h4 id="Установка_виртуальной_среды_для_macOS_X">Установка виртуальной среды для macOS X</h4> + +<p>Установка <em>virtualenvwrapper </em>на macOS X почти идентична Ubuntu (и снова вы можете воспользоваться либо <a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">официальными</a>, либо следующими инструкциями).</p> + +<p>Установите инструмент при помощи pip3:</p> + +<pre class="notranslate"><code>sudo pip3 install virtualenvwrapper</code> +</pre> + +<p>Затем добавьте следующие строки в конец вашего файла загрузки программной оболочки:</p> + +<pre class="notranslate"><code>export WORKON_HOME=$HOME/.virtualenvs +export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 +export PROJECT_HOME=$HOME/Devel +source /usr/local/bin/virtualenvwrapper.sh</code> +</pre> + +<div class="note"> +<p><strong>Замечание</strong>: Переменная <code>VIRTUALENVWRAPPER_PYTHON</code> указывает на обычное расположение Python3. Если virtualenv не работает во время тестирования, то вам следует проверить, находится ли интерпертатор Python в нужном расположении (и затем поменять его соответствующим образом в значении переменной).</p> +</div> + +<p>Эти строки такие же, как в случае с Ubuntu, но файл загрузки в вашей домашней директории назван иначе - <strong>.bash_profile</strong>. </p> + +<div class="note"> +<p><strong>Замечание</strong>: Если вы не можете найти и изменить <strong>.bash_profile </strong>при помощи Finder, то можно также открыть его при помощи редактора терминала <em>nano</em>.</p> + +<p>Команды в этом случае выглядят примерно так:</p> + + + +<pre class="notranslate"><code>cd ~ # Navigate to my home directory +ls -la #List the content of the directory. You should see .bash_profile +nano .bash_profile # Open the file in the nano text editor, within the terminal +# Scroll to the end of the file, and copy in the lines above +# Use Ctrl+X to exit nano, Choose Y to save the file.</code> +</pre> +</div> + +<p>После этого перезагрузите файл загрузки путем выполнения следующей команды в терминале:</p> + +<pre class="notranslate"><code>source ~/.bash_profile</code> +</pre> + +<p>В этот момент вы должны увидеть запуск группы скриптов (те же скрипты, что и в случае установки на Ubuntu).</p> + +<p>Теперь вы должны иметь возможность создания новой виртуальной среды при помощи команды <code>mkvirtualenv</code>.</p> + +<h4 id="Установка_виртуальной_среды_для_Windows_10">Установка виртуальной среды для Windows 10</h4> + +<p>Установка <a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a> еще более проста, чем установка <em>virtualenvwrapper</em>, потому что вам не нужно настраивать расположения сохранения информации о виртаульной среде инструментом (эти значения заданы по умолчанию). Все, что вам нужно сделать, это запустить следующую команду в командной строке:</p> + +<pre class="notranslate"><code>pip3 install virtualenvwrapper-win</code></pre> + +<p>Теперь вы можете создать новую виртуальную среду при помощи команды <code>mkvirtualen</code>.</p> + +<h3 id="Создание_виртуальной_среды">Создание виртуальной среды</h3> + +<p>После установки <em>virtualenvwrapper</em> и <em>virtualenvwrapper-win</em> работа с виртуальными средами становится одинаковой для всех платформ.</p> + +<p>Теперь вы можете создать новую виртуальную среду при помощи команды <code>mkvirtualenv</code>. Во время запуска команды вы увидите установку виртуальной среды (конкретные результаты команды очень зависят от платформы). После выполнения команды активируется новая виртуальная среда — заметить это вы можете по тому, что началом ввода будет название виртуальной среды в круглых скобках (как показано ниже).</p> + +<pre class="notranslate"><code>$ mkvirtualenv my_django_environment +Running virtualenv with interpreter /usr/bin/python3 ... +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/t_env7/bin/get_env_details +(my_django_environment) ubuntu@ubuntu:~$</code></pre> + +<p>Теперь вы находитесь внутри виртуальной области и можете установить Django и начать разработку.</p> + +<div class="note"> +<p><strong>Замечание</strong>: С этого момента в этой статье (и всем модуле) пожалуйста учитывайте, что любые команды запускаются в виртуальной среде Python, как та, что мы показали выше.</p> +</div> + +<h3 id="Использование_виртуальной_среды">Использование виртуальной среды</h3> + +<p>Есть еще несколько полезных команд, которые вам следует знать (в документации по инструменту их гораздо больше, но эти вы будете использовать регулярно):</p> + +<ul> + <li><code>deactivate</code> — Выход из текущей виртуальной среды Python</li> + <li><code>workon</code> — Список доступных виртуальных сред</li> + <li><code>workon name_of_environment</code> — Активация конкретной виртуальной среды Python</li> + <li><code>rmvirtualenv name_of_environment</code> — Удаление конкретной виртуальной среды.</li> +</ul> + +<h2 id="Установка_Django">Установка Django</h2> + +<p>После создания виртуальной среды и вызова <code>workon</code> для входа в нее вы можете использовать <em>pip3 </em>для установки Django. </p> + +<pre class="notranslate">pip3 install django +</pre> + +<p>Вы можете проверить установку Django, выполнив следующую команду (она просто проверяет, что Python может найти модуль Django):</p> + +<pre class="notranslate"># Linux/Mac OS X +python3 -m django --version + 1.10.10 + +# Windows +py -3 -m django --version + 1.10.10 +</pre> + +<div class="note"> +<p><strong>Замечание</strong>: Для Windows вы запускаете скрипты <em>Python 3</em> с префиксом команды <code>py -3</code>, в то время как для Linux/Mac OSX префикс - <code>python3</code>.</p> +</div> + +<div class="warning"> +<p><strong>Важно</strong>: В оставшейся части материала<strong> </strong>используется вариант команды <em>Linux</em> для вызова Python 3 (<code>python3</code>) . Если вы работаете в <em>Windows, </em>то просто замените этот префикс на: <code>py -3</code></p> +</div> + +<h2 id="Проверка_вашей_установки">Проверка вашей установки</h2> + +<p>Указанная выше проверка работает, но не представляет особого интереса.Более интересная проверка заключается в создании шаблона проекта и проверки его работы. Для ее выполнения перейдите в командной строке/терминале в место, где планируете сохранять приложения Django. Создайте папку для теста и перейдите в нее.</p> + +<pre class="notranslate">mkdir django_test +cd django_test +</pre> + +<p>Затем вы можете создать шаблон сайта "<em>mytestsite</em>" при помощи инструмента <strong>django-admin</strong>. После создания сайта вы можете перейти в папку, где найдете основной скрипт для управления проектами с именем <strong>manage.py</strong>.</p> + +<pre class="notranslate">django-admin startproject mytestsite +cd mytestsite</pre> + +<p>Мы можем запустить веб-сервер разработки из этой папки при помощи <strong>manage.py</strong> и команды <code>runserver</code>, как показано ниже.</p> + +<pre class="notranslate">$ <strong>python3 manage.py runserver </strong> +Performing system checks... + +System check identified no issues (0 silenced). + +You have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. +Run 'python manage.py migrate' to apply them. + +September 19, 2016 - 23:31:14 +Django version 1.10.1, using settings 'mysite.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. +</pre> + +<div class="note"> +<p><strong>Замечание</strong>: Указанная команда демонстрирует выполнение для Linux/Mac OS X. В настоящий момент вы можете проигнорировать предупреждения о "13 непримененных миграциях"!</p> +</div> + +<p>Как только сервер запущен, вы можете посмотреть сайт, перейдя по следующему адресу в вашем браузере: <code>http://127.0.0.1:8000/</code>. Вы должны увидеть, что сайт выглядит следующим образом:</p> + +<p><img alt="Django Skeleton App Homepage" src="https://mdn.mozillademos.org/files/15728/Django_Skeleton_Website_Homepage.png"></p> + +<ul> +</ul> + +<h2 id="Заключение">Заключение</h2> + +<p>Теперь у вас на компьютере установлена и запущена среда разработки Django.</p> + +<p>В разделе проверки вам коротко был показан способ создания нового сайта на Django при помощи <code>django-admin startproject</code> и его запуск в вашем браузере при помощи веб-сервера разработки (<code><strong>python3 manage.py runserver</strong></code>). В следующей статье мы подробнее рассмотрим этот процесс создания простого, но полноценного веб-приложения.</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Introduction">Введение в Django</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/development_environment">Установка среды разработки Django</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Руководство Django: Сайт локальной библиотеки</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/skeleton_website">Руководство Django Часть 2: Создание основы веб-сайта</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Models">Руководство Django Часть 3: Использование моделей</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Admin_site">Руководство Django Часть 4: Панель администрирования Django</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Home_page">Руководство Django Часть 5: Создание домашней страницы</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views">Руководство Django Часть 6: Основной список и детали представлений</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Sessions">Руководство Django Часть 7: Фреймворк сеансов</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Authentication">Руководство Django Часть 8: Авторизация пользователей и уровни доступа</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms">Руководство Django Часть 9: Работа с формами</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Testing">Руководство Django Часть 10: Тестирование веб-приложений Django</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Deployment">Руководство Django Часть 11: Разавертывание Django в производство</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/web_application_security">Безопасность веб-приложения Django</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Мини-блог на Django</a></li> +</ul> diff --git a/files/ru/learn/server-side/django/django_assessment_blog/index.html b/files/ru/learn/server-side/django/django_assessment_blog/index.html new file mode 100644 index 0000000000..59a1d9e1d2 --- /dev/null +++ b/files/ru/learn/server-side/django/django_assessment_blog/index.html @@ -0,0 +1,320 @@ +--- +title: 'Задание: DIY Джанго мини блог' +slug: Learn/Server-side/Django/django_assessment_blog +tags: + - Аттестация + - Бэкэнд + - Бэкэнд программирование + - Джанго + - Изучение + - Начинающий + - блог + - скриптовый кодинг +translation_of: Learn/Server-side/Django/django_assessment_blog +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</div> + +<p class="summary">В этом задании вы будете оценивать знания Django, которые вы приобрели в <a href="/en-US/docs/Learn/Server-side/Django">Django Web Framework (Python)</a>, чтобы создать очень простой блог.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Перед этим заданием, вы должны были проработать все статьи этого модуля.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Проверить понимание основ Django, включая конфигурации URL, модели, представления, формы и шаблоны.</td> + </tr> + </tbody> +</table> + +<h2 id="Краткое_описание_проекта">Краткое описание проекта</h2> + +<p>Страницы, которые должны отображаться, их URL-адреса и другие требования, перечислены ниже:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Page</th> + <th scope="col">URL</th> + <th scope="col">Requirements</th> + </tr> + </thead> + <tbody> + <tr> + <td>Home page</td> + <td><code>/</code> and <code>/blog/</code></td> + <td>Страница индекса, описывающая сайт.</td> + </tr> + <tr> + <td>List of all blog posts</td> + <td><code>/blog/blogs/</code></td> + <td> + <p>Список всех сообщений блога:</p> + + <ul> + <li>Доступно для всех пользователей из боковой панели.</li> + <li>Список отсортирован по дате публикации (от самого нового до самого старого).</li> + <li>Список разбит на группы по 5 статьям.</li> + <li>Элементы списка отображают название блога, дату публикации и автора.</li> + <li>Названия сообщений блога связаны с страницами подробных сведений о блоге.</li> + <li>Blogger (имена авторов) связаны с страницами подробных сведений о блоге.</li> + </ul> + </td> + </tr> + <tr> + <td>Blog author (blogger) detail page</td> + <td><code>/blog/blogger/<em><author-id></em></code></td> + <td> + <p>Информация для указанного автора (по id) и список постов:</p> + + <ul> + <li>Доступен для всех пользователей по ссылкам на автора в сообщениях в блогах и т. Д.</li> + <li>Содержит некоторые биографические данные в blogger/author.</li> + <li>Список отсортирован по дате добавления (от новых к старым).</li> + <li>Не разбит на страницы.</li> + <li>Элементы списка отображают только имя сообщения в блоге и дату публикации.</li> + <li>Названия блога связаны со страницей блога.</li> + </ul> + </td> + </tr> + <tr> + <td>Blog post detail page</td> + <td><code>/blog/<em><blog-id></em></code></td> + <td> + <p>Сведения о блоге.</p> + + <ul> + <li>Доступно для всех пользователей из списков блога.</li> + <li>Страница содержит сообщение в блоге: имя, автор, дата публикации и содержание.</li> + <li>Комментарии к сообщению в блоге должны отображаться внизу.</li> + <li>Комментарии должны быть отсортированы по порядку: от старых до самых последних.</li> + <li>Содержит ссылку для добавления комментариев на конец для зарегистрированных пользователей (см. Страницу формы комментариев)</li> + <li>В блогах и комментариях должен отображаться только обычный текст. Нет необходимости поддерживать какую-либо разметку HTML (например, ссылки, изображения, полужирный / курсив и т. Д.).</li> + </ul> + </td> + </tr> + <tr> + <td>List of all bloggers</td> + <td><code>/blog/bloggers/</code></td> + <td> + <p>Список блоггеров в системе:</p> + + <ul> + <li>Доступный для всех пользователей с боковой панели сайта</li> + <li>Имя блогера связано с блогом автора страницы.</li> + </ul> + </td> + </tr> + <tr> + <td>Comment form page</td> + <td><code>/blog/<em><blog-id></em>/create</code></td> + <td> + <p>Создать комментарий для публикации в блоге:</p> + + <ul> + <li>Доступно только зарегистрированным пользователям (только) из ссылки внизу страницы с подробными сведениями блога.</li> + <li>Отображает форму с описанием для ввода комментариев (дата публикации и блог недоступны для редактирования).</li> + <li>После того, как комментарий будет опубликован, страница будет перенаправлена на связанную страницу блога.</li> + <li>Пользователи не могут редактировать или удалять свои сообщения.</li> + <li>Вышедшие пользователи будут перенаправлены на страницу входа в систему, чтобы добавить комментарии. После входа в систему они будут перенаправлены на страницу блога, которую они хотели бы прокомментировать.</li> + <li>Страницы комментариев должны содержать имя / ссылку на комментарий блога.</li> + </ul> + </td> + </tr> + <tr> + <td>User authentication pages</td> + <td><code>/accounts/<em><standard urls></em></code></td> + <td> + <p>Стандартные страницы аутентификации Django для входа, выхода и установки пароля:</p> + + <ul> + <li>Вход / выход должен быть доступен через ссылки боковой панели.</li> + </ul> + </td> + </tr> + <tr> + <td>Admin site</td> + <td><code>/admin/<em><standard urls></em></code></td> + <td> + <p>Админ-сайт должен быть включен, чтобы разрешить создание / редактирование / удаление сообщений в блогах, авторов блога и комментариев блога (это механизм для создания блоггеров в блогах):</p> + + <ul> + <li>В админ панеле должен отображаться список комментариев в строке (внизу каждого сообщения в блоге).</li> + <li>Имена комментариев в админке создаются усеканием описания комментария до 75 знаков</li> + <li>Другие типы записей могут использовать базовую регистрацию.</li> + </ul> + </td> + </tr> + </tbody> +</table> + +<p>Кроме того, вы должны написать некоторые базовые тесты для проверки:</p> + +<ul> + <li>Все поля модели имеют правильную метку и длину.</li> + <li>Все модели имеют ожидаемое имя объекта (например,<code> __str__()</code>выдает ожидаемое значение).</li> + <li>Модели имеют ожидаемый URL для отдельных записей в блогах и комментариях (например,<code>get_absolute_url()</code> возвращает ожидаемый URL-адрес).</li> + <li>Страница BlogListView (страница на всех блогах) доступна в ожидаемом месте (например, /blog/blogs)</li> + <li>Страница BlogListView (страница на всех блогах) доступна на ожидаемом именованном URL-адресе (например, 'blogs')</li> + <li>Страница BlogListView (страница на всех блогах) использует ожидаемый шаблон (например, по умолчанию)</li> + <li>BlogListView разбивает записи на 5 (по крайней мере, на первой странице)</li> +</ul> + +<div class="note"> +<p><strong>Заметка</strong>: Конечно, есть много других тестов, которые вы можете запустить. Используйте на свое усмотрение, но мы ожидаем, что вы сделаете хотя бы тесты выше.</p> +</div> + +<p>В следующем разделе показаны <a href="#Screenshots">скриншоты</a> сайта, который выполняет перечисленные выше требования.</p> + +<h2 id="Скриншоты">Скриншоты</h2> + +<p>Следующий скриншот - пример того, что должна выводить готовая программа.</p> + +<h3 id="Список_всех_сообщений_в_блоге">Список всех сообщений в блоге</h3> + +<p>Это отображает список всех сообщений в блоге (доступны из ссылки "All blogs" на боковой панели). Что нужно отметить:</p> + +<ul> + <li>На боковой панели также списки вошедшего в систему пользователя.</li> + <li>Индивидуальные блоги и блогеры доступны в виде ссылок на странице.</li> + <li>Разбивка включена (в группах по 5)</li> + <li>Показ от новых к старым.</li> +</ul> + +<p><img alt="List of all blogs" src="https://mdn.mozillademos.org/files/14319/diyblog_allblogs.png" style="border-style: solid; border-width: 1px; display: block; height: 363px; margin: 0px auto; width: 986px;"></p> + +<h3 id="Список_всех_блоггеров">Список всех блоггеров</h3> + +<p> </p> + +<p>Это ссылки на всех блоггеров в "All bloggers" по ссылке, которая на боковой панели. В этом случае мы можем увидеть на боковой панели, что ни один пользователь не вошел в систему.</p> + +<p><img alt="List of all bloggers" src="https://mdn.mozillademos.org/files/14321/diyblog_blog_allbloggers.png" style="border-style: solid; border-width: 1px; display: block; height: 256px; margin: 0px auto; width: 493px;"></p> + +<h3 id="Подробная_страница_блога">Подробная страница блога</h3> + +<p>Это показывает подробную страницу для конкретного блога.</p> + +<p><img alt="Blog detail with add comment link" src="https://mdn.mozillademos.org/files/14323/diyblog_blog_detail_add_comment.png" style="border-style: solid; border-width: 1px; display: block; height: 640px; margin: 0px auto; width: 986px;"></p> + +<p>Обратите внимание, что комментарии имеют дату <em>и</em> время, и расположены в порядке от самых старых до новейших (противоположно порядку ведения блога). В конце у нас есть ссылка для доступа к форме, чтобы добавить новый комментарий. Если пользователь не вошел в систему, мы бы увидели предложение войти в систему.</p> + +<p><img alt="Comment link when not logged in" src="https://mdn.mozillademos.org/files/14325/diyblog_blog_detail_not_logged_in.png" style="border-style: solid; border-width: 1px; display: block; height: 129px; margin: 0px auto; width: 646px;"></p> + +<h3 id="Добавить_форму_комментария">Добавить форму комментария</h3> + +<p>Это форма добавления комментариев. Обратите внимание, что мы вошли в систему. Когда это удастся, мы должны вернуться к связанной странице блога.</p> + +<p><img alt="Add comment form" src="https://mdn.mozillademos.org/files/14329/diyblog_comment_form.png" style="border-style: solid; border-width: 1px; display: block; height: 385px; margin: 0px auto; width: 778px;"></p> + +<h3 id="Об_авторе">Об авторе</h3> + +<p>Здесь отображается информация о блоггере вместе со списком его блогов.</p> + +<p><img alt="Blogger detail page" src="https://mdn.mozillademos.org/files/14327/diyblog_blogger_detail.png" style="border-style: solid; border-width: 1px; display: block; height: 379px; margin: 0px auto; width: 982px;"></p> + +<h2 id="Завершающие_шаги">Завершающие шаги</h2> + +<p>В следующих разделах описывается, что вам нужно делать.</p> + +<ol> + <li>Создайте скелет проекта и веб-приложение для сайта (как описано в <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a>). Вы можете использовать «diyblog» для имени проекта и «blog» для имени приложения.</li> + <li>Создавайте модели для записей в блогах, комментариев и любых других необходимых объектов. + <ul> + <li>Каждый комментарий будет иметь только один блог, но блог может иметь много комментариев.</li> + <li>Посты в блоге и комментарии должны быть отсортированы по дате поста.</li> + <li>Не каждый пользователь обязательно будет автором блога, хотя любой пользователь может быть комментатором.</li> + <li>Блог автора также должен включать информацию о себе.</li> + </ul> + </li> + <li>Запустите миграцию для новых моделей и создайте суперпользователя.</li> + <li>Используйте админ панель, чтобы создать какой-нибудь пример блога и комментарии в блогах.</li> + <li>Создайте представления, шаблоны, и URL-конфигурации для публикации блога и списка страниц блоггера.</li> + <li>Создайте представления, шаблоны, и URL-конфигурации для публикации блога и подробных страниц блоггера.</li> + <li>Создайте страницу с формой для добавления новых комментариев (не забудьте сделать это доступным только для зарегистрированных пользователей!)</li> +</ol> + +<h2 id="Советы_и_подсказки">Советы и подсказки</h2> + +<p>Этот проект очень похож на <a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> учебник. Вы сможете настроить скелет, поведение входа пользователя / выхода из системы, поддержку статических файлов, представлений, URL-адресов, форм, базовых шаблонов и конфигурации админ-панели, используя почти все те же подходы.</p> + +<p>Некоторые общие рекомендации:</p> + +<ol> + <li>Индексная страница (index page) может быть реализована в качестве основной функции представления и шаблона (как и для locallibrary).</li> + <li>Просмотр списка публикаций блога и блогеров, а также подробное представление для сообщений в блоге можно создать с помощью <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">generic list and detail views</a>.</li> + <li>Список постов в блоге конкретного автора может быть создан с помощью общего списка Blog list view и фильтрация для объекта блога, соответствующего указанному автору. + <ul> + <li>Вам придется реализовать <code>get_queryset(self)</code> для фильтрации (как и в нашем классе библиотеки <code>LoanedBooksAllListView</code>) и получить информацию об авторе из URL-адреса.</li> + <li>Вам также необходимо передать имя автора на страницу в контексте. Чтобы сделать это в представлении на основе классов, вам необходимо реализовать <code>get_context_data()</code> (обсуждается ниже).</li> + </ul> + </li> + <li>Форма <em>добавления комментариев</em> может быть создана с использованием функционального представления (и связанной модели и формы) или с использованием общего <code>CreateView</code>. Если вы используете <code>CreateView</code> (рекомендуется): + <ul> + <li>Вам также нужно будет передать имя блога на страницу комментариев в контексте (реализовать <code>get_context_data()</code> как обсуждается ниже).</li> + <li>Форма должна отображать только комментарий «описание» для записи пользователя (дата и связанная с ними запись в блоге не должны редактироваться). Поскольку они не будут в форме, ваш код должен будет установить автора комментария в <code> form_valid()</code> функцию, поэтому он может быть сохранен в модели (<a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/#models-and-request-user">as described here</a> — Django docs). В этой же функции мы устанавливаем связанный блог. Возможная реализация показана ниже (<code>pk</code> это идентификатор блога, переданный из URL / URL конфигурации ). + <pre class="brush: python"> def form_valid(self, form): + """ + Add author and associated blog to form data before setting it as valid (so it is saved to model) + """ + #Add logged-in user as author of comment + form.instance.author = self.request.user + #Associate comment with blog based on passed id + form.instance.blog=get_object_or_404(Blog, pk = self.kwargs['pk']) + # Call super-class form validation behaviour + return super(BlogCommentCreate, self).form_valid(form) +</pre> + </li> + <li> Для успешного перенаправления после проверки формы вам нужно будет указать URL-адрес; это должен быть оригинальный блог. Для этого вам нужно будет переопределить <code>get_success_url()</code> и «обратный» URL-адрес для исходного блога. Вы можете получить требуемый ID блога, используя <code>self.kwargs</code> атрибут, как показано в методе <code>form_valid()</code> выше.</li> + </ul> + </li> +</ol> + +<p>Мы кратко говорили о передаче контекста шаблону в представлении на основе классов в теме <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views#Overriding_methods_in_class-based_views">Django Tutorial Part 6: Generic list and detail views</a>. Для этого вам нужно переопределить <code>get_context_data()</code> (сначала получить существующий контекст, обновить его любыми дополнительными переменными, которые вы хотите передать шаблону, а затем вернуть обновленный контекст). Например, фрагмент кода ниже показывает, как вы можете добавить объект blogger в контекст на основе его <code>BlogAuthor</code> id.</p> + +<pre class="brush: python">class SomeView(generic.ListView): + ... + + def get_context_data(self, **kwargs): + # Call the base implementation first to get a context + context = super(SomeView, self).get_context_data(**kwargs) + # Get the blogger object from the "pk" URL parameter and add it to the context + context['blogger'] = get_object_or_404(BlogAuthor, pk = self.kwargs['pk']) + return context +</pre> + +<h2 id="Аттестация">Аттестация</h2> + +<p>Оценка этого задания <a href="https://github.com/mdn/django-diy-blog/blob/master/MarkingGuide.md">доступна здесь на Github</a>. Эта оценка в основном основана на том, насколько хорошо ваше приложение соответствует требованиям, перечисленным выше, хотя есть некоторые части оценки, которые проверяют ваш код на использование соответствующих моделей и что вы написали хотя бы некоторый тестовый код. Когда вы закончите, вы можете проверить по нашему <a href="https://github.com/mdn/django-diy-blog">готовому примеру</a> который соответствует "высокой оценке проекта".</p> + +<p>После того, как вы завершили этот модуль, вы также закончили весь контент MDN для изучения базового веб-сайта на сервере Django! Надеемся, вам понравится этот модуль и вы почувствуете, что у вас есть хорошее понимание основ!</p> + +<p>{{PreviousMenu("Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</p> + +<p> </p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/server-side/django/forms/index.html b/files/ru/learn/server-side/django/forms/index.html new file mode 100644 index 0000000000..3b155495a9 --- /dev/null +++ b/files/ru/learn/server-side/django/forms/index.html @@ -0,0 +1,650 @@ +--- +title: 'Руководство часть 9: Работа с формами' +slug: Learn/Server-side/Django/Forms +tags: + - HTML + - django + - Для начинающих + - Руководство + - Серверная сторона + - Формы + - Формы Django +translation_of: Learn/Server-side/Django/Forms +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</div> + +<p class="summary">На этом уроке мы покажем вам процесс работы с HTML-формами в Django. В частности, продемонстрируем самый простой способ построения формы для создания, обновления и удаления экземпляров модели. При этом мы расширим сайт <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">местной библиотеки</a>, чтобы библиотекари могли обновлять книги, создавать, обновлять и удалять авторов, используя наши собственные формы (а не возможности приложения администратора).</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Завершите все предыдущие учебные темы, в том числе <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions">Django руководство часть 8: Аутентификация пользователя и права доступа</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Научиться понимать, как создавать формы, чтобы получать информацию от пользователей и обновлять базу данных. Узнать, как обобщенные классы отображения форм могут значительно упростить процесс создания форм при работе с одной моделью.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p><a href="/en-US/docs/Web/Guide/HTML/Forms">HTML форма </a>- это группа из одного или нескольких полей/виджетов на веб-странице, которая используется для сбора информации от пользователей для последующей отправки на сервер. Формы являются гибким механизмом сбора пользовательских данных, поскольку имеют целый набор виджетов для ввода различных типов данных, как то: текстовые поля, флажки, переключатели, установщики дат и т. д. Формы являются относительно безопасным способом взаимодействия пользовательского клиента и сервера, поскольку они позволяют отправлять данные в POST-запросах, применяя защиту от <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D0%BB%D0%BA%D0%B0_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">Межсайтовой подделки запроса</a> (<em><span lang="en">Сross Site Request Forgery - CSRF</span></em>)</p> + +<p>Пока что мы не создавали каких-либо форм в этом учебнике, но мы встречались с ними в административной панели Django — например, снимок экрана ниже показывает форму для редактирования одной из наших моделей книг (<a href="/en-US/docs/Learn/Server-side/Django/Models">Book</a>), состоящую из нескольких списков выбора и текстовых редакторов. </p> + +<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>Работа с формами может быть достаточно сложной! Разработчикам надо описать форму на HTML, проверить ее валидность, а также, на стороне сервера, проверять введенные пользователем данные (а возможно и на стороне клиента), далее, в случае возникновения ошибок необходимо опять показать пользователю форму и, при этом, указать на то, что пошло не так, в случае же успеха проделать с данными необходимые операции и каким-то образом проинформировать об этом пользователя. Django, при работе с формами, берет большую часть, описанной выше работы, на себя. Он предоставляет фреймворк, который позволяет вам определять форму и ее поля программно, а затем использовать эти объекты и для генерации непосредственно кода HTML-формы, и для контроля за процессом валидации и других пользовательский взаимодействий с формой.</p> + +<p>В данной части руководства мы покажем вам несколько способов создания и работы с формами и, в частности, как применение обобщенных классов работы с формой могут значительно уменьшить необходимый объем работы. Кроме того, мы расширим возможности нашего сайта <em>LocalLibrary,</em> путем добавления функционала для библиотекарей, который будет позволять им обновлять информацию - добавим страницы для создания, редактирования, удаления книг и авторов (воспроизведем и расширим стандартные возможности административной части сайта).</p> + +<h2 id="Формы_HTML">Формы HTML</h2> + +<p>Начнем мы с краткого обзора <a href="/en-US/docs/Web/Guide/HTML/Forms">Форм HTML</a>. Рассмотрим простую форму HTML, имеющую поле для ввода имени некоторой "команды" ("team"), и, связанную с данным полем, текстовой меткой:</p> + +<p><img alt="Simple name field example in HTML form" src="https://mdn.mozillademos.org/files/14117/form_example_name_field.png" style="border-style: solid; border-width: 1px; display: block; height: 44px; margin: 0px auto; width: 399px;"></p> + +<p>Форма описывается на языке HTML как набор элементов, расположенных внутри парных тэгов <code><form>...</form></code>. Любая форма содержит как минимум одно поле-тэг <code>input</code> типа <code>type="submit"</code>.</p> + +<pre class="brush: html notranslate"><form action="/team_name_url/" method="post"> + <label for="team_name">Enter name: </label> + <input id="team_name" type="text" name="name_field" value="Default name for team."> + <input type="submit" value="OK"> +</form></pre> + +<p>Здесь у нас только одно поле для ввода имени команды, но форма <em>может</em> иметь любое количество элементов ввода и, связанных с ними, текстовых меток. Атрибут элемента <code>type</code> определяет какого типа виджет будет показан в данной строке. Атрибуты <code>name</code> и <code>id</code> используются для однозначной идентификации данного поля в JavaScript/CSS/HTML, в то время как <code>value</code> содержит значение для поля (когда оно показывается в первый раз). Текстовая метка добавляется при помощи тэга <code style="font-style: normal; font-weight: normal;">label</code> (смотрите "Enter name", в предыдущем фрагменте) и имеет атрибут <code style="font-style: normal; font-weight: normal;">for</code> со значением идентификатора <code style="font-style: normal; font-weight: normal;">id</code>, того поля, с которым данная текстовая метка связана.</p> + +<p>Элемент <code>input</code> с <code>type="submit"</code> будет показана как кнопка (по умолчанию), нажав на которую, пользователь отправляет введенные им данные на сервер (в данном случае только значение поля с идентификатором <code>team_name</code>). Атрибуты формы определяют каким методом будут отправлены данные на сервер (атрибут <code>method</code>) и куда (атрибут <code>action</code>):</p> + +<ul> + <li><code>action</code>: Это ресурс/URL-адрес куда будут отправлены данные для обработки. Если значение не установлено (то есть, значением поля является пустая строка), тогда данные будут отправлены в отображение (функцию, или класс), которое сформировало текущую страницу.</li> + <li><code>method</code>: HTTP-метод, используемый для отправки данных: <em>post</em>, или <em>get</em>. + <ul> + <li>Метод <code>POST</code> должен всегда использоваться если отправка данных приведет к внесению изменений в базе данных на сервере. Применение данного метода должно повысить уровень защиты от CSRF.</li> + <li>Метод <code>GET</code> должен применяться только для форм, действия с которыми не приводят к изменению базы данных (например для поисковых запросов). Кроме того, данный метод рекомендуется применять для создания внешних ссылок на ресурсы сайта.</li> + </ul> + </li> +</ul> + +<p>Ролью сервера в первую очередь является отрисовка начального состояния формы — либо содержащей пустые поля, либо с установленными начальными значениями. После того как пользователь нажмет на кнопку, сервер получит все данные формы, а затем должен провести их валидацию. В том случае, если форма содержит неверные данные, сервер должен снова отрисовать форму, показав при этом поля с правильными данными, а также сообщения, описывающие "что именно пошло не так". В тот момент, когда сервер получит запрос с "правильными" данными он должен выполнить все необходимые действия (например, сохранение данных, возврат результата поиска, загрузка файла и тому подобное), а затем, в случае необходимости, проинформировать пользователя.</p> + +<p>Как вы видите, создание HTML-формы, валидация и возврат данных, переотрисовка введенных значений, при необходимости, а также выполнение желаемых действий с "правильными данными", в целом, может потребовать довольно больших усилий для того, чтобы все "заработало". Django делает этот процесс намного проще, беря на себя некоторые "тяжелые" и повторяющиеся участки кода!</p> + +<h2 id="Процесс_управления_формой_в_Django_2"><a id="Процесс_управления_формой_в_Django" name="Процесс_управления_формой_в_Django">Процесс управления формой в Django</a></h2> + +<p>Управление формами в Django использует те же самые техники, которые мы изучали в предыдущих частях руководства (при показе информации из наших моделей): отображение получает запрос, выполняет необходимые действия, включающие в себя чтение данных из моделей, генерацию и возврат страницы HTML (из шаблона, в который передается <em>контекст,</em> содержащий данные, которые и будут показаны). Что делает данный процесс более сложным, так это то, что серверной части надо дополнительно обработать данные, предоставленные пользователем и, в случае возникновения ошибок, снова перерисовать страницу.</p> + +<p>Диаграмма, представленная ниже, демонстрирует процесс работы с формой в Django, начиная с запроса страницы, содержащей форму (выделено зеленым цветом).</p> + +<p><img alt="Updated form handling process doc." src="https://mdn.mozillademos.org/files/14205/Form%20Handling%20-%20Standard.png" style="display: block; height: 569px; margin: 0px auto; width: 800px;"></p> + +<p>В соответствии с данной диаграммой, главными моментами, которые берут на себя формы Django являются:</p> + +<ol> + <li>Показ формы по умолчанию при первом запросе со стороны пользователя. + <ul> + <li>Форма может содержать пустые поля (например, если вы создаете новую запись в базе данных), или они (поля) могут иметь начальные значения (например, если вы изменяете запись, или хотите заполнить ее каким-либо начальным значением).</li> + <li>Форма в данный момент является <em>несвязанной</em>, потому что она не ассоциируется с какими-либо введенными пользователем данными (хотя и может иметь начальные значения).</li> + </ul> + </li> + <li>Получение данных из формы (из HTML-формы) со стороны клиента и связывание их с формой (классом формы) на стороне сервера. + <ul> + <li>Связывание данных с формой означает, что данные, введенные пользователем, а также возможные ошибки, при переотрисовке в дальнейшем, будут относиться именно к данной форме, а не к какой-либо еще.</li> + </ul> + </li> + <li>Очистка и валидация данных. + <ul> + <li>Очистка данных - это их проверка на наличие возможных значений, или вставок в поля ввода (то есть очистка - это удаление неправильных символов, которые потенциально могут использоваться для отправки вредоносного содержимого на сервер), с последующей конвертацией очищеных данных в подходящие типы данных Python.</li> + <li>Валидация проверяет, значения полей (например, правильность введенных дат, их диапазон и так далее)</li> + </ul> + </li> + <li>Если какие-либо данные являются неверными, то выполнение перерисовки формы, но на этот раз, с уже введенными пользователем данными и сообщениями об ошибках, описывающих возникшие проблемы.</li> + <li>Если все данные верны, то исполнение необходимых действий (например, сохранение данных, отправка писем, возврат результата поиска, загрузка файла и так далее)</li> + <li>Когда все действия были успешно завершены, то перенаправление пользователя на другую страницу.</li> +</ol> + +<p>Django предоставляет несколько инстументов и приемов, которые помогают вам во время выполнения задач, описанных выше. Наиболее фундаметальным из них является класс <code>Form</code>, который упрощает генерацию HTML-формы и очистку/валидацию ее данных. В следующем разделе мы опишем процесс работы с формами при помощи практического примера по созданию страницы, которая позволит библиотекарям обновлять информацию о книгах.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Понимание того, как используется класс <code>Form</code> поможет вам когда мы будем рассматривать классы фреймворка Django, для работы с формами более "высокого уровня".</p> +</div> + +<h2 id="HTML-форма_обновления_книги._Класс_Form_и_функция_отображения">HTML-форма обновления книги. Класс Form и функция отображения</h2> + +<p>Данная глава будет посвещена процессу создания страницы, которая позволит библиотекарям обновлять информацию о книгах (в частности, вводить дату возврата книги). Для того, чтобы сделать это мы создадим форму, которая позволит пользователям вводить значение дат. Мы проинициализируем поле датой, равной 3 неделям, начиная с текущего дня, и, для того, чтобы библотекарь не имел возможность ввести "неправильную" дату, мы добавим валидацию введенных значений, которая будет проверять, чтобы введенная дата не относилась к прошлому, или к слишком далекому будущему. Когда будет получена "правильная" дата мы запишем ее значение в поле <code>BookInstance.due_back</code>.</p> + +<p>Данный пример будет использовать отображение на основе функции, а также продемонстрирует работу с классом <code>Form</code>. Следующие разделы покажут изменения, которые вам надо сделать, чтобы продемонстрировать работу форм в проекте <em>LocalLibrary</em>.</p> + +<h3 id="Класс_Form">Класс Form</h3> + +<p>Класс <code>Form</code> является сердцем системы Django при работе с формами. Он определяет поля формы, их расположение, показ виджетов, текстовых меток, начальных значений, валидацию значений и сообщения об ошибках для "неправильных" полей (если таковые имеются). Данный класс, кроме того, предоставляет методы для отрисовки самого себя в шаблоне при помощи предопределенных форматов (таблицы, списки и так далее), или для получения значения любого элемента (позволяя выполнять более точную отрисовку).</p> + +<h4 id="Объявление_класса_формы_Form">Объявление класса формы Form</h4> + +<p>Синтаксис объявления для класса формы <code>Form</code> очень похож на объявление класса модели <code>Model</code>, он даже использует те же типы полей (и некоторые похожие параметры). Это существенный момент, поскольку в обоих случаях нам надо убедиться, что каждое поле управляет правильным типом данных, соответствует нужному диапазону (или другому критерию) и имеет необходимое описание для показа/документации.</p> + +<p>Для того, чтобы создать класс с функционалом базового класса <code>Form</code> мы должны импорировать библиотеку <code>forms</code>, наследовать наш класс от класса <code>Form</code>, а затем объявить поля формы. Таким образом, самый простой класс формы в нашем случае будет иметь вид, показанный ниже:</p> + +<pre class="brush: python notranslate">from django import forms + +class RenewBookForm(forms.Form): + renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).") +</pre> + +<h4 id="Поля_формы">Поля формы</h4> + +<p>В нашем случае мы имеем одно поле типа <code><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#datefield">DateField</a></code>, которое служит для ввода обновленной даты возврата книги, которое будет отрендерено в HTML с пустым значением и текстовой меткой "<em>Renewal date:</em>", а также текстовым описанием: "<em>Enter a date between now and 4 weeks (default 3 weeks).</em>" Так как никаких дополнительных опций мы не определяем, то поле будет "получать" даты в следующем формате <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#django.forms.DateField.input_formats">input_formats</a>: YYYY-MM-DD (2016-11-06), MM/DD/YYYY (02/26/2016), MM/DD/YY (10/25/16), а для отрисовки по умолчанию, будет использовать <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#widget">виджет</a>: <a href="https://docs.djangoproject.com/en/1.10/ref/forms/widgets/#django.forms.DateInput">DateInput</a>.</p> + +<p>Существует множество других типов полей для класса формы, которые по своему функционалу подобны соответствующим им эквивалентам типов полей для классов моделей: <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#booleanfield"><code>BooleanField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#charfield"><code>CharField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#choicefield"><code>ChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#typedchoicefield"><code>TypedChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#datefield"><code>DateField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#datetimefield"><code>DateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#decimalfield"><code>DecimalField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#durationfield"><code>DurationField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#emailfield"><code>EmailField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#filefield"><code>FileField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#filepathfield"><code>FilePathField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#floatfield"><code>FloatField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#imagefield"><code>ImageField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#integerfield"><code>IntegerField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#genericipaddressfield"><code>GenericIPAddressField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#multiplechoicefield"><code>MultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#typedmultiplechoicefield"><code>TypedMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#nullbooleanfield"><code>NullBooleanField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#regexfield"><code>RegexField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#slugfield"><code>SlugField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#timefield"><code>TimeField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#urlfield"><code>URLField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#uuidfield"><code>UUIDField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#combofield"><code>ComboField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#multivaluefield"><code>MultiValueField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#splitdatetimefield"><code>SplitDateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#modelmultiplechoicefield"><code>ModelMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#modelchoicefield"><code>ModelChoiceField</code></a>.</p> + +<p>Общие аргументы для большинства полей перечислены ниже:</p> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#required">required</a>: Если <code>True</code>, то данное поле не может быть пустым, или иметь значение<code>None</code>. Данное значение установлено по умолчанию.</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#label">label</a>: Тектовая метка, используемая для рендеринга поля в HTML-код. Если <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#label">label</a> не определена, то Django попытается создать ее значение при помощи имени поля, переводя первый символ в верхний регистр, а также заменяя символы подчеркивания пробелами (например, для переменной с именем renewal_date, будет создан следующий текст метки: <em>Renewal date</em>).</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#label-suffix">label_suffix</a>: По умолчанию показывает двоеточие после текста метки (например, Renewal date<strong>:</strong>). Данный параметр позволяет вам указать любой суффикс по вашему желанию.</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#initial">initial</a>: Начальное значение для поля при показе формы.</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#widget">widget</a>: Применяемый виджет для поля.</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#help-text">help_text</a> (как показано в примере выше): Дополнительный текст, который может быть показан на форме, для описания того, как использовать поле.</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#error-messages">error_messages</a>: Список сообщений об ошибках для данного поля. Вы можете переопределить его своими сообщениями, при необходимости.</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#validators">validators</a>: Список функций, которые будут вызваны для валидации, введенного в поле значения.</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#localize">localize</a>: Позволяет осуществить локализацию данных поля формы (например, формат ввода числовых значений, или дат).</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#disabled">disabled</a>: Если установлено в <code>True</code>, то поле показывается, но его значение изменить нельзя. По умолчанию равно <code>False</code>.</li> +</ul> + +<h4 id="Валидация">Валидация</h4> + +<p>Django предоставляет несколько мест где вы можете осуществить валидацию ваших данных. Простейшим способом проверки значения одиночного поля является переопределение метода<code>clean_<strong><fieldname></strong>()</code> (здесь, <code><strong><fieldname></strong></code> это имя поля, которое вы хотите проверить). Например, мы хотим проверить, что введенное значение <code>renewal_date</code> находится между текущей датой и 4 неделями в будущем. Для этого мы создаем метод <code>clean_<strong>renewal_date</strong>()</code>, как показано ниже:</p> + +<pre class="brush: python notranslate">from django import forms + +<strong>from django.core.exceptions import ValidationError +from django.utils.translation import ugettext_lazy as _ +import datetime #for checking renewal date range. +</strong> +class RenewBookForm(forms.Form): + renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).") + +<strong> def clean_renewal_date(self): + data = self.cleaned_data['renewal_date'] + + #Проверка того, что дата не выходит за "нижнюю" границу (не в прошлом). + if data < datetime.date.today(): + raise ValidationError(_('Invalid date - renewal in past')) + + #Проверка того, то дата не выходит за "верхнюю" границу (+4 недели). + if data > datetime.date.today() + datetime.timedelta(weeks=4): + raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) + + # Помните, что всегда надо возвращать "очищенные" данные. + return data</strong></pre> + +<p>Необходимо отметить два важных момента. Первый это то, что мы получаем наши данные при помощи словаря <code>self.cleaned_data['renewal_date']</code>, а затем в конце возвращаем полученное значение, для проведения необходимых проверок. Данный шаг позволяет нам, при помощи валидаторов, получить "очищенные", проверенные, а затем, приведенные к стандартным типам, данные (в нашем случае к типу Python <code>datetime.datetime</code>).</p> + +<p>Второй момент касается того случая, когда наше значение "выпадает за рамки" и мы "выкидываем" исключение <code>ValidationError</code>, в котором указываем текст, который мы хотим показать на форме, для случая когда были введены неправильные данные. Пример, показанный выше, оборачивает данный текст при помощи <a href="https://docs.djangoproject.com/en/1.10/topics/i18n/translation/">функции перевода Django</a> <code>ugettext_lazy()</code> (импортирумую через <code>_()</code>), которая может вам пригодиться, если вы планируете перевести ваш сайт в будущем.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Существует множество других методов и примеров валидации различных форм, которые можно найти в <a href="https://docs.djangoproject.com/en/1.10/ref/forms/validation/">Формы и валидация поля</a> (Django docs). Например, в случае, если у вас имеется много полей, которые зависят один от другого, вы можете переопределить функцию <a href="https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.Form.clean">Form.clean()</a> и, при необходимости, "выкинуть" <code>ValidationError</code>.</p> +</div> + +<p>В целом, это все, что нам понадобится для создания формы в данном примере!</p> + +<h4 id="Копирование_класса_формы">Копирование класса формы</h4> + +<p>Создайте и откройте файл <strong>locallibrary/catalog/forms.py</strong>, а затем скопируйте в него весь код, указанный в предыдущем фрагменте.</p> + +<h3 id="Конфигурация_URL-адресов">Конфигурация URL-адресов</h3> + +<p>Перед созданием отображения давайте добавим соответствующую конфигурацию URL-адреса для страницы обновления книг. Скопируйте следующий фрагмент в нижнюю часть файла<strong> locallibrary/catalog/urls.py</strong>.</p> + +<pre class="brush: python notranslate">urlpatterns += [ + url(r'^book/(?P<pk>[-\w]+)/renew/$', views.renew_book_librarian, name='renew-book-librarian'), +]</pre> + +<p>Данная конфигурация перенаправит запросы с адресов формата <strong>/catalog/book/<em><bookinstance id></em>/renew/</strong> в функции с именем <code>renew_book_librarian()</code> в <strong>views.py</strong>, туда же передаст идентификатор id записи <code>BookInstance</code> в качестве параметра с именем <code>pk</code>. Шаблон соответствует только если <strong>pk </strong>это правильно отформатированный <strong>uiid.</strong></p> + +<div class="note"> +<p><strong>Примечание</strong>: Вместо имени "pk" мы можем использовать любое другое, по нашему желанию, потому что мы имеем полный контроль над функцией отображения (которого у нас нет в случае использования встроенного обобщенного класса отображения, который ожидает параметр с определенным именем). Тем не менее имя <code>pk</code> является понятным сокращением от "primary key", поэтому мы его тут и используем!</p> +</div> + +<h3 id="Отображение">Отображение</h3> + +<p>Как было отмечено в разделе <a href="#Процесс_управления_формой_в_Django">Процесс управление формой в Django</a>, отображение должно отрендерить форму по умолчанию, когда она вызывается в первый раз и, затем, перерендерить ее, в том случае, если возникли какие-либо ошибки при работе с ее полями. В случае же успеха, после обработки "правильных" данных отображение перенаправляет пользователя на новую (другую) страницу. Для того чтобы выполнить все эти действия, отображение должно знать вызвано ли оно в первый раз для отрисовки формы по умолчанию, а если это не так, то провести валидацию полученных данных.</p> + +<p>Для форм, которые используют <code>POST</code>-запрос при отправке информации на сервер, наиболее общей схемой проверки данного факта является следующая строка кода <code>if request.method == 'POST':</code>. <code>GET</code>-запросу, а также первому запросу формы, в таком случае соответствует блок <code>else</code>. Если вы хотите отправлять свои данные в виде <code>GET</code>-запроса, то в таком случае приемом проверки того факта, что данный запрос первый (или последующий), является получение значения какого-либо поля формы (например, если значение скрытого поля формы пустое, то данный вызов является первым).</p> + +<p>Процесс обновления книги приводит к изменению информации в базе данных, таким образом, в соответствии с нашими соглашениями, в таком случае мы должны применять запрос типа <code>POST</code>. Фрагмент кода, представленный ниже, показывает (наиболее общую) схему работы для таких запросов. </p> + +<pre class="brush: python notranslate">from django.shortcuts import get_object_or_404 +from django.http import HttpResponseRedirect +from django.urls import reverse +import datetime + +from .forms import RenewBookForm + +def renew_book_librarian(request, pk): + book_inst = get_object_or_404(BookInstance, pk=pk) + + # Если данный запрос типа POST, тогда +<strong> if request.method == 'POST':</strong> + + # Создаем экземпляр формы и заполняем данными из запроса (связывание, binding): + form = RenewBookForm(request.POST) + + # Проверка валидности данных формы: + <strong>if form.is_valid():</strong> + # Обработка данных из form.cleaned_data + #(здесь мы просто присваиваем их полю due_back) + book_inst.due_back = form.cleaned_data['renewal_date'] + book_inst.save() + + # Переход по адресу 'all-borrowed': + return HttpResponseRedirect(reverse('all-borrowed') ) + + # Если это GET (или какой-либо еще), создать форму по умолчанию. +<strong> else:</strong> + proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) + form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,}) + + return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre> + +<p>В первую очередь мы импортируем наш класс формы (<code>RenewBookForm</code>), а также другие необходимые объекты и методы:</p> + +<ul> + <li><code><a href="https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#get-object-or-404">get_object_or_404()</a></code>: Возвращает определенный объект из модели в зависимости от значения его первичного ключа, или выбрасывает исключение <code>Http404</code>, если данной записи не существует. </li> + <li><code><a href="https://docs.djangoproject.com/en/1.10/ref/request-response/#django.http.HttpResponseRedirect">HttpResponseRedirect</a></code>: Данный класс перенаправляет на другой адрес (HTTP код статуса 302). </li> + <li><code><a href="https://docs.djangoproject.com/en/1.10/ref/urlresolvers/#django.urls.reverse">reverse()</a></code>: Данная функция генерирует URL-адрес при помощи соответствующего имени URL конфигурации/преобразования и дополнительных аргументов. Это эквивалент Python тэгу <code>url</code>, которые мы использовали в наших шаблонах.</li> + <li><code><a href="https://docs.python.org/3/library/datetime.html">datetime</a></code>: Библиотека Python для работы с датами и временим. </li> +</ul> + +<p>В отображении аргумент <code>pk</code> мы используем в функции<code>get_object_or_404()</code> для получения текущего объекта типа <code>BookInstance</code> (если его не существует, то функция, а следом и наше отображение прервут свое выполнение, а на странице пользователя отобразится сообщение об ошибке: "объект не найден"). Если запрос вызова отображения <em>не является</em> <code>POST</code>-запросом, то мы переходим к условному блоку <code>else</code>, в котором мы создаем форму по умолчанию и передаем ей начальное значения<code>initial</code> для поля <code>renewal_date</code> (выделено жирным ниже, - 3 недели, начиная с текущей даты). </p> + +<pre class="brush: python notranslate"> book_inst = get_object_or_404(BookInstance, pk=pk) + + # Если это GET (или другой метод), тогда создаем форму по умолчанию + <strong>else:</strong> + proposed_renewal_date = datetime.date.today() + datetime.timedelta(<strong>weeks=3</strong>) + <strong>form = RenewBookForm(initial={'</strong>renewal_date<strong>': </strong>proposed_renewal_date<strong>,})</strong> + + return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre> + +<p>После создания формы мы вызываем функцию <code>render()</code>, чтобы создать HTML страницу; передаем ей в качестве параметров шаблон и контекст, который содержит объект формы. Кроме того, контекст содержит объект типа <code>BookInstance</code>, который мы будем использовать в шаблоне, для получения информации об обновляемой книге.</p> + +<p>Если все таки у нас <code>POST</code>-запрос, тогда мы создаем объект с именем <code>form</code> и заполняем его данными, полученными из запроса. Данный процесс называется связыванием (или, биндингом, от англ. "binding") и позволяет нам провести валидацию данных. Далее осуществляется валидация формы, при этом проверяются все поля формы — для этого используются как код обобщенного класса, так и пользовательских функций, в частности нашей функции проверки введенных дат <code>clean_renewal_date()</code>. </p> + +<pre class="brush: python notranslate"> book_inst = get_object_or_404(BookInstance, pk=pk) + + # Если данный запрос типа POST, тогда + if request.method == 'POST': + + # Создаем экземпляр формы и заполняем данными из запроса (связывание, binding): +<strong> form = RenewBookForm(request.POST)</strong> + + # Проверка валидности формы: + if form.is_valid(): + # process the data in form.cleaned_data as required (here we just write it to the model due_back field) + book_inst.due_back = form.cleaned_data['renewal_date'] + book_inst.save() + + # redirect to a new URL: + return HttpResponseRedirect(reverse('all-borrowed') ) + + return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre> + +<p>Если формы не прошла валидацию, то мы снова вызываем функцию <code>render()</code>, но на этот раз форма будет содержать сообщения об ошибках. </p> + +<p>Если форма прошла валидацию, тогда мы можем начать использовать данные, получая их из атрибута формы <code>form.cleaned_data</code> (то есть, <code>data = form.cleaned_data['renewal_date']</code>). Здесь мы просто сохраняем данные в поле <code>due_back</code> , соответствующего объекта<code> BookInstance</code>.</p> + +<div class="warning"> +<p><strong>Важно</strong>: Хотя вы также можете получить доступ к данным формы непосредственно через запрос (например <code>request.POST['renewal_date'],</code> или <code>request.GET['renewal_date']</code> (в случае GET-запроса), это НЕ рекомендуется. Очищенные данные проверены на вредоносность и преобразованы в типы, совместимые с Python.</p> +</div> + +<p>Последним шагом в части обработки формы представления является перенаправление на другую страницу, обычно страницу «Успех». В нашем случае мы используем объект класса <code>HttpResponseRedirect</code> и функцию <code>reverse()</code> для перехода к отображению с именем <code>'all-borrowed'</code> (это было домашним заданием в <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Руководство часть 8: Аутентификация и разграничение доступа</a>). Если вы не создали данную страницу, то просто укажите переход на домашнюю страницу сайта по адресу '/').</p> + +<p>Все это необходимо для управления формой как таковой, но нам нужно как-то ограничить доступ к отображению (открыть доступ только библиотекарям). Мы могли бы создать новое разрешение (permission) в классе <code>BookInstance</code> ("<code>can_renew</code>"), но мы пойдем простым путем и воспользуемся функцией-декоратором <code>@permission_required</code> вместе с нашим существующим разрешением<code>can_mark_returned</code>.</p> + +<p>Окончательный вид отображения показан ниже. Пожалуйста, скопируйте данный текст в нижнюю часть файла <strong>locallibrary/catalog/views.py</strong>.</p> + +<pre class="notranslate"><strong>from django.contrib.auth.decorators import permission_required</strong> + +from django.shortcuts import get_object_or_404 +from django.http import HttpResponseRedirect +from django.urls import reverse +import datetime + +from .forms import RenewBookForm + +<strong>@permission_required('catalog.<code>can_mark_returned</code>')</strong> +def renew_book_librarian(request, pk): + """ + View function for renewing a specific BookInstance by librarian + """ + book_inst = get_object_or_404(BookInstance, pk=pk) + + # If this is a POST request then process the Form data + if request.method == 'POST': + + # Create a form instance and populate it with data from the request (binding): + form = RenewBookForm(request.POST) + + # Check if the form is valid: + if form.is_valid(): + # process the data in form.cleaned_data as required (here we just write it to the model due_back field) + book_inst.due_back = form.cleaned_data['renewal_date'] + book_inst.save() + + # redirect to a new URL: + return HttpResponseRedirect(reverse('all-borrowed') ) + + # If this is a GET (or any other method) create the default form. + else: + proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) + form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,}) + + return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst}) +</pre> + +<h3 id="Шаблон">Шаблон</h3> + +<p>Создайте шаблон, на который ссылается наше отображение (<strong>/catalog/templates/catalog/book_renew_librarian.html</strong>) и скопируйте в него код, указаный ниже:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} +{% block content %} + + <h1>Renew: \{{bookinst.book.title}}</h1> + <p>Borrower: \{{bookinst.borrower}}</p> + <p{% if bookinst.is_overdue %} class="text-danger"{% endif %}>Due date: \{{bookinst.due_back}}</p> + +<strong> <form action="" method="post"> + {% csrf_token %} + <table> + \{{ form }} + </table> + <input type="submit" value="Submit" /> + </form></strong> + +{% endblock %}</pre> + +<p>Большая его часть вам знакома из предыдущих частей руководства. Мы расширяем базовый шаблон, а затем замещаем блок содержимого <code>content</code>. У нас имеется возможность ссылаться на переменную <code>\{{bookinst}}</code> (и ее поля) поскольку мы передали ее в объект контекста при вызове функции <code>render()</code>. Здесь мы используем данный объект для вывода заголовка книги, дат ее получения и возврата.</p> + +<p>Код формы относительно прост. В первую очередь мы объявляем тэг<code>form</code>, затем определяем куда будут отправлены данные (<code>action</code>) и каким способом (<code>method</code>, в данном случае "HTTP POST") — если обратитесь к обзору раздела <a href="#HTML_forms">Формы HTML</a> в верхней части данной страницы, то найдете там замечение, что пустое значние атрибута <code>action</code>, означает, что данные из формы будут переданы обратно по текущему URL-адресу данной страницы (чего мы и хотим!). Внутри тэга формы мы объявляем кнопку <code>submit</code> при помощи которой мы можем отправить наши данные. Блок <code>{% csrf_token %}</code>, добавленный первой строкой внутри блока формы, является частью фреймворка Django и служит для борьбы с CSRF.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Добавляйте <code>{% csrf_token %}</code> в каждый шаблон Django, в котором вы создаете форму для отправки данных методом <code>POST</code>. Это поможет уменьшить вероятность взлома вашего сайта злоумышленниками.</p> +</div> + +<p>Все что осталось, это указать переменную <code>\{{form}}</code>, которую мы передали в шаблон в словаре контекста. Возможно это вас не удивит, но таким образом мы предоставим возможность форме отрендерить свои поля с их метками, виджетами и дополнительными текстами, и в результате мы получим следующее:</p> + +<pre class="brush: html notranslate"><tr> + <th><label for="id_renewal_date">Renewal date:</label></th> + <td> + <input id="id_renewal_date" name="renewal_date" type="text" value="2016-11-08" required /> + <br /> + <span class="helptext">Enter date between now and 4 weeks (default 3 weeks).</span> + </td> +</tr> +</pre> + +<div class="note"> +<p><strong>Примечание:</strong> Возможно это не очевидно, поскольку наша форма содержит только одно поле, но по умолчанию каждое поле формы помещается в ее собственную строку таблицы (поэтому переменная <code>\{{form}}</code> находится внутри тэга <code>table </code>. Тот же результат можно получить, если воспользоваться следующим вызовом <code>\{{ form.as_table }}</code>.</p> +</div> + +<p>Если вы ввели неправильную дату, то на странице вы должны получить список сообщений об ошибках (показано жирным ниже).</p> + +<pre class="brush: html notranslate"><tr> + <th><label for="id_renewal_date">Renewal date:</label></th> + <td> +<strong> <ul class="errorlist"> + <li>Invalid date - renewal in past</li> + </ul></strong> + <input id="id_renewal_date" name="renewal_date" type="text" value="2015-11-08" required /> + <br /> + <span class="helptext">Enter date between now and 4 weeks (default 3 weeks).</span> + </td> +</tr></pre> + +<h4 id="Другие_варианты_применения_переменной_шаблона_form">Другие варианты применения переменной шаблона form</h4> + +<p>В простом случае применения <code>\{{form}}</code> как показано выше, каждое поле рендерится в виде отдельной строки таблицы. Кроме того, вы можете отрендерить каждое поле как список элементов (<code>\{{form.as_ul}}</code> ), или как параграф (<code>\{{form.as_p}}</code>).</p> + +<p>Что еще больше вдохновляет, так это то, что вы можете полностью контролировать процесс рендеринга любой части формы, используя для этого дот-нотацию (точку). Например, мы можем получить доступ к следующим полям поля формы <code>renewal_date</code>:</p> + +<ul> + <li><code>\{{form.renewal_date}}:</code> само поле.</li> + <li><code>\{{form.renewal_date.errors}}</code>: Список ошибок.</li> + <li><code>\{{form.renewal_date.id_for_label}}</code>: Идентификатор текстовой метки.</li> + <li><code>\{{form.renewal_date.help_text}}</code>: Дополнительный текст.</li> + <li>и так далее!</li> +</ul> + +<p>Примеры того как вручную отрендерить формы в шаблонах, а также пробежать циклом по шаблонным полям, смотрите <a href="https://docs.djangoproject.com/en/1.10/topics/forms/#rendering-fields-manually">Работы с формами > Ручная работа с формами</a> (Django docs).</p> + +<h3 id="Тестирование_страницы">Тестирование страницы</h3> + +<p>Если вы выполнили задание в <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Django руководство часть 8: Аутентификация и разрешение доступа</a>, то у вас должна быть страница со списком всех книг в наличии библиотеки и данный список (страница) должен быть доступен только ее сотрудникам. На данной странице в каждом пункте (для каждой книги) мы можем добавить ссылку на нашу новую страницу обновления книги.</p> + +<pre class="brush: html notranslate">{% if perms.catalog.can_mark_returned %}- <a href="{% url 'renew-book-librarian' bookinst.id %}">Renew</a> {% endif %}</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Помните что, для того чтобы перейти на страницу обновления книги, ваш тестовый логин должен иметь разрешение доступа типа "<code>catalog.can_mark_returned</code>"(возможно надо воспользоваться вашим аккаунтом для суперпользователя).</p> +</div> + +<p>Вы можете попробовать вручную создать URL-адрес для тестирования, например — <a href="http://127.0.0.1:8000/catalog/book/<bookinstance id>/renew/">http://127.0.0.1:8000/catalog/book/<em><bookinstance_id></em>/renew/</a> (правильный идентификатор записи id для bookinstance можно получить, если перейти на страницу детальной информации книги и скопировать поле <code>id</code>).</p> + +<h3 id="Как_теперь_все_это_выглядит">Как теперь все это выглядит?</h3> + +<p>Если все получилось как надо, то форма по умолчанию должна выглядеть следующим образом:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14209/forms_example_renew_default.png" style="border-style: solid; border-width: 1px; display: block; height: 292px; margin: 0px auto; width: 680px;"></p> + +<p>А такой наша форма будет в случае ввода неправильной даты:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14211/forms_example_renew_invalid.png" style="border-style: solid; border-width: 1px; display: block; height: 290px; margin: 0px auto; width: 658px;"></p> + +<p>Список всех книг с ссылками на странцу обновления данных:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14207/forms_example_renew_allbooks.png" style="border-style: solid; border-width: 1px; display: block; height: 256px; margin: 0px auto; width: 613px;"></p> + +<h2 id="Класс_ModelForm">Класс ModelForm</h2> + +<p>Создание класса формы <code>Form</code> при помощи примера, описанного выше, является довольно гибким способом, позволяющим вам создавать формы любой структуры которую вы пожелаете, в связке с любой моделью, или моделями.</p> + +<p>Тем не менее, если вам просто нужна форма для отображения полей одиночной модели, тогда эта самая модель уже содержит большую часть информации, которая вам нужна для построения формы: сами поля, текстовые метки, дополнительный текст и так далее. И чтобы не воспроизводить информацию из модели для вашей формы, проще воспользоваться классом <a href="https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/">ModelForm</a>, который помогает созадавать формы непосредственно из модели. Класс <code>ModelForm</code> может применяться в ваших отображениях точно таким же образом как и "классический" класс формы <code>Form</code>.</p> + +<p>Базовая реализация <code>ModelForm</code> содержит тоже поле как и ваш предыдущий класс формы <code>RenewBookForm</code>, что и показано ниже. Все что вам необходимо сделать, - внутри вашего нового класса добавить класс <code>Meta</code> и связать его с моделью <code>model</code> (<code>BookInstance</code>), а затем перечислить поля модели в поле <code>fields</code> которые должны быть включены в форму (вы можете включить все поля при помощи <code>fields = '__all__'</code>, или можно вопользоваться полем <code>exclude</code> (вместо <code>fields</code>), чтобы определить поля модели, которые <em>не</em> нужно включать).</p> + +<pre class="brush: python notranslate">from django.forms import ModelForm +from .models import BookInstance + +class RenewBookModelForm(ModelForm): +<strong> class Meta: + model = BookInstance + fields = ['due_back',]</strong> +</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Это не выглядит сильно проще, чем просто использовать класс <code>Form</code> (и это действительно так, поскольку мы используем только одно поле). Тем не менее, если вы хотите иметь много полей, то такой способ построения формы может значительно уменьшить количество кода и ускорить разработку!</p> +</div> + +<p>Оставшаяся часть информации касается объявления полей модели (то есть, текстовых меток, виджетов, текстов, сообщений об ошибках). Если они недостаточно "правильные", то тогда мы можем переопределить их в нашем классе <code>Meta</code> при помощи словаря, содержащего поле, которое надо изменить и его новое значение. Например, в нашей форме мы могли бы поменять текст метки для поля "<em>Renewal date</em>" (вместо того, чтобы оставить текст по умолчанию: <em>Due date</em>), а кроме того мы хотим написать другой вспомогательный текст. Класс <code>Meta</code>, представленный ниже, показывает вам, как переопределить данные поля. Кроме того, при необходимости, вы можете установить значения для виджетов <code>widgets</code> и сообщений об ошибках <code>error_messages</code>.</p> + +<pre class="brush: python notranslate">class Meta: + model = BookInstance + fields = ['due_back',] +<strong> labels = { 'due_back': _('Renewal date'), } + help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), } </strong> +</pre> + +<p>Чтобы добавить валидацию, вы можете использовать тот же способ как и для класса <code>Form</code> — вы определяете функцию с именем <code>clean_<em>field_name</em>()</code> из которой выбрасываете исключение <code>ValidationError</code>, если это необходимо. Единственным отличием от нашей оригинальной формы будет являться то, что поле модели имеет имя <code>due_back</code>, а не "<code>renewal_date</code>".</p> + +<pre class="brush: python notranslate">from django.forms import ModelForm +from .models import BookInstance + +class RenewBookModelForm(ModelForm): +<strong> def clean_due_back(self): + data = self.cleaned_data['due_back'] + + #Проверка того, что дата не в прошлом + if data < datetime.date.today(): + raise ValidationError(_('Invalid date - renewal in past')) + + #Check date is in range librarian allowed to change (+4 weeks) + if data > datetime.date.today() + datetime.timedelta(weeks=4): + raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) + + # Не забывайте всегда возвращать очищенные данные + return data +</strong> + class Meta: + model = BookInstance + fields = ['due_back',] + labels = { 'due_back': _('Renewal date'), } + help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), } +</pre> + +<p>Теперь класс <code>RenewBookModelForm</code> является функциональным эквивалентом нашему предыдущему классу <code>RenewBookForm</code>. Вы можете импортировать и использовать его в тех же местах, где и <code>RenewBookForm</code>.</p> + +<h2 id="Обобщенные_классы_отображения_для_редактирования">Обобщенные классы отображения для редактирования</h2> + +<p>Алгоритм управления формой, который мы использовали в нашей функции отображения, является примером достаточно общего подхода к работе с формой. Django старается абстрагировать и упростить бульшую часть данной работы, путем широкого применения <a href="https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-editing/">обобщенных классов отображений</a>, которые служат для создания, редактирования и удаления отображений на основе моделей. Они не только управляют поведением отображения, но, кроме того, они из вашей модели автоматически создают класс формы (<code>ModelForm</code>).</p> + +<div class="note"> +<p><strong>Примечание: </strong>В дополнение к отображениям для реактирования, описываемых здесь, существует также класс <a href="https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-editing/#formview">FormView</a>, который по своему предназначению находится где-то между "простой" функцией отображения и другими обобщенными отображенями, то есть в каком-то смысле, в диапазоне: "гибкость" против "усилия при программировании". Применяя <code>FormView,</code> вы все еще нуждаетесь в создании класса <code>Form</code>, но вам не нужно реализовавыть весь "стандартный" функционал работы с формой. Вместо этого, вы должны просто реализовать функцию, которая будет вызвана в тот момент, когда станет понятно, что получаемые из формы данные, "правильные" (валидны).</p> +</div> + +<p>В данном разделе мы собираемся использовать обобщенные классы для редактирования, для того, чтобы создать страницы, который добавляют функционал создания, редактирования и удаления записей типа <code>Author</code> из нашей библиотеки — предоставляя базовый функционал некоторых частей административной части сайта (это может быть полезно для случаев, когда вам нужно создать административную часть сайта, которая, в отличие от стандартной, была бы более гибкой).</p> + +<h3 id="Отображения">Отображения</h3> + +<p>Откройте файл отображений (<strong>locallibrary/catalog/views.py</strong>) и добавьте следующий код в его нижнюю часть:</p> + +<pre class="brush: python notranslate">from django.views.generic.edit import CreateView, UpdateView, DeleteView +from django.urls import reverse_lazy +from .models import Author + +class AuthorCreate(CreateView): + model = Author + fields = '__all__' + initial={'date_of_death':'12/10/2016',} + +class AuthorUpdate(UpdateView): + model = Author + fields = ['first_name','last_name','date_of_birth','date_of_death'] + +class AuthorDelete(DeleteView): + model = Author + success_url = reverse_lazy('authors')</pre> + +<p>Как вы видите, для создания отображений вам надо наследоваться от следующих классов<code>CreateView</code>, <code>UpdateView</code> и <code>DeleteView</code> (соответственно), а затем связать их с соответствующей моделью.</p> + +<p>Для случаев "создать" и "обновить" вам также понадобится определить поля для показа на форме (применяя тот же синтаксис, что и для <code>ModelForm</code>). В этом случае мы демонстриурем синтаксис и для показаза "всех" полей, и перечисление их по отдельности. Также вы можете указать начальные значения для каждого поля, применяя словарь пар <em>имя_поля</em>/<em>значение</em> (в целях демонстрации, в нашем примере мы явно указываем дату смерти — если хотите, то вы можете удалить это поле). По умолчанию отображения перенаправляют пользователя на страницу "успеха", показывая только что созданные/отредатированные данные (записи в модели). В нашем случае это, созданная в предыдущей части руководства, подробная информация об авторе. Вы можете указать альтернативное перенаправление при помощи параметра <code>success_url</code> (как в примере с классом <code>AuthorDelete</code>).</p> + +<p>Классу <code>AuthorDelete</code> не нужно показывать каких либо полей, таким образом их не нужно и декларировать. Тем не менее, вам нужно указать <code>success_url</code>, потому что, в данном случае, для Django не очевидно что делать после успешного выполнения операции удаления записи. Мы используем функцию <code><a href="https://docs.djangoproject.com/en/1.10/ref/urlresolvers/#reverse-lazy">reverse_lazy()</a></code> для перехода на страницу списка авторов после удаления одного из них — <code>reverse_lazy()</code> это более "ленивая" версия <code>reverse().</code></p> + +<h3 id="Шаблоны">Шаблоны</h3> + +<p>Отображения "создать" и "обновить" используют шаблоны с именем <em>model_name</em><strong>_form.html,</strong> по умолчанию: (вы можете поменять суффикс на что-нибудь другое, при помощи поля <code>template_name_suffix</code> в вашем отображении, например, <code>template_name_suffix = '_other_suffix'</code>)</p> + +<p>Создайте файл шаблона <strong>locallibrary/catalog/templates/catalog/author_form.html</strong> и скопируйте в него следующий текст.</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + +<form action="" method="post"> + {% csrf_token %} + <table> + \{{ form.as_table }} + </table> + <input type="submit" value="Submit" /> + +</form> +{% endblock %}</pre> + +<p>Это напоминает наши предыдущие формы и рендер полей при помощи таблицы. Заметьте, что мы снова используем<code>{% csrf_token %}</code>.</p> + +<p>Отображения "удалить" ожидает "найти" шаблон с именем формата <em>model_name</em><strong>_confirm_delete.html</strong> (и снова, вы можете изменить суффикс при помощи поля отображения<code>template_name_suffix</code>). Создайте файл шаблона <strong>locallibrary/catalog/templates/catalog/author_confirm_delete</strong><strong>.html</strong> и скопируйте в него текст, указанный ниже.</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + +<h1>Delete Author</h1> + +<p>Are you sure you want to delete the author: \{{ author }}?</p> + +<form action="" method="POST"> + {% csrf_token %} + <input type="submit" value="Yes, delete." /> +</form> + +{% endblock %} +</pre> + +<h3 id="Настройки_URL-адресов">Настройки URL-адресов</h3> + +<p>Откройте файл конфигураций URL-адресов (<strong>locallibrary/catalog/urls.py</strong>) и добавьте в его нижнюю часть следующие настройки:</p> + +<pre class="brush: python notranslate">urlpatterns += [ + url(r'^author/create/$', views.AuthorCreate.as_view(), name='author_create'), + url(r'^author/(?P<pk>\d+)/update/$', views.AuthorUpdate.as_view(), name='author_update'), + url(r'^author/(?P<pk>\d+)/delete/$', views.AuthorDelete.as_view(), name='author_delete'), +]</pre> + +<p>Здесь нет ничего нового! Как вы видите отображения являются классами и следовательно должны вызываться через метод <code>.as_view()</code>. Паттерны URL-адресов для каждого случая должны быть вам понятны. Мы обязаны использовать <code>pk</code> как имя для "захваченного" значения первичного ключа, так как параметр именно с таким именем ожидается классами отображения.</p> + +<p>Страницы создания, обновления и удаления автора теперь готовы к тестированию (мы не будем создавать на них ссылки в отдельном меню, но вы, если хотите, можете их сделать).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Наблюдательные пользователи могли заметить, что мы ничего не делаем, чтобы предотвратить несанкционированный доступ к страницам! Мы оставили это в качестве упражнения для вас (подсказка: вы можете использовать <code>PermissionRequiredMixin</code> и, либо создать новое разрешение, или воспользоваться нашим прежним <code>can_mark_returned</code>).</p> +</div> + +<h3 id="Тестирование_страницы_2">Тестирование страницы</h3> + +<p>Залогиньтесь на сайте с аккаунтом, который позволит вам получить доступ к страницам редактирования данных (и записей) автора.</p> + +<p>Затем перейдите на страницу создания новой записи автора: <a href="http://127.0.0.1:8000/catalog/author/create/">http://127.0.0.1:8000/catalog/author/create/</a>, которая должна быть похожей на следующий скриншот.</p> + +<p><img alt="Form Example: Create Author" src="https://mdn.mozillademos.org/files/14223/forms_example_create_author.png" style="border-style: solid; border-width: 1px; display: block; height: 184px; margin: 0px auto; width: 645px;"></p> + +<p>Введите в поля значения и нажмите на кнопку <strong>Submit</strong>, чтобы сохранить новую запись об авторе. После этого, вы должны были перейти на страницу редактирования только что созданного автора, имеющий адрес, похожий на следующий <em>http://127.0.0.1:8000/catalog/author/10</em>.</p> + +<p>У вас есть возможность редактирования записей при помощи добавления<em> /update/</em> в конец адреса подробной информации (то есть, <em>http://127.0.0.1:8000/catalog/author/10/update/</em>) — мы не показываем скриншот, потому что он выглядит в точности также как страница "создать"!</p> + +<p>И последнее, мы можем удалить страницу, добавляя строку <em>/delete/</em> в конец адреса подробной информации автора (то есть, <em>http://127.0.0.1:8000/catalog/author/10/delete/</em>). Django должен показать страницу, которая похожа на представленную ниже. Нажмите <strong>Yes, delete.</strong>, чтобы удалить запись и перейти на страницу со списком авторов.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14221/forms_example_delete_author.png" style="border-style: solid; border-width: 1px; display: block; height: 194px; margin: 0px auto; width: 561px;"></p> + +<h2 id="Проверьте_себя">Проверьте себя</h2> + +<p>Создайте несколько форм создания, редактирования и удаления записей в модели <code>Book</code>. При желании, вы можете использовать теже структуры как и в случае с моделью <code>Authors</code>. Если ваш шаблон <strong>book_form.html</strong> является просто копией шаблона <strong>author_form.html</strong>, тогда новая страница "create book" будет выглядеть как на следующем скриншоте:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14225/forms_example_create_book.png" style="border-style: solid; border-width: 1px; display: block; height: 521px; margin: 0px auto; width: 595px;"></p> + +<ul> +</ul> + +<h2 id="Итоги">Итоги</h2> + +<p>Создание и управление формами может быть достаточно сложным! Django делает этот процесс намного проще, предоставляя прикладные механизмы объявления, рендеринга и проверки форм. Более того, Django предоставляет обобщенные классы редактирования форм, которые могут выполнять <em>практически любую</em> работу по созданию, редактированию и удалению записей, связанных с одиночной моделью.</p> + +<p>Существует много чего еще, что можно делать с формами (ознакомьтесь со списком ниже), но теперь вы должны понимать как добавлять базовые формы и создавать код управления формой на вашем сайте. </p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/forms/">Работа с формами</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/intro/tutorial04/#write-a-simple-form">Создание вашего первого приложения, часть 4 > Создание простой формы </a>(Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/api/">Forms API</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/">Поля класса Form</a> (Django docs) </li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/validation/">Класс Form и валидация поля</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-editing/">Управление классом Form из классов отображений</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/">Создание форм из моделей</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-editing/">Обобщенные отображения для редактирования</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/django/generic_views/index.html b/files/ru/learn/server-side/django/generic_views/index.html new file mode 100644 index 0000000000..7b1bf6f08c --- /dev/null +++ b/files/ru/learn/server-side/django/generic_views/index.html @@ -0,0 +1,605 @@ +--- +title: 'Руководство часть 6: Отображение списков и детальной информации' +slug: Learn/Server-side/Django/Generic_views +tags: + - django + - Для начинающих + - Отображения django + - Руководство + - Шаблоны django +translation_of: Learn/Server-side/Django/Generic_views +--- +<div>{{LearnSidebar}}<br> +{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</div> + +<p class="summary">Данная часть расширяет наш сайт <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, добавляя в него списки и страницы, путем предоставления подробной информации о книгах и авторах. В текущей части мы подробно изучим обобщенные базовые классы отображения и покажем как они могут существенно сократить количество кода, который вы должны были бы написать в обычной ситуации. Кроме того, мы более подробно рассмотрим управление и настройки URL-адресов, показывая как выполнить простое сопоставление какой-либо строки паттерну регулярного выражения.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Завершить все предыдущие части руководства, включая <a href="/en-US/docs/Learn/Server-side/Django/Home_page">Руководство Django Часть 5: Создание домашней страницы</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понимать где и как применять обобщенные базовые классы отображения, и как применять паттерны URL-адресов для передачи информации в отображения.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>В данном руководстве мы завершим первую версию сайта <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, с помощью добавления страницы перечисления и подробной информации о книгах и авторах (или, если быть более точными, мы покажем как вам реализовать соответствующие страницы для книг, а для авторов вы сможете сделать их самостоятельно!)</p> + +<p>Данный процесс похож на создание главной страницы сайта, который мы показывали в предыдущей части руководства. Нам все также надо создать URL-преобразования, отображения и шаблоны страниц. Основным отличием будет то, что для страниц подробной информации перед нами встанет дополнительная задача получения информации из паттерна URL-адреса и передачи ее отображению. Для этих страниц мы собираемся продемонстрировать совершенно другой тип отображения, основанный на применении обобщеных классов отображения списка и детальной информации о записи. Это может существенно сократить количество кода, необходимого для отображения и сделает его (код) более простым для написания и поддержки.</p> + +<p>Завершающая часть данного руководства будет посвещена демонстрации постраничного показа ваших данных (pagination) при применении обобщенного класса отображения списка.</p> + +<h2 id="Страница_со_списком_книг">Страница со списком книг</h2> + +<p>Страница со списком книг показывает все книги в наличии и будет доступна по адресу: <code>catalog/books/</code>. Эта страница для каждой записи выводит заголовок и автора, при этом каждый заголовок является гиперссылкой на соответствующую страницу подробной информации о книге. Данная страница будет иметь ту же структуру и навигацию как и все остальные страницы сайта, таким образом мы сможем расширить базовый шаблон сайта (<strong>base_generic.html</strong>), который мы создали в предыдущей части руководства.</p> + +<h3 id="Преобразования_URL-адресов">Преобразования URL-адресов</h3> + +<p>Откройте файл <strong>/catalog/urls.py</strong> и скопируйте в него строки, выделенные жирным внизу. Практически также как и для главной страницы сайта, данная функция <code>url()</code> определяет регулярное выражение (<strong>r'^books/$'</strong>), связывающее URL-адрес с функцией отображения (<code>views.BookListView.as_view()</code> ), которая будет вызвана, если URL-адрес будет соответствовать паттерну РВ. Кроме того, определяется имя для данного сопоставления.</p> + +<pre class="brush: python">from django.urls import path +from . import views +<strong>from django.conf.urls import url</strong> + +urlpatterns = [ + url(r'^$', views.index, name='index'), +<strong> url(r'^books/$', views.BookListView.as_view(), name='books'), +</strong>]</pre> + +<p>Данный паттерн РВ сопоставления URL-адреса полностью соответствует строке <code>books/</code> (<code>^</code> является маркером начала строки, а <code>$</code> - маркер конца строки). Как было отмечено в предыдущей части руководства, URL-адрес уже должен содержать <code>/catalog</code>, таким образом полный адрес, на самом деле, имеет вид : <code>/catalog/books/</code>.</p> + +<p>Функция отображения имеет другой формат, чем ранее — это связано с тем, что данное отображение реализуется через класс. Мы будем наследоваться от существующей общей функции из <strong>view</strong>, которая уже делает большую часть того, что мы хотим, что нам и нужно, вместо того, чтобы писать свою собственную функцию во <strong>view</strong> с нуля.</p> + +<p>При использовании обобщенных классов отображения в Django мы получаем доступ к соответствующей функции отображения при помощи вызова метода <code>as_view()</code>. Таким образом выполняется вся работа по созданию экземпляра класса и гарантируется вызов правильных методов для входящих HTTP-запросов.</p> + +<h3 id="Отображение_(на_основе_базового_класса)">Отображение (на основе базового класса)</h3> + +<p>Мы могли бы достаточно просто реализовать отображение списка книг при помощи обычной функции (также, как мы сделали это для главной страницы сайта), которая должны была бы выполнить запрос получения всех книг из базы данных, затем вызвать функцию <code>render()</code>, в которую передать данный список, в соответствующий шаблон страницы. Тем не менее, вместо это мы будем использовать обобщенный класс отображения списка — класс, который наследуется от существующего отображения (ListView). Поскольку обобщенный класс уже реализует большую часть того, что нам нужно, и следуя лучшим практикам Django, мы сможем создать более эффективный список при помощи меньшего количества кода, меньшего количества повторений и гораздо лучшей поддержкой.</p> + +<p>Откройте <strong>catalog/views.py</strong> и скопируйте следующий код, в нижнюю часть данного файла:</p> + +<pre class="brush: python">from django.views import generic + +class BookListView(generic.ListView): + model = Book</pre> + +<p>Это всё! Обобщенное отображение выполнит запрос к базе данных, получит все записи заданной модели (<code>Book</code>), затем отрендерит (отрисует) соответствующий шаблон, расположенный в <strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> (который мы создадим позже). Внутри данного шаблона вы можете получить доступ к списку книг при помощи переменной шаблона <code>object_list</code> ИЛИ <code>book_list</code> (если обобщить, то "<code><em>the_model_name</em>_list</code>").</p> + +<div class="note"> +<p><strong>Примечание</strong>: Этот, выглядящий странно, путь к файлу шаблона не является опечаткой — обобщенное отображение ищет файл шаблона <code>/<em>application_name</em>/<em>the_model_name</em>_list.html</code> (<code>catalog/book_list.html</code>, в данном случае) внутри директории приложения <code>/<em>application_name</em>/templates/</code> (у нас - <code>/catalog/templates/)</code>.</p> +</div> + +<p>Вы можете использовать атрибуты для того, чтобы изменить поведение по умолчанию. Например, вы могли бы указать другой файл шаблона, например, если в вашем распоряжении имеется несколько отображений, которые используют одну и ту же модель, или вам позарез захотелось бы использовать другое имя переменной шаблона, если <code>book_list</code> не является интуитивно понятным. Возможно, наиболее полезным вариантом является изменение/отфильтрование результата запроса к базе данных — таким образом, вместо перечисления всех книг вы могли бы показывать 5 наиболее популярных.</p> + +<pre class="brush: python">class BookListView(generic.ListView): + model = Book + context_object_name = 'my_book_list' # ваше собственное имя переменной контекста в шаблоне + queryset = Book.objects.filter(title__icontains='war')[:5] # Получение 5 книг, содержащих слово 'war' в заголовке + template_name = 'books/my_arbitrary_template_name_list.html' # Определение имени вашего шаблона и его расположения</pre> + +<h4 id="Переопределение_методов_в_классах_отображения">Переопределение методов в классах отображения</h4> + +<p>Пока что вам не приходилось этого делать, но у вас имеется возможность переопределять некоторые методы класса отображения.</p> + +<p>Например, мы можем переопределить метод получения списка всех записей <code>get_queryset()</code>. Данный подход является более гибким, чем использование атрибута <code>queryset</code>, как мы сделали в предыдущем фрагменте кода (хотя, в данном случае и нет никакой разницы):</p> + +<pre class="brush: python">class BookListView(generic.ListView): + model = Book + + def get_queryset(self): + return Book.objects.filter(title__icontains='war')[:5] # Получить 5 книг, содержащих 'war' в заголовке +</pre> + +<p>Мы также могли бы переопределить метод <code>get_context_data()</code> для того, чтобы в контексте (в переменной контекста) передавать шаблону дополнительные переменные (например, список книг передается по умолчанию). Фрагмент, представленный ниже, показывает как добавить переменную с именем "some_data" в контекст (затем она будет доступна как переменная шаблона).</p> + +<pre class="brush: python">class BookListView(generic.ListView): + model = Book + + def get_context_data(self, **kwargs): + # В первую очередь получаем базовую реализацию контекста + context = super(BookListView, self).get_context_data(**kwargs) + # Добавляем новую переменную к контексту и иниуиализируем ее некоторым значением + context['some_data'] = 'This is just some data' + return context</pre> + +<p>В процессе выполнения всего этого важно придерживаться определенной последовательности действий:</p> + +<ul> + <li>В первую очередь - получить существующий контекст из нашего суперкласса.</li> + <li>Затем добавить в контекст новую информацию.</li> + <li>Затем вернуть новый (обновленный) контекст.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Посмотрите <a href="https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-display/">Встроенные обобщенные классы отображения</a> (Django docs) для ознакомления с большим количеством примеров того, что вы могли бы сделать.</p> +</div> + +<h3 id="Создание_шаблона_Отображения_Списка">Создание шаблона Отображения Списка</h3> + +<p>Создайте HTML-файл <strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> и скопируйте в него текст, указанный ниже. Как было отмечено ранее, это файл шаблона по умолчанию, который будет "искать" обобщенный класс отображения списка (для модели с именем <code>Book</code> в приложении с именем <code>catalog</code>).</p> + +<p>Шаблоны для обобщенных отображений такие же как все остальные шаблоны (хотя, естественно, передаваемые в них контекст, или информация могут отличаться). Так же как и с нашим шаблоном для главной страницы, в первой строке мы расширяем наш базовый шаблон, а затем определяем и замещаем блок с именем <code>content</code>.</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + <h1>Book List</h1> + + <strong>{% if book_list %}</strong> + <ul> + + {% for book in book_list %} + <li> + <a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}}) + </li> + {% endfor %} + + </ul> + <strong>{% else %}</strong> + <p>There are no books in the library.</p> + <strong>{% endif %} </strong> +{% endblock %}</pre> + +<p>По умолчанию отображение передает контекст (список книг) как <code>object_list</code> и <code>book_list</code> (синонимы; оба варианта будут работать).</p> + +<h4 id="Условные_ветвления">Условные ветвления</h4> + +<p>Мы применяем теги шаблона <code><a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#if">if</a></code>, <code>else</code> и <code>endif</code> для того, чтобы проверить определена ли переменная <code>book_list</code> и содержит ли она данные. Если список НЕ пуст, тогда мы выполняем итерации по списку книг. Если список пуст (<code>else</code>-случай) тогда мы показываем текст, поясняющий, что в наличии нет книг.</p> + +<pre class="brush: html"><strong>{% if book_list %}</strong> + <!-- здесь наш код "бежит" по списку книг --> +<strong>{% else %}</strong> + <p>В библиотеке книг нет.</p> +<strong>{% endif %}</strong> +</pre> + +<p>В данном фрагменте проверяется только одно условие, но вы можете протестировать другие варианты при помощи тэга шаблона <code>elif</code> (например, <code>{% elif var2 %}</code> ). Для дополнительной информации по данной теме смотрите: <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#if">if</a>, <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#ifequal-and-ifnotequal">ifequal/ifnotequal</a> и <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#ifchanged">ifchanged</a> в главе <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins">Встроенные тэги и фильтры шаблона</a> (Django Docs).</p> + +<h4 id="Цикл_For">Цикл For</h4> + +<p>Шаблон использует тэги <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#for">for</a> и <code>endfor</code> для того, чтобы "пробежаться" по списку книг, как показано ниже. На каждой итерации (каждом цикле) в переменную шаблона <code>book</code> передается информация текущего эелемента списка.</p> + +<pre class="brush: html">{% for <strong>book</strong> in book_list %} + <li> <!-- здесь код, который использует информацию из каждого элемента <strong>book </strong>списка--> </li> +{% endfor %} +</pre> + +<p>Мы не применяем здесь, но внутри каждого цикла Django создает переменные, которые вы можете использовать при итерации. Например, вы можете проверять переменную <code>forloop.last</code> (указывает на последнюю итерацию в цикле) для выполнения каких-либо завершающих действий для данного цикла.</p> + +<h4 id="Доступ_к_переменным">Доступ к переменным</h4> + +<p>Код внутри цикла создает экземпляр для каждой книги из списка, при помощи которой показывается заголовок (как ссылка на "скоро-будет-сделано" подробное отображение) и автора книги.</p> + +<pre class="brush: html"><a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}}) +</pre> + +<p>Мы получаем доступ к <em>полям</em> соответствующей записи о книге при помощи "дот-нотации", то есть через точку (например, <code>book.title</code> и <code>book.author</code>), где текст, который идет после <code>book</code>, является именем поля (так, как определено в модели).</p> + +<p>Кроме того, внутри нашего шаблона, мы можем вызывать <em>функции</em> модели — в данном случае, мы вызываем <code>Book.get_absolute_url()</code> для получения URL-адреса, который мы используем для показа детальной информации о книге. Данный вызов работает только для функции у которой нет аргументов (в шаблоне не существует возможности передать аргументы в функцию!)</p> + +<div class="note"> +<p><strong>Примечание</strong>: Мы должны быть достаточно осмотрительными для того, чтобы избегать "сторонних эффектов" когда мы вызываем функции из шаблона. В данном случае мы просто получаем URL-адрес, но функции могут делать все что угодно — мы не хотели бы "убить" наша базу данных (например) просто отрендеривая наш шаблон!</p> +</div> + +<h4 id="Обновление_базового_шаблона">Обновление базового шаблона</h4> + +<p>Откройте файл базового шаблона (<strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong>) и вставьте <strong>{% url 'books' %} </strong> в URL-ссылку для пункта <strong>All books</strong>, как показано ниже. Тем самым, мы создали "переход" на страницу с книгами (теперь мы можем смело это сделать, поскольку у нас имеется соответствующее "книжное" url-преобразование).</p> + +<pre class="brush: python"><li><a href="{% url 'index' %}">Home</a></li> +<strong><li><a href="{% url 'books' %}">All books</a></li></strong> +<li><a href="">All authors</a></li></pre> + +<h3 id="Как_же_теперь_все_это_выглядит">Как же теперь все это выглядит?</h3> + +<p>Пока что у вас нет возможности создать список книг, потому что мы не учли еще необходимые зависимости — преобразование URL-адреса для страниц с подробной информации о книге, которое необходимо для ссылок на отдельные книги. Мы покажем страницы со списком и подробной информацией о книге после следующего раздела.</p> + +<h2 id="Страница_с_подробной_информацией_о_книге">Страница с подробной информацией о книге</h2> + +<p>Доступ к странице с подробной информацией о книге осуществляется при помощи URL-адреса <code>catalog/book/<em><id></em></code> (где <code><em><id></em></code> является первичным ключом для данной книги). В дополнение к полям модели <code>Book</code> (автор, краткое содержание, ISBN, язык и жанр), также мы перечислим детали доступных экземпляров книги (<code>BookInstances</code>) включая их статус, ожидаемую дату возврата, штамп (imprint) и id. Это должно позволить нашим читателям не просто узнать о книге, но также убедиться, имеется ли она в наличии и/или когда будет доступна.</p> + +<h3 id="URL-преобразования">URL-преобразования</h3> + +<p>Откройте <strong>/catalog/urls.py</strong> и добавьте '<strong>book-detail</strong>' URL-преобразование, отмеченное жирным в следующем фрагменте. Эта функция <code>url()</code> определяет паттерн, связанный с обобщенным классом отображения детальной информации, а также имя для данной связи.</p> + +<pre class="brush: python">from django.urls import path +from . import views +<strong>from django.conf.urls import url</strong> + +urlpatterns = [ + url(r'^$', views.index, name='index'), + url(r'^books/$', views.BookListView.as_view(), name='books'), + <strong>url(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'),</strong> +]</pre> + +<p>В отличие от предыдущих преобразований, в данном случае мы применяем наше регулярное выражение (РВ) для сопоставления "настоящего паттерна", а не просто строки. Данное РВ сопоставляет любой URL-адрес, который начинается с <code>book/</code>, за которым до конца строки (до маркера конца строки - $) следуют одна, или более <em>цифр</em>. В процессе выполнения данного преобразования, оно "захватывает" цифры и передает их в функцию отображения как параметр с именем <code>pk</code>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: как было отмечено ранее, наш преоразуемый URL-адрес в реальности выглядит вот так <code>catalog/book/<digits></code> (потому что мы находимся в приложении <strong>catalog</strong>, то подразумевается каталог <code>/catalog/</code>).</p> +</div> + +<div class="warning"> +<p><strong>Важно</strong>: Обобщенный класс отображения подробной информации ожидает получить параметр с именем pk. Если вы пишете свою собственную функцию отображения, то тогда вы можете использовать параметр с любым именем, который пожелаете, или вообще передавать информацию в безымянном аргументе.</p> +</div> + +<h4 id="Отдельный_пример_с_регулярными_выражениями">Отдельный пример с регулярными выражениями</h4> + +<p>Паттерны <a href="https://docs.python.org/3/library/re.html">регулярного выражения</a> является невероятно мощным инструментом преобразования. Пока что, мы не очень много говорили о них, поскольку мы сопоставляли URL-адреса с простыми строками (а не паттернами), и потому что они не интуитивны и пугающи для начинающих.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Без паники! Мы будем рассматривать и использовать достаточно простые паттерны и при этом хорошо задокументированные!</p> +</div> + +<p>В первую очередь вы должны знать что обычно регулярные выражения объявляются при помощи строкового литерала (то есть, они заключены в кавычки: <strong>r'<ваше регулярное выражение>'</strong>).</p> + +<p>Главными элементами синтаксиса объявления паттерна, который вы должны знать, являются:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Символ</th> + <th scope="col">Значение</th> + </tr> + </thead> + <tbody> + <tr> + <td>^</td> + <td>Соответствует началу строки</td> + </tr> + <tr> + <td>$</td> + <td>Соответствует концу строки</td> + </tr> + <tr> + <td>\d</td> + <td>Соответствует цифре (0, 1, 2, ... 9)</td> + </tr> + <tr> + <td>\w</td> + <td>Соответствует любому символу из алфавита в верхнем- или нижнем- регистре, цифре, или символу подчеркивания (_)</td> + </tr> + <tr> + <td>+</td> + <td>Соответствует <strong>одному, или более</strong> предыдущему символу. Например, для соответствия <strong>одной, или более</strong> цифре вы должны использовать <code>\d+</code>. Для <strong>одного и более</strong> символа "a", вы можете использовать <code>a+</code></td> + </tr> + <tr> + <td>*</td> + <td>Соответствует отсутствию вообще, или присутствию <strong>одного, или более</strong> предыдущему символу. Например, для соответствия "ничему", или слову (то есть, любому символу) вы можете использовать <code>\w*</code></td> + </tr> + <tr> + <td>( )</td> + <td>Захват части паттерна внутри скобок. Любое захваченное значение будет передано отображению как безымянный параметр (если захватывается множество паттернов, то соответствующие параметры будут поставляться в порядке их объявления).</td> + </tr> + <tr> + <td>(?P<name>...)</td> + <td>Захват части паттерна (обозначеного через ...) как именованной переменной (в данном случае <name>). Захваченные значения передаются в отображение с определенным именем. Таким образом, ваше отображение должно объявить аргумент с тем же самым именем!</td> + </tr> + <tr> + <td>[ ]</td> + <td>Соответствует одному символу из множества. Например, [abc] будет соответствовать либо 'a', или 'b', или 'c'. [-\w] будет соответствовать либо символу '-' , или любому другому словарному символу.</td> + </tr> + </tbody> +</table> + +<p>Большинство других символов могут быть заданы буквально!</p> + +<p>Давайте рассмотрим несколько реальных примеров паттернов:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Паттерн</th> + <th scope="col">Описание</th> + </tr> + </thead> + <tbody> + <tr> + <td><strong>r'^book/(?P<pk>\d+)$'</strong></td> + <td> + <p>Это РВ применяется в нашем url-преобразовании. Оно соответствует строке, которая начинается с <code>book/</code> (<strong>^book/</strong>), затем имеет одну, или более цифр (<code>\d+</code>), а затем завершается (цифрой и только цифрой).</p> + + <p>Оно также захватывает все цифры <strong>(?P<pk>\d+)</strong> и передает их в отображение, в параметре с именем 'pk'. <strong>Захваченные значения всегда передаются как строка!</strong></p> + + <p>Например, данному паттерну должна соответствовать следующая строка <code>book/1234</code> , которая отправляет переменную <code>pk='1234'</code> в отображение.</p> + </td> + </tr> + <tr> + <td><strong>r'^book/(\d+)$'</strong></td> + <td>Этот паттерн соответствует тем же самым URL-адресам как и в предыдущем случае. Захваченная информация будет отправлена в отображение как безымянный параметр.</td> + </tr> + <tr> + <td><strong>r'^book/(?P<stub>[-\w]+)$'</strong></td> + <td> + <p>Данный паттерн соответствует строке, которая начинается с <code>book/</code> (<strong>^book/</strong>), затем идут один, или более символов либо '-', или словарные символы (<strong>[-\w]+</strong>), а затем завершается. Он также захватывает данное множество символов и передает их в отображение в параметре с именем 'stub'.</p> + + <p>Это довольно типичный паттерн для "стаба". Стабы являются дружественными URL-адресами - первичными ключами для данных. Вы могли бы применить стаб, если вы захотели бы, чтобы URL-адрес вашей книги был более информативным. Например, <code>/catalog/book/the-secret-garden</code>, выглядит немного лучше чем <code>/catalog/book/33</code>.</p> + </td> + </tr> + </tbody> +</table> + +<p>Вы можете захватить (указать) несколько паттернов в одном преобразовании и, тем самым, закодировать много различной информации в URL-адресе.</p> + +<div class="note"> +<p><strong>Примечание</strong>: В качестве дополнительного задания, рассмотрите возможность того, как вы могли бы закодировать url на список всех книг, вышедших в определенный год, месяц, день и какое РВ (паттерн) должно соответствовать этому.</p> +</div> + +<h4 id="Передача_дополнительных_настроек_в_ваши_преобразования_URL-адресов">Передача дополнительных настроек в ваши преобразования URL-адресов</h4> + +<p>Одной возможностью, которую мы не применяли здесь, но которая могла бы быть вам полезной, является то, что вы можете объявлять и передавать <a href="https://docs.djangoproject.com/en/1.10/topics/http/urls/#views-extra-options">дополнительные настройки</a> в отображения. Данные настройки объявляются как словарь, который вы передаете как третий безымянный аргумент функции <code>url()</code>. Этот способ может быть полезен, если вы хотите воспользоваться тем же самым отображением для нескольких ресурсов и передавать данные для изменения его поведения в каждом отдельном случае (ниже, мы передаем разные имена шаблонов).</p> + +<pre class="brush: python">url(r'^/url/$', views.my_reused_view, {'my_template_name': 'some_path'}, name='aurl'), +url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'}, name='anotherurl'), + +</pre> + +<div class="note"> +<p><strong>Примечание:</strong> И дополнительные настройки, и именованные захваченные паттерны передаются в отображение как именованные параметры. Если вы используете одинаковое имя и для захваченного паттерна и для дополнительной настройки, то последняя будет отброшена, а в отображение будет передано значение захваченного паттерна. </p> +</div> + +<h3 id="Отображение_(на_основе_класса)">Отображение (на основе класса)</h3> + +<p>Откройте <strong>catalog/views.py</strong>, и скопируйте следующий код в нижнюю часть файла:</p> + +<pre class="brush: python">class BookDetailView(generic.DetailView): + model = Book</pre> + +<p>Это всё! Все что вам надо теперь сделать это создать шаблон с именем <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>, а отображение передаст ему информацию из базы данных для определенной записи <code>Book,</code>выделенной при помощи URL-преобразования. Внутри шаблона вы можете получить доступ к списку книг при помощи переменной с именем <code>object</code> или <code>book</code> (обобщённо "<code><em>the_model_name</em></code>").</p> + +<p>Если у вас имеется необходимость, то вы можете изменить текущий шаблон и/или имя объекта контекста, используемого для ссылки на книгу в шаблоне. Кроме того, вы можете переопределить методы, например, для добавления дополнительной информации к контексту.</p> + +<h4 id="Что_произойдет_если_записи_не_существует">Что произойдет, если записи не существует?</h4> + +<p>Если запрашиваемой записи не существует, тогда обобщенный класс отображения подробной информации автоматически "выкинет" исключение Http404 — в продакшине это приведет к автоматическому отображению страницы с текстом "resource not found" ("ресурс не найден"), которую, конечно же, вы можете настроить по своему усмотрению.</p> + +<p>Просто для иллюстрации идеи как это могло бы работать, мы приведем фрагмент кода, демонстрирующего возможную реализацию отображения в виде функции, если по каким-либо причинам вы не используете отображение на основе обобщенного класса.</p> + +<pre class="brush: python">def book_detail_view(request,pk): + try: + book_id=Book.objects.get(pk=pk) + except Book.DoesNotExist: + raise Http404("Book does not exist") + + #book_id=get_object_or_404(Book, pk=pk) + + return render( + request, + 'catalog/book_detail.html', + context={'book':book_id,} + ) +</pre> + +<p>В первую очередь отображение пытается получить определенную запись о книге из модели. Если ей это не удается, то "выбрасывается" исключение <code>Http404</code>, которое сигнализирует, что данная книга не найдена "not found". Последним шагом является, как обычно, вызов функции <code>render()</code> с именем соответствующего шаблона и данных о книге, передаваемых в параметре с именем <code>context</code> (в виде словаря).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Функция <code>get_object_or_404()</code> (показана закомментированной) является удобным "ярлыком" для генерации исключения <code>Http404</code> если запись не найдена.</p> +</div> + +<h3 id="Создание_шаблона_детальной_информации">Создание шаблона детальной информации</h3> + +<p>Создайте HTML файл <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong> и скопируйте в него содержимое, представленное ниже. Как было указано ранее, это шаблон "по умолчанию" (имя шаблона), который "ожидается"обобщенным классом отображения детальной информации (для модели с именем <code>Book</code> в приложении с именем <code>catalog</code>).</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + <h1>Title: \{{ book.title }}</h1> + + <p><strong>Author:</strong> <a href="">\{{ book.author }}</a></p> <!-- author detail link not yet defined --> + <p><strong>Summary:</strong> \{{ book.summary }}</p> + <p><strong>ISBN:</strong> \{{ book.isbn }}</p> + <p><strong>Language:</strong> \{{ book.language }}</p> + <p><strong>Genre:</strong> {% for genre in book.genre.all %} \{{ genre }}{% if not forloop.last %}, {% endif %}{% endfor %}</p> + + <div style="margin-left:20px;margin-top:20px"> + <h4>Copies</h4> + + {% for copy in book.bookinstance_set.all %} + <hr> + <p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'd' %}text-danger{% else %}text-warning{% endif %}">\{{ copy.get_status_display }}</p> + {% if copy.status != 'a' %}<p><strong>Due to be returned:</strong> \{{copy.due_back}}</p>{% endif %} + <p><strong>Imprint:</strong> \{{copy.imprint}}</p> + <p class="text-muted"><strong>Id:</strong> \{{copy.id}}</p> + {% endfor %} + </div> +{% endblock %}</pre> + +<ul> +</ul> + +<div class="note"> +<p>Ссылка на автора в шаблоне содержит пустой URL-адрес, потому что мы еще не создали страницу детальной информации об авторе. Когда это произойдет, вы должны будете обновить данный URL-адрес как указано ниже:</p> + +<pre><a href="<strong>{% url 'author-detail' book.author.pk %}</strong>">\{{ book.author }}</a> +</pre> +</div> + +<p>Хотя и несколько больше, но почти все в данном шаблоне нам уже встречалось ранее:</p> + +<ul> + <li>Мы расширяем наш базовый шаблон и переопределяем блок <code>content</code>.</li> + <li>Мы используем условие <code>if</code> для показа того, или иного содержимого.</li> + <li>Мы используем циклы <code>for</code> того, чтобы пробежаться по элементам (объектам) в соответствующих списках.</li> + <li>Мы получаем доступ к полям контекста при помощи "дот-нотации" (поскольку мы использовали обобщенный класс отображения детальной информации, то контекст имеет имя <code>book</code>; также можем использовать имя <code>object</code>)</li> +</ul> + +<p>Одной интересной вещью, которую мы не видели ранее, является функция <code>book.bookinstance_set.all()</code>. Данный метод является "автомагически"-сконструированным Django для того, чтобы вернуть множество записей <code>BookInstance</code>, связанных с данной книгой <code>Book</code>.</p> + +<pre class="brush: python">{% for copy in book.bookinstance_set.all %} +<!-- итерации по каждой копии/экземпляру книги --> +{% endfor %}</pre> + +<p>Этот метод создан, потому что вы, на стороне "многим" данной связи, объявили поле <code>ForeignKey</code> (один-ко многим). Поскольку вы ничего не объявили на другой стороне ("один") данной модели (то есть, модель <code>Book</code> "ничего не знает" про модель <code>BookInstance</code>), то она не имеет никакой возможности (по умолчанию) для получения множества соответствующих записей. Для того, чтобы обойти эту проблему, Django конструирует соответствующую функцию "обратного просмотра" ("reverse lookup"), которой вы можете воспользоваться. Имя данной функции создается в нижнем регистре и состоит из имени модели, в которой был объявлен <code>ForeignKey</code> (то есть, <code>bookinstance</code>), за которым следует <code>_set</code> (то есть функция, созданная для <code>Book</code> будет иметь вид <code>bookinstance_set()</code>).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Здесь мы используем <code>all()</code> для получения всех записей (по умолчанию). Вы, наверное, могли бы использовать метод <code>filter()</code> для получения подмножетсва записей в коде, но, к сожалению, вы НЕ можете применить данный вызов в шаблоне, потому что вы не можете передать в нем (в шаблоне) аргументы в функцию.</p> + +<p>Обратите внимание, что если вы не определяете порядок выдачи данных (в вашем отображении, или в модели), то сервер разработки "выкинет" сообщения об ошибках, похожие на следующие:</p> + +<pre>[29/May/2017 18:37:53] "GET /catalog/books/?page=1 HTTP/1.1" 200 1637 +/foo/local_library/venv/lib/python3.5/site-packages/django/views/generic/list.py:99: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <QuerySet [<Author: Ortiz, David>, <Author: H. McRaven, William>, <Author: Leigh, Melinda>]> + allow_empty_first_page=allow_empty_first_page, **kwargs) +</pre> + +<p>Это случилось потому что, <a href="https://docs.djangoproject.com/en/1.10/topics/pagination/#paginator-objects">paginator object</a> (далее объект постраничного вывода) ожидает видеть некую упорядоченность ORDER BY при запросе к базе данных. Без этого, он не сможет гарантировать правильный вывод полученных данных!<strong> </strong></p> + +<p>Данное руководство пока не дошло до описания <strong>Pagination</strong> (пока, но скоро будет), и поскольку вы не можете использовать функцию <code>sort_by()</code> и передавать параметр (по той же причине, что и <code>filter()</code>) вы должны выбрать один из трех вариантов дальнейших действий:</p> + +<ol> + <li>Добавить атрибут <code>ordering</code> внутри <code>Meta-класса</code> объявленного в вашей модели.</li> + <li>Добавить атрибут <code>queryset</code> в вашей реализации класса отображения, определяющего <code>order_by()</code>.</li> + <li>Добавить метод <code>get_queryset</code> в вашу реализацию класса отображения и также определить метод <code>order_by()</code>.</li> +</ol> + +<p>Если вы выбрали пункт номер один с <code>Meta-классом</code> для модели Author (вероятно, не такой гибкий как вариант с настройкой класса отображения, но тем не менее, достаточно простой), вы должны прийти к чему-то похожему на следующее:</p> + +<pre>class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + return '%s, %s' % (self.last_name, self.first_name) + +<strong> class Meta: + ordering = ['last_name']</strong></pre> + +<p>Конечно же, поле не обязательно должно иметь имя <code>last_name</code>: оно может быть любым.</p> + +<p>И последнее, но не окончательное, вы должны сортировать по атрибуту/колонке, которая была проиндексирована (уникально, или нет) в вашей базе данных для того, чтобы избежать проблем с быстродействием. Конечно, это не является необходимым в данном примере (и мы, вероятно, забегаем далеко вперед), если у нас такое небольшое количество книг (и пользователей!), но это необходимо помнить для будущих проектов.</p> +</div> + +<h2 id="Как_это_теперь_выглядит">Как это теперь выглядит?</h2> + +<p>На данный момент мы должны были создать все необходимое для показа страниц со списком книг и детальной информацией. Запустите сервер (<code>python3 manage.py runserver</code>) и откройте ваш браузер <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>.</p> + +<div class="warning"> +<p><strong>Предупреждение:</strong> Не кликайте на каком-либо авторе, - ссылки пока не заданы — это будет вашим дополнительным заданием!</p> +</div> + +<p>Кликните ссылку <strong>All books</strong> для перехода на страницу со списком книг. </p> + +<p><img alt="Book List Page" src="https://mdn.mozillademos.org/files/14049/book_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 823px;"></p> + +<p>Затем кликните на ссылку одной из ваших книг. Если все настроено как надо, то вы должны увидеть то, что указано на картинке.</p> + +<p><img alt="Book Detail Page" src="https://mdn.mozillademos.org/files/14051/book_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 783px; margin: 0px auto; width: 926px;"></p> + +<h2 id="Постраничный_вывод_(Pagination)">Постраничный вывод (Pagination)</h2> + +<p>Если у вас всего лишь несколько записей в базе данных, то наша страница вывода списка книг будет выглядеть отлично. Тем не менее, когда у вас появятся десятки, или сотни записей ваша страница станет значительно дольше загружаться (и станет слишком длинной для комфортного просмотра). Решением данной проблемы является добавление постраничного вывода (Pagination) к вашему отображению списка, который будет выводить ограниченное количество элементов на каждой странице.</p> + +<p>Django имеет отличный встроенный механизм для постраничного вывода. Даже более того, он встроен в обобщенный класс отображения списков, следовательно вам не нужно проделывать большой объем работы, чтобы воспользоваться возможностями постраничного вывода!</p> + +<h3 id="Отображения">Отображения</h3> + +<p>Откройте <strong>catalog/views.py</strong> и добавьте поле <code>paginate_by</code> как показано жирным в следующем фрагменте.</p> + +<pre class="brush: python">class BookListView(generic.ListView): + model = Book + <strong>paginate_by = 10</strong></pre> + +<p>Как только у вас появится более 10 записей в базе данных отображение начнет формировать постраничный вывод данных, которые он передает шаблону. К различным страницам данного вывода можно получить доступ при помощи параметров GET-запроса — к странице 2 вы можете получить доступ, используя URL-адрес: <code>/catalog/books/<strong>?page=2</strong></code>.</p> + +<h3 id="Шаблоны">Шаблоны</h3> + +<p>Теперь, когда данные выводятся постранично, нам надо добавить функционал переключения между страницами в шаблона страницы. Поскольку мы хотели бы использовать данный механизм для всех списков на сайте, то мы пропишем его в базовом шаблоне сайта.</p> + +<p>Откройте <strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> и, ниже блока <code>content</code>, вставьте блок (во фрагменте не выделен жирным), отвечающий за постраничный вывод. Данный код, в первую очередь, проверяет "включен" ли механизм постраничного вывода для данной страницы и если это так, то он добавляет ссылки <code>next</code> и <code>previous,</code>соответственно (а также, номер текущей страницы). </p> + +<pre class="brush: python"><strong>{% block content %}{% endblock %}</strong> + +{% block pagination %} + {% if is_paginated %} + <div class="pagination"> + <span class="page-links"> + {% if page_obj.has_previous %} + <a href="\{{ request.path }}?page=\{{ page_obj.previous_page_number }}">previous</a> + {% endif %} + <span class="page-current"> + Page \{{ page_obj.number }} of \{{ page_obj.paginator.num_pages }}. + </span> + {% if page_obj.has_next %} + <a href="\{{ request.path }}?page=\{{ page_obj.next_page_number }}">next</a> + {% endif %} + </span> + </div> + {% endif %} +{% endblock %} </pre> + +<p>Параметр <code>page_obj</code> является объектом типа <a href="https://docs.djangoproject.com/en/1.10/topics/pagination/#paginator-objects">Paginator</a>, который будет создаваться каждый раз, когда будет применяться постраничный вывод данных для текущей страницы. Он позволяет получить всю информацию о текущей странице, о предыдущих страницах, сколько всего страниц и так далее. </p> + +<p>Мы используем <code>\{{ request.path }}</code> для получения URL-адреса текущей страницы, для того, чтобы создать ссылки на соответствующие страницы, обратите внимание, что данный вызов не зависит от объекта <code>page_obj</code>и, таким образом, может использоваться отдельно.</p> + +<p>На этом все!</p> + +<h3 id="Как_это_выглядит">Как это выглядит?</h3> + +<p>Картинка ниже показывает как выглядит постраничный вывод — если вы не добавили более 10 записей в вашу базу данных, тогда вы можете проверить как это работает, просто уменьшив значение в <code>paginate_by,</code> в файле <strong>catalog/views.py</strong>. Для получения результата, соответствующего картинке ниже, мы изменили<code>paginate_by = 2</code>.</p> + +<p>Ссылки на страницы показаны в нижней части страницы. Показаны ссылки следующая/предыдущая в зависимости от того на какой странице вы в данный момент находитесь.</p> + +<p><img alt="Book List Page - paginated" src="https://mdn.mozillademos.org/files/14057/book_list_paginated.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 924px;"></p> + +<h2 id="Проверьте_себя">Проверьте себя</h2> + +<p>Дополнительным задание в данной статье и для завершения данного этапа проекта будет создание отображений детальной информации об авторе и их списка. Эти отображения должны находиться по следующим адресам:</p> + +<ul> + <li><code>catalog/authors/</code> — Список авторов.</li> + <li><code>catalog/author/<em><id></em></code><em> </em>— Детальная информация об авторе со значением первичного ключа равным <em><code><id></code></em></li> +</ul> + +<p>Соответствующий код для URL-преобразований и оторажений должен быть идентичным коду для списка книг и детальной информаци о книге <code>Book</code>, который мы создали ранее. Шаблоны будут отличаться, но будут иметь похожее поведение.</p> + +<div class="note"> +<p><strong>Примечание</strong>:</p> + +<ul> + <li>Когда вы создадите URL-преобразование для страницы списка авторов вам понадобится обновить ссылку <strong>All authors</strong> в базовом шаблоне. Следуйте <a href="#Update_the_base_template">тем же путем</a>, который мы проделали когда обновляли ссылку <strong>All books</strong>.</li> + <li>Когда вы создадите URL-преобразование для страницы с детальной информацией об авторе, вы должны будете обновить <a href="#Creating_the_Detail_View_template">шаблон детальной информации о книге</a> (<strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>), таким образом, чтобы ссылка автора указывала на страницу с детальной информации о нем (а не быть пустой). Данная ссылка будет иметь вид как указано жирным во фрагменте ниже. + <pre class="brush: html"><p><strong>Author:</strong> <a href="<strong>{% url 'author-detail' book.author.pk %}</strong>">\{{ book.author }}</a></p> +</pre> + </li> +</ul> +</div> + +<p>Когда вы закончите, ваши страницы должны будут выглядеть как на картинке.</p> + +<p><img alt="Author List Page" src="https://mdn.mozillademos.org/files/14053/author_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<ul> +</ul> + +<p><img alt="Author Detail Page" src="https://mdn.mozillademos.org/files/14055/author_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 358px; margin: 0px auto; width: 825px;"></p> + +<ul> +</ul> + +<h2 id="Итоги">Итоги</h2> + +<p>Поздравляем! Наш базовый функционал библиотеки готов! </p> + +<p>В данной статье мы изучили как применять обобщенные классы отображения списка и детальной информации, и использовать их для создания страниц отображения наших книг и авторов. Кроме того, мы многое узнали о паттернах преобразования, построенных на основе регулярных выражений, а также то, как вы можете передавать данные из URL-адреса в ваше отображение. Мы изучили несколько приемов применения шаблонов. В самом конце мы показали как осуществлять постраничный вывод списков, так, что наши списки управляются даже тогда, когда они содерждат много записей.</p> + +<p>В нашей следующей статье мы расширим нашу библиотеку, путем поддержки пользовательких аккаутов, и так образом продемонстрируем аутетификацию, разграничение уровней доступа, сессии и формы.</p> + +<h2 id="Дополнительная_информация">Дополнительная информация</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-display/">Встроенные обобщенные классы отображения</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-display/">Обобщенный вид отображения</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/class-based-views/intro/">Введение в отображения на основе классов</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins">Встроенные теги шаблона и фильтры</a> (Django docs).</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/pagination/">Постраничный вывод (Pagination)</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/django/home_page/index.html b/files/ru/learn/server-side/django/home_page/index.html new file mode 100644 index 0000000000..b573f3fdb6 --- /dev/null +++ b/files/ru/learn/server-side/django/home_page/index.html @@ -0,0 +1,359 @@ +--- +title: 'Руководство часть 5: Создание домашней страницы' +slug: Learn/Server-side/Django/Home_page +tags: + - django + - Для начинающих + - Изучение + - Кодирование + - Отображения + - Руководство + - Серверная сторона + - Статья + - Шаблоны +translation_of: Learn/Server-side/Django/Home_page +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</div> + +<p class="summary">Теперь мы готовы создать код нашей первой страницы — домашняя страница сайта <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> будет показывать количество записей в каждой модели, кроме того, она будет выводить боковую навигационную панель с ссылками на другие страницы сайта. В результате мы приобретем практический навык написания простых URL-преобразований и отображений, получения записей из базы данных и применения шаблонов.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Прочитать <a href="/en-US/docs/Learn/Server-side/Django/Introduction">Введение в Django</a>. Завершить изучение предыдущех частей руководства (включая <a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Руководство часть 4: Django административный раздел сайта</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понимать как создавать простые url-преобразования (которые не содержат никаких данных) и отображения, как получать данные из моделей и создавать шаблоны.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>Теперь, когда мы определили наши модели и создали несколько записей в них, пришло время написать код, который будет показывать данную информацию пользователям. И первое, что нам необходимо сделать это определиться какую информацию мы бы хотели показывать на наших страницах, а затем определить соответствующие URL-адреса для получения соответствующих ресурсов. Затем нам надо создать url-преобразования, отображения (функции, или классы), а затем шаблоны страницы. </p> + +<p>Диаграмма, представленная ниже, демонстрирует главный поток данных и элементов, которые нужно реализовать для управления HTTP запросами и ответами. Поскольку мы уже создали модель, то нам остается создать следующее:</p> + +<ul> + <li>URL-преобразования для перехода по соответствующему URL-адресу (с учетом информации, передаваемой в данном адресе) к соответствующей функции отображения.</li> + <li>Функции отображения для запроса соответствующих данных из моделей, создание страниц HTML для показа этих данных и их отправку в клиент пользователя (в браузер).</li> + <li>Шаблоны, которые используются отображениями для рендеринга (отрисовки) данных.</li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13931/basic-django.png" style="display: block; margin: 0px auto;"></p> + +<p>Как вы увидите в следующем разделе, у нас будет 5 страниц, которые мы немного опишем в данной статье. Данная статья, большей частью, будет сконцентрирована на реализации всего-лишь одной, домашней страницы нашего сайта (к другим страницам мы перейдем в других частях руководства). Это должно дать вам хорошее базовое представление о работе с URL-преобразованиями (связывании), отображениями и моделями.</p> + +<h2 id="Определяем_URL-адреса_страниц">Определяем URL-адреса страниц</h2> + +<p>По сути, так как для конечных пользователей, данная версия сайта <em>LocalLibrary</em> является read-only (только для чтения), то нам надо создать домашнюю страницу и страницы, которые будут <em>показывать</em> списки авторов и книг, а также детальную информацию о них, соответственно. </p> + +<p>Перечислим URL-адреса, которые понадобятся для наших страниц:</p> + +<ul> + <li><code>catalog/</code> — Домашняя/индексная странца.</li> + <li><code>catalog/books/</code> — Список всех книг.</li> + <li><code>catalog/authors/</code> — Список всех авторов.</li> + <li><code>catalog/book/<em><id></em></code> — Детальная информация для определенной книги со значением первичного ключа равного <code><em><id></em></code>. Например, <code>/catalog/book/3</code>, для <code>id = 3</code>.</li> + <li><code>catalog/author/<em><id></em></code><em> </em>— Детальная информация для определенного автора со значением первичного ключа равного <em><code><id>. </code></em>Например, <code>/catalog/author/11</code>, для автора с <code>id = 11</code>.</li> +</ul> + +<p>Первые три URL-адреса используются для показа домашней страницы, а также списков книг и авторов. Они не кодируют никакой дополнительной информации и результат показа данных страниц будет полностью зависеть от того, что находится в базе данных и, по сути, будет все время одним и тем же (при неизменной базе данных, конечно).</p> + +<p>Последние два URL-адреса применяются для показа детальной информации об определенной книге, или авторе — в себе они содержат соответствующее значение идентификатора (показан как <code><em><id></em></code>, выше). URL-преобразование получает данную информацию и передает ее в отображение, которое применяет ее для запроса к базе данных. Для кодирования и применения данной информации в вашем URL-адресе нам понадобится только одно url-преобразование, соответствующее отображение и шаблон страницы для показа любой книги (или автора). </p> + +<div class="note"> +<p><strong>Примечание</strong>: Django позволяет вам конструировать ваши URL-адреса любым, удобным для вас, способом — вы можете закодировать информацию в теле URL-адреса, как показано выше, или использовать URL-адрес типа <code>GET</code> (например, <code>/book/?id=6</code>). Независимо от ваших предпочтений, URL-адреса должны быть понятными, логичными и читабельными (<a href="https://www.w3.org/Provider/Style/URI">посмотрите совет W3C здесь</a>).<br> + <br> + Документация Django рекомендует кодировать информацию в теле URL-адреса, на практике это приводит к лучшей стркутуре сайта.</p> +</div> + +<p>Как было отмечено ранее, оставшаяся часть данной статьи описывает как сделать главную страницу сайта.</p> + +<h2 id="Создание_главной_страницы_сайта">Создание главной страницы сайта</h2> + +<p>Первой страницей, которую мы создадим, будет главная страница сайта (<code>catalog/</code>). Она будет небольшой статической HTML-страницей, которая будет показывать вычисленные "количества" различных записей из базы данных. Для того, чтобы проделать данную работу мы вначале создадим URL-преобразование, затем отображение и шаблон. </p> + +<div class="note"> +<p><strong>Примечание</strong>: Лучше уделить больше внимания на данный раздел, поскольку информация, представленная здесь, применяется для создания всех страниц сайта.</p> +</div> + +<h3 id="URL-преобразование">URL-преобразование</h3> + +<p>Когда мы создавали <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">скелет сайта</a> мы обновили <strong>locallibrary/urls.py </strong>так что всякий раз, когда начинается URL-адрес наш catalog/ получен и URLConf catalog.urls подлючен для обработки оставшейся части строки.</p> + +<pre><code>urlpatterns += [ + path('catalog/', include('catalog.urls')), +]</code></pre> + +<p>Примечание: всякий раз, когда Django сталкивается c <code><a href="https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.include" title="django.conf.urls.include">django.urls.include()</a></code> он отбрасывает часть совпавшего URL , и отправляет оставшуюся строку в включенный URLconf для дальнейшей обработки.</p> + +<p>Внутри нашего каталога приложения откройте <strong>urls.py</strong> и поместите в него текст, отмеченный жирным, ниже. </p> + +<pre class="brush: python line-numbers language-python"><code class="language-python">urlpatterns = [ +<strong> path('', views.index, name='index'),</strong> +]</code></pre> + +<p>Эта функция <code>path()</code> определяет URL-паттерн (в данном случае это пустая строка:<code>'' - </code>мы поговорим чуть более подробно о них далее в данном руководстве) и функцию отображения, которая будет вызвана, если введенный адрес будет соответствать данному паттерну (<code>views.index</code> — это функция с именем <code>index()</code> в <strong>views.py</strong>).</p> + +<p>Данная функция <code>path()</code>, кроме того, определяет параметр <code>name</code>, который уникально определяет <em>это </em>частное URL-преобразование. Вы можете использовать данное имя для "обратного" ("reverse") преобразования — то есть, для динамического создания URL-адреса, указывающего на ресурс, на которое указывает данное преобразование. Например, теперь, когда у нас имеется данное символическое имя, мы можем ссылаться на нашу домашнюю страницу при помощи создания следующей ссылки внутри какого-либо шаблона:</p> + +<pre class="brush: html"><a href="<strong>{% url 'index' %}</strong>">Home</a>.</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Мы могли бы, конечно, жестко указать прямую ссылку (то есть, <code><a href="<strong>/catalog/</strong>">Home</a></code>), но тогда, если мы изменим адрес нашей домашней страницы (например на <code>/catalog/index</code>), то данные ссылки перестанут корректно работать. Применение "обратного" url-преобразования более гибкий и эффективный подход!</p> +</div> + +<h3 id="Отображения_(на_основе_функций)">Отображения (на основе функций)</h3> + +<p>Отображение является функцией, которая обрабатывает HTTP-запрос, получает данные из базы данных (при необходимости), которые применяются для генерации страницы HTML. Затем функция отображения возвращает сгенерированную страницу пользователю в виде HTTP-ответа. В нашем случае, индексная функция демонстрирует этот процесс — она получает информацию о количестве записей <code>Book</code>, <code>BookInstance</code>, доступности <code>BookInstance</code>, а также записи <code>Author</code> из базы данных, затем передает эти записи в шаблон страницы, генерирует страницу и передает ее пользователю (клиенту пользователя, например браузеру).</p> + +<p>Откройте <strong>catalog/views.py</strong> и отметьте для себя, что данный файл уже импортирует функцию <a href="https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#django.shortcuts.render">render()</a> - функцию, которая генерирует HTML-файлы при помощи шаблонов страниц и соответствующих данных. </p> + +<pre class="brush: python">from django.shortcuts import render + +# Создайте ваше отображение здесь +</pre> + +<p>Скопируйте следующий код в нижнюю часть файла. Первая строка импортирует классы модели, которые мы будем использовать для доступа к данным во всех наших функциях (позже и классах) отображения.</p> + +<pre class="brush: python">from .models import Book, Author, BookInstance, Genre + +def index(request): + """ + Функция отображения для домашней страницы сайта. + """ + # Генерация "количеств" некоторых главных объектов + num_books=Book.objects.all().count() + num_instances=BookInstance.objects.all().count() + # Доступные книги (статус = 'a') + num_instances_available=BookInstance.objects.filter(status__exact='a').count() + num_authors=Author.objects.count() # Метод 'all()' применен по умолчанию. + + # Отрисовка HTML-шаблона index.html с данными внутри + # переменной контекста context + return render( + request, + 'index.html', + context={'num_books':num_books,'num_instances':num_instances,'num_instances_available':num_instances_available,'num_authors':num_authors}, + )</pre> + +<p>Первая часть функции отображения получает количество записей при помощи вызова функции <code>objects.all()</code> у атрибута <code>objects</code>, доступного для всех классов моделей. Похожим образом мы получаем список объектов <code>BookInstance</code>, которые имеют статус 'a' (Доступно). Вы можете найти дополнительную инофрмацию о работе с моделями в предыдущей части руководства (<a href="/en-US/docs/Learn/Server-side/Django/Models#Searching_for_records">Руководство часть 3: Применение моделей > Поиск записей</a>).</p> + +<p>В конце функции <code>index</code> вызывается функция <code>render()</code>, которая, в качестве ответа, создает и возвращает страницу HTML (эта функция "оборачивает" вызовы нескольких функций, тем самым существенно упрощая процесс разработки). В качестве параметров ей передаются объект <code>request</code> (типа <code>HttpRequest</code>), шаблон HTML-страницы с метками (<code>placeholders</code>), которые будут замещены данными, а также переменной <code>context</code> (словарь Python, который содержит данные, которые и будут замещать метки в шаблоне). </p> + +<p>В следующем разделе мы более подробно поговорим о шаблонах и переменной контекста. Давайте создадим наш шаблон, чтобы показать уже что-нибудь пользователю!</p> + +<h3 id="Шаблон">Шаблон</h3> + +<p>Шаблон это текстовый файл, который определяет структуру и расположение данных в файле, кроме того, в нем размещают специальные метки (placeholders), которые используются для показа реального содержимого, то есть данных. По умолчанию Django ищет файлы шаблонов в директории с именем '<strong>templates</strong>' внутри вашего приложения. Например, внутри индексной функции отображения, которую мы только что создали, вызов <code>render()</code> будет пытаться найти файл <strong>/locallibrary/catalog/templates/<em>index.html</em></strong> и в случае неудачи сгенерирует ошибку о том, что файл не найден. Вы можете увидеть данную ошибку, если вы сохраните предыдущие изменения, затем перейдете в браузер и наберете в адресной строке <code>127.0.0.1:8000</code>. В результате, в окно браузера будет выведено сообщение об ошибке "TemplateDoesNotExist at /catalog/" и некоторая другая информация.</p> + +<div class="note"> +<p><strong>Примечание</strong>: На самом деле, в зависимости от настроек проекта, Django просматривает несколько мест в поисках шаблона (поиск в директории приложения осуществляется по умолчанию!). Вы можете найти больше информации о шаблонах и форматах, которые они поддерживают, перейдя по ссылке <a href="https://docs.djangoproject.com/en/1.10/topics/templates/">Шаблоны</a> (Django docs).</p> +</div> + +<h4 id="Расширение_шаблонов">Расширение шаблонов</h4> + +<p>Шаблон главной страницы нашего сайта должен соответствовать стандарту разметки HTML для разделов <code>head</code> и <code>body</code>, кроме того иметь разделы для навигации (на другие страницы, которые мы создадим позже) и показа некоторого вводного текста. Большая часть данной структуры будет одинаковой для всех страниц нашего сайта. Таким образом, чтобы избежать копирования одной и той же информации, язык создания шаблонов Django позволяет вам объявить базовый шаблон, а затем расширить его, замещая только те части, которые являются специфическими для каждой страницы. </p> + +<p>Например, базовый шаблон <strong>base_generic.html</strong> может выглядеть как показано ниже. Как вы видите, этот файл содержит некоторую "общую" структуру HTML, разделы для заголовка, панель навигации и содержимое, отмеченное тэгами шаблона <code>block</code> и <code>endblock</code> (показано жирным). Данные блоки могут быть пустыми, или иметь содержимое, которое будет использоваться "по умолчанию" всеми страницами-наследниками.</p> + +<div class="note"> +<p><strong>Примечание</strong>: <em>Тэги</em> шаблона подобны функциям, которые могут применяться для создания циклов по спискам, выполнять условные оперции и так далее. Кроме тэгов, язык шаблона позволяет использовать переменные (которые передаются в шаблон из отображения), а также <em>шаблонные фильтры</em>, которые переформатируют переменные (например, переводят строку в нижний регистр).</p> +</div> + +<pre class="brush: html"><!DOCTYPE html> +<html lang="en"> +<head> + <strong>{% block title %}</strong><title>Local Library</title><strong>{% endblock %}</strong> +</head> + +<body> + <strong>{% block sidebar %}</strong><!-- insert default navigation text for every page --><strong>{% endblock %}</strong> + <strong>{% block content %}</strong><!-- default content text (typically empty) --><strong>{% endblock %}</strong> +</body> +</html> +</pre> + +<p>Когда мы определяем шаблон для конкретного отображения, то в первую очередь мы объявляем базовый шаблон (при помощи тэга <code>extends</code> — смотрите код в следующем фрагменте). Если имеются блоки в базовом шаблоне, которые мы хотим заместить, тогда в нашем текущем шаблоне мы объявляем <code>block</code>/<code>endblock</code> и указываем соответствующее имя блока. </p> + +<p>Например фрагмент кода, показанный ниже, демонстрирует применение тэга <code>extends</code> и переопределяет блок с именем <code>content</code>. Окончальный код HTML будет содержать все структуры базового файла шаблона (включая содержимое по умолчанию, которое мы указали в блоке <code>title</code>) и код блока <code>content</code>, который мы разместили в текущем файле шаблона.</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} +<h1>Local Library Home</h1> +<p>Welcome to <em>LocalLibrary</em>, a very basic Django website developed as a tutorial example on the Mozilla Developer Network.</p> +{% endblock %}</pre> + +<h4 id="Базовый_шаблон_сайта_LocalLibrary">Базовый шаблон сайта LocalLibrary</h4> + +<p>Базовый шаблон, который мы планируем использовать для сайта <em>LocalLibrary</em>, представлен ниже. Как вы видите, данный фрагмент содержит HTML код и объявляет следующие блоки <code>title</code>, <code>sidebar</code> и <code>content</code>. Мы добавили заголовок по умолчанию (который, возможно, мы захотим изменить), а также боковую панель навигации, содержащей ссылки на списки всех книг и авторов (панель навигации, мы, вероятно, не будем менять/замещать, но, тем не менее, добавив этот блок, мы оставим для себя такую возможность).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Во фрагменте мы используем два дополнительных шаблонных тега: <code>url</code> и <code>load static</code>. Они будут описаны в следующих разделах.</p> +</div> + +<p>Создайте новый файл — <strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> — и добавьте в него следующее содержимое:</p> + +<pre class="brush: html"><!DOCTYPE html> +<html lang="en"> +<head> + + {% block title %}<title>Local Library</title>{% endblock %} + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> + + <!-- Добавление дополнительного статического CSS файла --> + {% load static %} + <link rel="stylesheet" href="{% static 'css/styles.css' %}"> +</head> + +<body> + + <div class="container-fluid"> + + <div class="row"> + <div class="col-sm-2"> + {% block sidebar %} + <ul class="sidebar-nav"> + <li><a href="{% url 'index' %}">Home</a></li> + <li><a href="">All books</a></li> + <li><a href="">All authors</a></li> + </ul> + {% endblock %} + </div> + <div class="col-sm-10 "> + {% block content %}{% endblock %} + </div> + </div> + + </div> +</body> +</html></pre> + +<p>Шаблон использует (и включает в себя) JavaScript и CSS от <a href="http://getbootstrap.com/">Bootstrap</a> для лучшего размещения элементов и формирования внешнего вида HTML страницы. Применение Bootstrap, или любого другого фреймворка для клиентской части сайта, является довольно продуктивным способом повышения привлекательности страницы, в том числе, это учитывает возможность запроса и показа сайта с устройств, с различными разрешениями экрана, а кроме того, это позволяет нам повысить уровень взаимодействия с пользователем — мы направим большую часть своих усилий на серверную часть нашего сайта!</p> + +<p>Базовый шаблон ссылается на локальный файл css (<strong>styles.css</strong>), который предоставляет дополнительные стили. Создайте <strong>/locallibrary/catalog/static/css/styles.css</strong> и добавьте в него следующее содержимое:</p> + +<pre class="brush: css">.sidebar-nav { + margin-top: 20px; + padding: 0; + list-style: none; +}</pre> + +<h4 id="Индексный_шаблон_(шаблон_главной_страницы_сайта)">Индексный шаблон (шаблон главной страницы сайта)</h4> + +<p>Создайте файл HTML <strong>/locallibrary/catalog/templates/<em>index.html</em></strong> и скопируйте в него код, указанный ниже. Как вы наверное заметили, в первой строке мы расширяем наш базовый шаблон, а затем замещаем содержимое блока <code>content</code>, базового шаблона, новым содержимым текущего шаблона.</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} +<h1>Local Library Home</h1> + + <p>Welcome to <em>LocalLibrary</em>, a very basic Django website developed as a tutorial example on the Mozilla Developer Network.</p> + +<h2>Dynamic content</h2> + + <p>The library has the following record counts:</p> + <ul> + <li><strong>Books:</strong> <strong>\{{ num_books }}</strong></li> + <li><strong>Copies:</strong> <strong>\{{ num_instances }}</strong></li> + <li><strong>Copies available:</strong> <strong>\{{ num_instances_available }}</strong></li> + <li><strong>Authors:</strong> <strong>\{{ num_authors }}</strong></li> + </ul> + +{% endblock %}</pre> + +<p>В данном фрагменте, в разделе <em>Динамическое содержимое, </em>мы объявили метки (<em>шаблонные переменные</em>) для информации, которую мы получаем из соответствующего отображения. Данные переменные объявляются при помощи "двойных фигурных скобок" (в предыдущем фрагменте выделено жирным).</p> + +<div class="note"> +<p><strong>Примечание:</strong> Переменные шаблона заключаются в двойные фигурные скобки (<code>\{{ num_books }}</code>) , а тэги шаблона (функции шаблона), помещаются в одинарные фигурные скобки со знаками процента (<code>{% extends "base_generic.html" %}</code>).</p> +</div> + +<p>Важно отметить, что данные переменные имеют имена, соответствующие именам передаваемых <em>ключей</em> из словаря переменной <code>context</code>, которая, в свою очередь, передается из отображения, во время вызова функции <code>render()</code> (смотри ниже). При отрисовке шаблона, вместо этих ключей будут подставлены, соответствующие им, <em>значения</em>. </p> + +<pre class="brush: python">return render( + request, + 'index.html', + context={'<strong>num_books</strong>':num_books,'<strong>num_instances</strong>':num_instances,'<strong>num_instances_available</strong>':num_instances_available,'<strong>num_authors</strong>':num_authors}, +)</pre> + +<h4 id="Ссылка_на_статические_файлы_их_шаблонов">Ссылка на статические файлы их шаблонов</h4> + +<p>Любой ваш проект с большой вероятностью будет использовать статические ресурсы, включая JavaScript, CSS и изображения. В связи с тем, что расположение этих файлов может быть неизвестно (или может измениться), Django позволяет вам в шаблоне указать относительное расположение данных файлов при помощи глобального значения <code>STATIC_URL</code> (по умолчанию, значение параметра <code>STATIC_URL</code> установлено в '<code>/static/</code>', но вы можете выбрать любое другое значение, указав, например, сетевой ресурс, или что-то еще).</p> + +<p>Внутри шаблона вы вызываете функцию (тэг) <code>load</code>, которая загружает статическую библиотеку "static" (как показано ниже). После того как статическая библиотека загружена, вы можете использовать тэг шаблона <code>static</code>, который указывает относительный путь URL к интересующему вас файлу.</p> + +<pre class="brush: html"> <!-- Добавляем дополнительный статический CSS-файл --> +{% load static %} +<link rel="stylesheet" href="{% static 'css/styles.css' %}"></pre> + +<p>Тем же способом вы можете загрузить нужное изображение. Например:</p> + +<pre class="brush: html">{% load static %} +<img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="My image" style="width:555px;height:540px;"/> +</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Фрагменты выше указывают пути расположения файлов, но Django не использует их по умолчанию. В процессе разработки сервер использует значения, указанные в глобальном файле URL-преобразований (<strong>/locallibrary/locallibrary/urls.py</strong>), который мы создали в части <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">создание скелета сайта</a>. В дальнейшем, в продакшине, вам нужно будет уточнить параметры расположения статических файлов. Мы вернемся к этому позже.</p> +</div> + +<p>Для получения более подробной информации о работе со статическими файлами обратитесь к документации по ссылке <a href="https://docs.djangoproject.com/en/1.10/howto/static-files/">Управление статическими файлами</a> (Django docs).</p> + +<h4 id="Построение_URL-адресов">Построение URL-адресов</h4> + +<p>Базовый шаблон, указанный выше, вводит тэг <code>url</code>.</p> + +<pre class="brush: python"><li><a href="{% url 'index' %}">Home</a></li> +</pre> + +<p>Данный тэг с именем <code>url()</code>, ищет в файле <strong>urls.py</strong> связанное значение переменной, указанной в качестве ее параметра <code>'index'</code>, а затем возвращает URL, который вы можете использовать для ссылки на соответствующие ресурсы.</p> + +<h2 id="Как_теперь_все_это_выглядит">Как теперь все это выглядит?</h2> + +<p>На данный момент мы должны были сделать все что необходимо, для того, чтобы показать главную страницу нашего сайта. Запустите сервер (<code>python3 manage.py runserver</code>) и введите в ваш браузер адрес <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>. Если все настроено как надо, то ваш сайт должен выглядеть как показано на следующей картинке.</p> + +<p><img alt="Index page for LocalLibrary website" src="https://mdn.mozillademos.org/files/14045/index_page_ok.png" style="border-style: solid; border-width: 1px; display: block; height: 356px; margin: 0px auto; width: 874px;"></p> + +<div class="note"> +<p><strong>Примечание:</strong> На данном этапе вы не сможете воспользоваться ссылками на страницы <strong>All books</strong> и <strong>All authors</strong>, потому что url-адреса, отображения и шаблоны для данных страниц не созданы (мы просто объявили метки для соответствующих ссылок в базовом шаблоне<code> base_generic.html</code>).</p> +</div> + +<h2 id="Проверьте_себя">Проверьте себя</h2> + +<p>А теперь парочка заданий, чтобы проверить, насколько вы усвоили работу с запросами к моделям базы данных, взаимодействия с отображениями и шаблонами. </p> + +<ol> + <li>В главном файле шаблона (<em>base_generic.html</em>) есть блок <code>title</code>. Переопределите этот блок в индексном шаблоне (<em>index.html</em>) и задейте новый заголовок для этой страницы.</li> + <li>Модифицируйте функцию отображения таким образом, чтобы получать из базы данных количество жанров и количество книг, которые содержат в своих заголовках какое-либо слово (без учета регистра), а затем передайте эти значения в шаблон.</li> +</ol> + +<ul> +</ul> + +<h2 id="Итог">Итог</h2> + +<p>Мы создали домашнюю страницу для нашего сайта — HTML страница, которая показывает количество некоторых записей из базы данных и содержит ссылки на другие "все-еще-будут-созданы" страницы. Кроме того, мы изучили большое количество базовой информации об url-преобразованиях, отображениях, запросах к базе данных, используя наши модели, передачу информации из отображений в шаблоны, кроме того, создание и расширение шаблонов.</p> + +<p>В следующей части, при помощи наших новых знаний, мы создадим еще четыре страницы.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/intro/tutorial03/">Написание вашего первого приложения Django, часть 3: Отображения и Шаблоны</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/http/urls/">URL-диспетчер</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/http/views/">Функции отображения</a> (DJango docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/templates/">Шаблоны</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/howto/static-files/">Управление статическими файлами</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#django.shortcuts.render">Удобные (встроенные) функции Django</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/django/index.html b/files/ru/learn/server-side/django/index.html new file mode 100644 index 0000000000..7e167477b1 --- /dev/null +++ b/files/ru/learn/server-side/django/index.html @@ -0,0 +1,66 @@ +--- +title: Веб-фреймворк Django (Python) +slug: Learn/Server-side/Django +tags: + - back-end программирование + - Введение + - Джанго + - Изучать + - Начинающим +translation_of: Learn/Server-side/Django +--- +<div>{{LearnSidebar}}</div> + +<p>Django является чрезвычайно популярным и полнофункциональным серверным веб-фреймворком, написанным на Python. Данный модуль расскажет о том, почему Django один из самых популярных серверных веб-фреймворков, как установить среду разработки, и как начать использовать его для создания собственных веб-приложений.</p> + +<h2 id="Требования">Требования</h2> + +<p>Перед началом работы с этим модулем вам не обязательно уже быть знакомым с Django. Вам бы пригодилось общее понимание того, что такое серверное веб-программирование и веб-фреймворки, почерпнутое, в идеале, из топиков другого нашего модуля <a href="./First_steps">Первые шаги серверного программирования вебсайтов</a>.</p> + +<p>Рекомендуется базовое понимание концепций программирования и языка Python, но это не обязательно для освоения основных понятий.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Python является одним из самых доступных в чтении и понимании для новичков языком программирования. Тем не менее, если вы захотите глубже понять этот модуль, в Интернете сейчас доступны многочисленные бесплатные книги и учебные пособия (новички в программирование возможно захотят посетить <a href="https://wiki.python.org/moin/BeginnersGuide/NonProgrammers">Python for Non Programmers</a> на вики-страницах python.org).</p> +</div> + +<h2 id="Руководство">Руководство</h2> + +<dl> + <dt><a href="/ru/docs/Learn/Server-side/Django/Introduction">Введение в Django</a></dt> + <dd>В этой первой статье по Django мы ответим на вопрос "Что такое Django?" и сделаем обзор того, что делает этот веб-фреймворк особенным. Мы кратко рассмотрим основные особенности, включая некоторый продвинутый функционал, на котором у нас не будет возможности подробно остановиться в этом модуле. Мы также покажем вам некоторые из основных строительных блоков приложения Django, чтобы дать вам представление о том, что он может сделать, прежде чем вы перейдете к установке и начнете экспериментировать.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/development_environment">Установка среды разработки Django</a></dt> + <dd>Теперь, когда вы знаете, что такое Django, мы покажем вам, как установить и протестировать среду разработки Django для Windows, Linux (Ubuntu) и Mac OS X — какую бы операционную систему вы не использовали, эта статья должна дать вам понимание того, что вам потребуется, чтобы начать разработку Django-приложений .</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">Учебник Django: Веб-сайт местной библиотеки</a></dt> + <dd>Первая статья в нашей серии практических уроков объясняет, что вы узнаете, и представит обзор веб-сайта «местной библиотеки», над которым мы будем работать и развиваться в последующих статьях.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/skeleton_website">Учебник Django часть 2: Создание скелета веб-сайта</a></dt> + <dd>В этой статье показано, как вы можете создать проект веб-сайта «каркас» в качестве основы, после чего вы сможете заполнить параметры сайта, urls, модели, представления и шаблоны.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Models">Учебник Django часть 3: Использование моделей</a></dt> + <dd>В этой статье показано, как определить модели для сайта местной библиотеки — модели представляют структуры данных, в которых мы хотим хранить данные нашего приложения, а также позволяют Django хранить данные в базе данных для нас (и модифицировать позже). Она раскрывает, что такое модель, как она объявляется и некоторые из основных типов полей. В ней также кратко показаны некоторые из основных способов доступа к данным модели.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Admin_site">Учебник Django часть 4: Django admin веб-сайта</a></dt> + <dd>Теперь, когда мы создали модели для сайта местной библиотеки, мы будем использовать Django Admin, чтобы добавить данные о книгах в библиотеке. Сначала мы покажем вам, как регистрировать и администрировать модели сайта а затем мы покажем вам, как входить в систему и создавать некоторые данные. В конце мы покажем некоторые способы дальнейшего улучшения представлений сайта.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Home_page">Учебник Django часть 5: Создание главной страницы </a></dt> + <dd>Теперь мы готовы добавить код для отображения нашей первой полной страницы — главной страницы сайта местной библиотеки, которая показывает, сколько записей у нас есть для каждого типа модели, и предоставляет ссылки на боковых панелях на другие наши страницы. По пути мы получим практический опыт написания основных карт и представлений URL, получения записей из базы данных и использования шаблонов.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Generic_views">Учебник Django часть 6: Общий список и подробные представления</a></dt> + <dd>Это руководство расширяет наш сайт местной библиотеки, добавляя список и подробные страницы для книг и авторов. Здесь мы узнаем об общих представлениях на основе классов и покажем, как они могут уменьшить количество кода, который вы должны писать для случаев общего использования. Мы также перейдем к обработке URL-адресов более подробно, покажем, как выполнить базовое сопоставление шаблонов.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Sessions">Учебник Django часть 7: Структура сессий</a></dt> + <dd>Это руководство расширяет наш сайт местной библиотеки, добавляя счётчик посещений домашней страницы. Это относительно простой пример, но он показывает, как вы можете использовать структуру сессии, чтобы обеспечить постоянное поведение анонимных пользователей на ваших собственных сайтах.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Authentication">Учебник Django часть 8: Авторизация и права пользователей</a></dt> + <dd>В этом уроке мы покажем вам, как разрешить пользователям входить на ваш сайт со своими учетными записями и как управлять тем, что они могут делать и видеть на основе того, зарегистрированы ли они или нет, и их допусках. В рамках этой демонстрации мы расширим сайт местной библиотеки, добавив страницы входа и выхода, а также страницы пользователей и персональные страницы для просмотра книг, которые были взяты на руки.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Forms">Учебник Django часть 9: Работа с формами</a></dt> + <dd>В этом уроке мы покажем вам, как работать с <a href="/en-US/docs/Web/Guide/HTML/Forms">HTML Forms</a> в Django, и в частности, самый простой способ писать формы для создания, обновления и удаления экземпляров модели. В рамках этой демонстрации мы расширим сайт местной библиотеки, чтобы библиотекари могли вносить новые книги, создавать, обновлять и удалять авторов, используя наши собственные формы (а не использовать приложение администратора).</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Testing">Учебник Django часть10: Тестирование веб-приложения Django</a></dt> + <dd>По мере роста веб-сайтов становится сложнее проверять вручную — требуется больше проверок, поскольку взаимодействие между компонентами усложняется, небольшое изменение в одной области может потребовать дополнительные тесты для проверки его влияния на другие области. Один из способов смягчить эти проблемы - написать автоматизированные тесты, которые можно легко и надежно запускать каждый раз, когда вы вносите изменения. В этом руководстве показано, как автоматизировать модульное тестирование вашего сайта с помощью тестовой среды Django.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/Deployment">Учебник Django часть 11: Деплой Django на продакшн</a></dt> + <dd>Теперь вы создали (и протестировали) удивительный сайт местной библиотеки, вам захочется установить его на общедоступный веб-сервер, чтобы к нему мог получить доступ персонал библиотеки и пользователи Интернета. В этой статье представлен обзор того, как вы можете найти хост для развертывания вашего веб-сайта и что вам нужно сделать, чтобы подготовить ваш сайт к выпуску.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Django/web_application_security">Безопасность веб-приложений Django</a></dt> + <dd>Защита пользовательских данных является неотъемлемой частью любой разработки сайта. Ранее мы объяснили некоторые из наиболее распространенных угроз безопасности в статье <a href="https://developer.mozilla.org/ru/docs/Web/Security">Web security</a> — Эта статья дает практическую демонстрацию того, как встроенные средства защиты Django справляются с такими угрозами.</dd> +</dl> + +<h2 id="Задания">Задания</h2> + +<p>Следующее задание проверит ваше понимание того, как создать сайт с помощью Django, как описано в руководствах, перечисленных выше.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django мини-блог</a></dt> + <dd>В этом задании вы будете использовать некоторые знания, которые вы узнали из этого модуля, чтобы создать свой собственный блог.</dd> +</dl> diff --git a/files/ru/learn/server-side/django/models/index.html b/files/ru/learn/server-side/django/models/index.html new file mode 100644 index 0000000000..9ed7993e0b --- /dev/null +++ b/files/ru/learn/server-side/django/models/index.html @@ -0,0 +1,448 @@ +--- +title: 'Django учебник Часть 3: Использование моделей' +slug: Learn/Server-side/Django/Models +tags: + - Джанго + - данные + - модель + - туториал +translation_of: Learn/Server-side/Django/Models +--- +<div> {{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</div> + +<p class="summary">В этой статье показано, как определить модели для <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> сайта. Она объясняет, что такое модель, как она объявляется, и некоторые из основных типов полей. В ней также кратко показаны некоторые из основных способов доступа к данным модели.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки</th> + <td><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Научиться проектировать и создавать свои собственные модели, выбирая подходящие поля.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>Веб-приложения Django получают доступ и управляют данными через объекты Python, называемые моделями. Модели определяют структуру хранимых данных, включая типы полей и, возможно, их максимальный размер, значения по умолчанию, параметры списка выбора, текст справки для документации, текст меток для форм и т. д. Определение модели не зависит от основной базы данных - вы можете выбрать один из нескольких компонентов вашей настройки проекта. После того, как вы выбрали какую базу данных хотите использовать, вам не нужно напрямую работать с ней - вы просто пишете свою структуру модели и код, а Django делает всю грязную работу, связанную с базой данных за вас.</p> + +<p>В этом учебнике показано, как определить и получить доступ к моделям на примере <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary website</a>.</p> + +<h2 id="Проектирование_моделей_LocalLibrary">Проектирование моделей LocalLibrary</h2> + +<p>Перед тем, как вы начнёте программировать модели, стоит потратить несколько минут, чтобы подумать о том, какие данные нам нужно хранить, и о взаимоотношениях между разными объектами.</p> + +<p>Мы знаем, что нам нужно хранить информацию о книгах (название, резюме, автор, язык, на котором написана книга, категория, ISBN) и что у нас может быть несколько доступных экземпляров (с уникальным глобальным идентификатором, статусом доступности и т. Д.). Нам может потребоваться хранить больше информации об авторе, чем просто их имя, и могут быть несколько авторов с одинаковыми или похожими именами. Мы хотим иметь возможность сортировать информацию на основе названия книги, автора, письменного языка и категории.</p> + +<p>При проектировании ваших моделей имеет смысл иметь отдельные модели для каждого «объекта» (группа связанной информации). В этом случае очевидными объектами являются книги, экземпляры книг и авторы.</p> + +<p>Вы также можете использовать модели для представления параметров списка выбора (например, как выпадающий список вариантов), вместо жёсткого кодирования выбора на самом веб-сайте - это рекомендуется, когда все варианты неизвестны заранее или могут измениться. Очевидные кандидаты на модели в этом случае включают жанр книги (например, «Научная фантастика», «Французская поэзия» и т. д.) И язык (английский, французский, японский).</p> + +<p>Как только мы определились с нашими моделями и полями, нам нужно подумать об отношениях. Django позволяет вам определять отношения, как один к одному (<code>OneToOneField</code>), один ко многим (<code>ForeignKey</code>) и многие ко многим (<code>ManyToManyField</code>).</p> + +<p>Диаграмма ассоциации UML, приведённая ниже показывает модели, которые мы определили в этом случае (в виде блоков). Как и выше, мы создали модели для книги (общие сведения о книге), экземпляр книги (статус конкретных физических копий книги, доступных в системе) и автора.Мы также решили создать модель для жанра, чтобы можно было создавать / выбирать значения через интерфейс администратора. Мы решили не иметь модель для BookInstance: status - мы жестко закодировали значения (LOAN_STATUS), потому что мы не ожидаем их изменения. В каждом из полей вы можете увидеть имя модели, имена и типы полей, а также методы и их типы возврата.</p> + +<p>На диаграмме также показаны зависимости между моделями, включая их <em>множители</em>. Множители представляют собой числа на диаграмме, показывающие минимум и максимум единиц каждой модели, которые могут присутствовать в этой связи. Например, соединительная линия между ящиками показывает, что книга и жанр связаны между собой. Цифры, близкие к модели жанра, показывают, что у книги может быть один или несколько жанров (сколько угодно), а числа на другом конце строки рядом с моделью книги показывают, что у жанра может быть ноль или более связанных книг.</p> + +<p><img alt="LocalLibrary Model UML - v3" src="https://mdn.mozillademos.org/files/15646/local_library_model_uml.png" style="height: 660px; width: 977px;"></p> + +<div class="note"> +<p>Примечание. В следующем разделе приведен базовый пример, поясняющий, как модели определяются и используются. Когда вы его прочитаете, подумайте, как мы построим каждую из моделей на диаграмме выше.</p> +</div> + +<h2 id="Модель_для_начинающих">Модель для начинающих</h2> + +<p>В этом разделе представлен краткий обзор того, как определяется модель, и некоторые из наиболее важных полей и аргументы поля.</p> + +<h3 id="Определение_модели">Определение модели</h3> + +<p>Модели обычно определяются в приложении <strong>models.py</strong>. Они реализуются как подклассы <code>django.db.models.Model</code>, и могут включать поля, методы и метаданные. В приведенном ниже фрагменте кода показана «типичная» модель, названная <code>MyModelName</code>:</p> + +<pre class="notranslate">from django.db import models + +class MyModelName(models.Model): + """ + A typical class defining a model, derived from the Model class. + """ + + # Fields + my_field_name = models.CharField(max_length=20, help_text="Enter field documentation") + ... + + # Metadata + class Meta: + ordering = ["-my_field_name"] + + # Methods + def get_absolute_url(self): + """ + Returns the url to access a particular instance of MyModelName. + """ + return reverse('model-detail-view', args=[str(self.id)]) + + def __str__(self): + """ + String for representing the MyModelName object (in Admin site etc.) + """ + return self.field_name</pre> + +<p>В следующих разделах мы подробно рассмотрим каждый элемент внутри модели:</p> + +<h4 id="Поля">Поля</h4> + +<p>Модель может иметь произвольное количество полей любого типа - каждый представляет столбец данных, который мы хотим сохранить в одной из наших таблиц базы данных. Каждая запись (строка) базы данных будет состоять из одного значения каждого поля. Давайте рассмотрим приведенный выше пример:</p> + +<pre class="brush: js notranslate">my_field_name = models.CharField(max_length=20, help_text="Enter field documentation")</pre> + +<p>Наш вышеприведенный пример имеет одно поле, называемое my_<code>field_name</code>, типа <code>models.CharField</code> — что означает, что это поле будет содержать строки буквенно-цифровых символов. Типы полей назначаются с использованием определенных классов, которые определяют тип записи, которая используется для хранения данных в базе данных, а также критерии проверки, которые должны использоваться, когда значения получены из формы HTML (то есть, что составляет действительное значение). Типы полей также могут принимать аргументы, которые дополнительно определяют, как поле хранится или может использоваться. В этом случае мы даем нашему полю два аргумента:</p> + +<ul> + <li><code>max_length=20</code> — Указывает, что максимальная длина значения в этом поле составляет 20 символов.</li> + <li><code>help_text="Enter field documentation"</code> — предоставляет текстовую метку для отображения, чтобы помочь пользователям узнать, какое значение необходимо предоставить, когда это значение должно быть введено пользователем через HTML-форму.</li> +</ul> + +<p>Имя поля используется для обращения к нему в запросах и шаблонах. В полях также есть метка, которая задается как аргумент (verbose_name), либо выводится путем заглавной буквы первой буквы имени переменной поля и замены любых символов подчеркивания пробелом (например, my_field_name будет иметь метку по умолчанию <em>My field name</em>).</p> + +<p>Порядок, в котором объявляются поля, будет влиять на их порядок по умолчанию, если модель отображается в форме (например, на сайте администратора), хотя это может быть переопределено.</p> + +<h5 id="Общие_аргументы_поля">Общие аргументы поля</h5> + +<p>Следующие общие аргументы могут использоваться при объявлении многих / разных типов полей:</p> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#help-text">help_text</a>: Предоставляет текстовую метку для HTML-форм (например, на сайте администратора), как описано выше.</li> + <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#verbose-name">verbose_name</a>: Удобо-читаемое имя для поля, используемого в поле метки. Если не указано, Django выведет по умолчанию подробное название от имени поля.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#default">default</a>: Значение по умолчанию для поля. Это может быть значение или вызываемый объект, и в этом случае объект будет вызываться каждый раз, когда создается новая запись.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#null">null</a>: Если True, Django будет хранить пустые значения как NULL в базе данных для полей, где это уместно (CharField вместо этого сохранит пустую строку). По умолчанию используется значение False.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#blank">blank</a>: Если True, поле может быть пустым в ваших формах. По умолчанию используется значение False, что означает, что проверка формы Django заставит вас ввести значение. Это часто используется с null = True, потому что если вы хотите разрешить пустые значения, вы также хотите, чтобы база данных могла представлять их соответствующим образом.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#choices">choices</a>: Группа вариантов для этого поля. Если это предусмотрено, по умолчанию соответствующий виджет формы будет полем выбора с этими вариантами вместо стандартного текстового поля.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#primary-key">primary_key</a>: Если True, задает текущее поле в качестве первичного ключа для модели (первичный ключ - это специальный столбец базы данных, предназначенный для однозначной идентификации всех разных записей таблицы). Если в качестве первичного ключа не указано поле, Django автоматически добавит для этой цели поле.</li> +</ul> + +<p>Есть много других вариантов - вы можете просмотреть <a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/">full list of field options here</a>.</p> + +<h5 id="Общие_типы_полей">Общие типы полей</h5> + +<p>Следующие общие аргументы могут использоваться при объявлении многих / разных типов полей:</p> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.CharField">CharField</a> Используется для определения строк фиксированной длины от короткой до средней. Вы должны указать max_length для хранения данных.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.TextField">TextField</a> используется для больших строк произвольной длины. Вы можете указать <code>max_length</code> для поля, но это используется только тогда, когда поле отображается в формах (оно не применяется на уровне базы данных).</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.IntegerField" title="django.db.models.IntegerField">IntegerField</a> это поле для хранения значений (целого числа) и для проверки введенных значений в виде целых чисел в формах.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.DateField">DateField</a> и <a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.DateTimeField">DateTimeField</a> используются для хранения / представления дат и информации о дате / времени (как Python datetime.date и datetime.datetime, соответственно). Эти поля могут дополнительно объявлять (взаимоисключающие) параметры <code>auto_now=True</code> (для установки поля на текущую дату каждый раз, когда модель сохраняется), auto_now_add (только для установки даты, когда модель была впервые создана) и по умолчанию (чтобы установить дату по умолчанию, которую пользователь может переустановить).</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.EmailField">EmailField</a> используется для хранения и проверки адресов электронной почты.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.FileField">FileField</a> и <a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ImageField">ImageField</a> используются для загрузки файлов и изображений соответственно ( <code>ImageField</code> просто добавляет дополнительную проверку, что загруженный файл является изображением). Они имеют параметры для определения того, как и где хранятся загруженные файлы.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.AutoField">AutoField</a> - это особый тип IntegerField, который автоматически увеличивается. Первичный ключ этого типа автоматически добавляется в вашу модель, если вы явно не укажете его.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ForeignKey">ForeignKey</a> Используется для указания отношения «один ко многим» к другой модели базы данных (например, автомобиль имеет одного производителя, но производитель может делать много автомобилей). «Одна» сторона отношения - это модель, содержащая ключ.</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ManyToManyField">ManyToManyField</a> используется для определения отношения «многие ко многим» (например, книга может иметь несколько жанров, и каждый жанр может содержать несколько книг). В нашем приложении для библиотек мы будем использовать их аналогично ForeignKeys, но их можно использовать более сложными способами для описания отношений между группами. Они имеют параметр on_delete, чтобы определить, что происходит, когда связанная запись удаляется (например, значение <code>models.SET_NULL</code> просто установило бы значение NULL)</li> +</ul> + +<p>Существует много других типов полей, включая поля для разных типов чисел (большие целые числа, малые целые числа, дробные), логические значения, URL-адреса, slugs, уникальные идентификаторы и другие «связанные с временем» сведения (продолжительность, время и т. д.). Вы можете просмотреть <a href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#field-types">full list here</a>.</p> + +<h4 id="Метаданные">Метаданные</h4> + +<p>Вы можете объявить метаданные на уровне модели для своей модели, объявив класс Meta, как показано на рисунке.</p> + +<pre class="brush: python notranslate">class Meta: + ordering = ["-my_field_name"] + ...</pre> + +<p>Одной из наиболее полезных функций этих метаданных является управление сотрировкой записей, возвращаемых при запросе типа модели. Вы можете сделать это, указав соответствия названия полей для сортировки, как показано выше. Порядок будет зависеть от типа поля (поля символов отсортированы в алфавитном порядке, а поля даты отсортированы в хронологическом порядке). Как показано выше, вы можете префикс имени поля минус-символом (-), чтобы изменить порядок сортировки.</p> + +<p>Например, если мы решили сортировать книги по умолчанию:</p> + +<pre class="brush: python notranslate">ordering = ["title", "-pubdate"]</pre> + +<p>Книги будут отсортированы по алфавиту по названию, от A-Z, а затем по дате публикации внутри каждого названия, от самого нового до самого старого.</p> + +<p>Другим распространенным атрибутом является verbose_name, подробное имя для класса в единственной и множественной форме:</p> + +<pre class="brush: python notranslate">verbose_name = "BetterName"</pre> + +<p>Другие полезные атрибуты позволяют создавать и применять новые «разрешения доступа» для модели (разрешения по умолчанию применяются автоматически), разрешить упорядочение на основе другого поля или объявить, что класс является «абстрактным» (базовый класс, для которого вы не можете создавать записи, и вместо этого будет создан для создания других моделей). Многие другие параметры метаданных управляют тем, какая база данных должна использоваться для модели и как хранятся данные (это действительно полезно, если вам нужно сопоставить модель с существующей базой данных). Полный список опций метаданных доступен здесь: <a href="https://docs.djangoproject.com/en/2.2/ref/models/options/#model-meta-options">Model metadata options</a> (Django документация).</p> + +<h4 id="Методы">Методы</h4> + +<p>Модель также может иметь методы. Минимально в каждой модели вы должны определить стандартный метод класса для Python __str __ (), чтобы вернуть удобочитаемую строку для каждого объекта. Эта строка используется для представления отдельных записей на сайте администрирования (и в любом другом месте, где вам нужно обратиться к экземпляру модели). Часто это возвращает поле названия или имени из модели.</p> + +<pre class="brush: python notranslate">def __str__(self): + return self.field_name</pre> + +<p>Другим распространенным методом включения в модели Django является get_absolute_url (), который возвращает URL-адрес для отображения отдельных записей модели на веб-сайте (если вы определяете этот метод, тогда Django автоматически добавит кнопку «Просмотр на сайте» на экранах редактирования записей модели на сайте администратора). Типичный шаблон для get_absolute_url () показан ниже.</p> + +<pre class="brush: python notranslate">def get_absolute_url(self): + """ + Returns the url to access a particular instance of the model. + """ + return reverse('model-detail-view', args=[str(self.id)]) +</pre> + +<div class="note"> +<p>Примечание. Предполагется, что вы будете использовать URL-адреса, например / myapplication / mymodelname / 2, для отображения отдельных записей для вашей модели (где «2» - это идентификатор для определенной записи), вам нужно будет создать URL-карту, чтобы передать ответ и идентификатор «Образцовое представление модели» (которое будет выполнять работу, необходимую для отображения записи). Вышеуказанная функция reverse () может «перевернуть» ваш URL-адрес (в приведенном выше примере с именем «model-detail-view»), чтобы создать URL-адрес правильного формата.</p> + +<p>Конечно, для выполнения этой работы вам все равно придется писать сопоставление URL-адрес, просмотр и шаблон!</p> +</div> + +<p>Вы также можете определить любые другие методы, которые вам нравятся, и вызывать их из вашего кода или шаблонов (при условии, что они не принимают никаких параметров).</p> + +<h3 id="Управление_моделью">Управление моделью</h3> + +<p>После того, как вы определили свои классы моделей, вы можете использовать их для создания, обновления или удаления записей и для запуска запросов для получения всех записей или отдельных подмножеств записей. Мы покажем вам, как это сделать в учебнике, когда мы определяем наши представления, с кратким обзором.</p> + +<h4 id="Создание_и_изменение_записей">Создание и изменение записей</h4> + +<p>Чтобы создать запись, вы можете определить экземпляр модели, а затем вызвать метод save ().</p> + +<pre class="brush: python notranslate"># Create a new record using the model's constructor. +a_record = MyModelName(my_field_name="Instance #1") + +# Save the object into the database. +a_record.save() +</pre> + +<div class="note"> +<p>Примечание. Если вы не указали какое-либо поле в качестве primary_key, новая запись будет выдаваться автоматически, с идентификатором имени поля. Вы можете запросить это поле после сохранения указанной выше записи, и оно будет иметь значение 1.</p> +</div> + +<p>Вы можете получить доступ к полям в этой новой записи с использованием синтаксиса точек и изменить значения. Вы должны вызвать save (), чтобы сохранить измененные значения в базе данных.</p> + +<pre class="brush: python notranslate"># Access model field values using Python attributes. +print(a_record.id) #should return 1 for the first record. +print(a_record.my_field_name) # should print 'Instance #1' + +# Change record by modifying the fields, then calling save(). +a_record.my_field_name="New Instance Name" +a_record.save()</pre> + +<h4 id="Поиск_записей">Поиск записей</h4> + +<p>Вы можете искать записи, соответствующие определенным критериям, используя атрибут объектов модели (предоставляемый базовым классом).</p> + +<div class="note"> +<p>Примечание. Объяснение того, как искать записи, используя «абстрактную» модель и имена полей, может быть немного запутанным. В приведенном ниже обсуждении мы будем ссылаться на модель книги с полями названия и жанра, где жанр также является моделью с единственным именем в поле.</p> +</div> + +<p>Мы можем получить все записи для модели как объект QuerySet, используя <code>objects.all()</code>. QuerySet - это итерируемый объект, означающий, что он содержит несколько объектов, которые мы можем перебирать / прокручивать.</p> + +<pre class="brush: python notranslate">all_books = Book.objects.all() +</pre> + +<p>Метод <code>filter()</code> Django позволяет отфильтровать возвращаемый <code>QuerySet</code> для соответствия указанному текстовому или числовому полю по конкретным критериям. Например, чтобы отфильтровать книги, содержащие слово «wild» («дикие») в заголовке, а затем подсчитать их, мы могли бы сделать следующее.</p> + +<pre class="brush: python notranslate">wild_books = Book.objects.filter(title__contains='wild') +number_wild_books = Book.objects.filter(title__contains='wild').count() +</pre> + +<p>Соответствующие поля и тип соответствия определяются в имени параметра фильтра, используя формат: <code>field_name__match_type </code>(обратите внимание на двойное подчеркивание между заголовком выше). Выше мы фильтруем заголовок с учетом регистра. Есть много других типов совпадений, которые вы можете сделать: <code>icontains</code> (без учета регистра), <code>iexact </code>(точное совпадение без учета регистра), <code>exact </code>(точное совпадение с учетом регистра ) и <code>in</code>, <code>gt </code>(больше), <code>startswith</code> и т. д <a href="https://docs.djangoproject.com/en/2.2/ref/models/querysets/#field-lookups">смотреть полный список </a>(Django Docs, [EN]).</p> + +<p>В некоторых случаях вам нужно будет фильтровать поле, которое определяет отношение «один ко многим» к другой модели (например, <code>ForeignKey</code>). В этом случае вы можете «индексировать» поля в связанной модели с дополнительными двойными подчеркиваниями. Так, например, чтобы фильтровать книги с определенным жанровым рисунком, вам нужно будет указывать имя в поле жанра, как показано ниже:</p> + +<pre class="brush: python notranslate">books_containing_genre = Book.objects.filter(genre<strong>__</strong>name<strong>__</strong>icontains='fiction') # Will match on: Fiction, Science fiction, non-fiction etc. +</pre> + +<div class="note"> +<p><strong>Примечание:</strong> Вы можете использовать символы подчеркивания (__) для навигации по многим уровням отношений (ForeignKey / ManyToManyField) по своему усмотрению. Например, книга, имеющая разные типы, определяемая с использованием дополнительной связи «обложка», может иметь имя параметра: type__cover__name__exact = 'hard'.</p> +</div> + +<p>Существует гораздо больше возможностей для запросов, включая обратные поиски от связанных моделей, цепочки фильтров, возврат меньшего набора значений и т. д. Для получения дополнительной информации см. <a href="https://docs.djangoproject.com/en/2.2/topics/db/queries/">Making queries</a> (Django Docs, [EN]).</p> + +<h2 id="Определение_моделей_LocalLibrary">Определение моделей LocalLibrary</h2> + +<p>В этом разделе мы начнем определять модели для библиотеки. Откройте <em>models.py (в / locallibrary / catalog /)</em>. Шаблон в верхней части страницы импортирует модуль моделей, который содержит базовый класс модели <code>models.Model</code>, от которого наследуются наши модели.</p> + +<pre class="brush: python notranslate">from django.db import models + +# Create your models here.</pre> + +<h3 id="Модель_жанра">Модель жанра</h3> + +<p>Скопируйте приведенный ниже код модели <code>Genre </code>и вставьте его в нижнюю часть вашего файла <code>models.py</code>. Эта модель используется для хранения информации о категории книг - например, будь то художественная или документальная, роман или военно-историческая и т. д. Как уже упоминалось выше, мы создали жанр как модель, а не как свободный текст или список выбора, чтобы возможные значения могли управляться через базу данных, а не были закодированными.</p> + +<pre class="brush: python notranslate">class Genre(models.Model): + """ + Model representing a book genre (e.g. Science Fiction, Non Fiction). + """ + name = models.CharField(max_length=200, help_text="Enter a book genre (e.g. Science Fiction, French Poetry etc.)") + + def __str__(self): + """ + String for representing the Model object (in Admin site etc.) + """ + return self.name</pre> + +<p>Модель имеет один <code>CharField</code> field (имя), которое используется для описания жанра (оно ограничено 200 символами и имеет некоторый <code>help_text</code>. В конце модели мы объявляем метод <code>__str__()</code>, который просто возвращает имя жанра, определенного конкретной записью. Verbose name не был определен, поэтому поле будет называться <code>Name</code> в формах.</p> + +<h3 id="Модель_книги">Модель книги</h3> + +<p>Скопируйте модель книги ниже и снова вставьте ее в нижнюю часть файла. Модель книги представляет всю информацию о доступной книге в общем смысле, но не конкретный физический «экземпляр» или «копию» для временного использования. Модель использует CharField для представления названия книги и isbn (обратите внимание, как isbn указывает свой ярлык как «ISBN», используя первый неименованный параметр, поскольку в противном случае ярлык по умолчанию был бы «Isbn»). Модель использует TextField для summary, потому что этот текст, возможно, должен быть очень длинным.</p> + +<pre class="brush: python notranslate">from django.urls import reverse #Used to generate URLs by reversing the URL patterns + +class Book(models.Model): + """ + Model representing a book (but not a specific copy of a book). + """ + title = models.CharField(max_length=200) + author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True) + # Foreign Key used because book can only have one author, but authors can have multiple books + # Author as a string rather than object because it hasn't been declared yet in the file. + summary = models.TextField(max_length=1000, help_text="Enter a brief description of the book") + isbn = models.CharField('ISBN',max_length=13, help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn">ISBN number</a>') + genre = models.ManyToManyField(Genre, help_text="Select a genre for this book") + # ManyToManyField used because genre can contain many books. Books can cover many genres. + # Genre class has already been defined so we can specify the object above. + + def __str__(self): + """ + String for representing the Model object. + """ + return self.title + + + def get_absolute_url(self): + """ + Returns the url to access a particular book instance. + """ + return reverse('book-detail', args=[str(self.id)]) +</pre> + +<p>Жанр представляет из себя ManyToManyField, так что книга может иметь несколько жанров, а жанр может иметь много книг. Автор объявляется через ForeignKey, поэтому в каждой книге будет только один автор, но у автора может быть много книг (на практике книга может иметь несколько авторов, но не в такой реализации!)</p> + +<p>В обоих типах полей соответствующий класс модели объявляется как первый неименованный параметр, используя либо класс модели, либо строку, содержащую имя соответствующей модели. Вы должны использовать имя модели как строку, если связанный класс еще не был определен в этом файле до того, как он будет указан! Другими параметрами, представляющими интерес для поля автора, являются <code>null=True</code>, которое позволяет базе данных хранить значение <code>Null</code> , если автор не выбран, и on_delete = models. <code>SET_NULL </code>установит значение автора в Null, если связанная с автором запись будет удалена.</p> + +<p>Модель также определяет __str __ (), используя поле заголовка книги для представления книги. Окончательный метод get_absolute_url () возвращает URL-адрес, который можно использовать для доступа к подробной записи для этой модели (для этого нам нужно будет определить сопоставление URL-адресов, в котором содержится подробная информация о книге, и определить связанное представление и шаблон ).</p> + +<h3 id="Модель_BookInstance">Модель BookInstance</h3> + +<p>Затем скопируйте модель BookInstance (показано ниже) под другие модели. BookInstance представляет собой определенную копию книги, которую кто-то может брать взаймы, и включает информацию о том, доступна ли копия или в какой день она ожидается, «отпечаток» или сведения о версии, а также уникальный идентификатор книги в библиотеке. Теперь некоторые из полей и методов будут знакомы. Модель использует</p> + +<ul> + <li>ForeignKey для идентификации связанной книги (в каждой книге может быть много копий, но в копии может быть только одна книга).</li> + <li>CharField, для представления данных (конкретного выпуска) о книге.</li> +</ul> + +<pre class="brush: python notranslate">import uuid # Required for unique book instances + +class BookInstance(models.Model): + """ + Model representing a specific copy of a book (i.e. that can be borrowed from the library). + """ + id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text="Unique ID for this particular book across whole library") + book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True) + imprint = models.CharField(max_length=200) + due_back = models.DateField(null=True, blank=True) + + LOAN_STATUS = ( + ('m', 'Maintenance'), + ('o', 'On loan'), + ('a', 'Available'), + ('r', 'Reserved'), + ) + + status = models.CharField(max_length=1, choices=LOAN_STATUS, blank=True, default='m', help_text='Book availability') + + class Meta: + ordering = ["due_back"] + + + def __str__(self): + """ + String for representing the Model object + """ + return '%s (%s)' % (self.id,self.book.title)</pre> + +<p>Мы дополнительно объявляем несколько новых типов полей:</p> + +<ul> + <li><code>UUIDField</code> используется для поля id, чтобы установить его как primary_key для этой модели. Этот тип поля выделяет глобальное уникальное значение для каждого экземпляра (по одному для каждой книги, которую вы можете найти в библиотеке).</li> + <li><code>DateField</code> используется для данных due_back (при которых ожидается, что книга появится после заимствования или обслуживания). Это значение может быть blank или null (необходимо, когда книга доступна). Метаданные модели (Class Meta) используют это поле для упорядочивания записей, когда они возвращаются в запросе.</li> + <li>status - это CharField, который определяет список choice/selection. Как вы можете видеть, мы определяем кортеж, содержащий кортежи пар ключ-значение и передаем его аргументу выбора. Значение в key/value паре - это отображаемое значение, которое пользователь может выбрать, а ключи - это значения, которые фактически сохраняются, если выбрана опция. Мы также установили значение по умолчанию «m» (техническое обслуживание), поскольку книги изначально будут созданы недоступными до того, как они будут храниться на полках.</li> +</ul> + +<p>Модель __str __ () представляет объект BookInstance, используя комбинацию его уникального идентификатора и связанного с ним заголовка книги.</p> + +<div class="note"> +<p>Примечание. Немного Python'а:</p> + +<ul> + <li>Значение, возвращаемое __str __ (), является форматированной строкой. В строке мы используем % S для объявления 'placeholders'. После строки укажем %, а затем кортеж, содержащий значения, которые будут вставлены в заполнители. Если у вас просто один заполнитель, вы можете опустить кортеж - например, 'Мое значение:% S' % переменная.<br> + <br> + Обратите также внимание на то, что, хотя этот подход совершенно применим, но он более не является предпочтительным. Начиная с Python 3, вы должны использовать метод format, например. '{0} ({1})'.format (self.id, self.book.title). Вы можете узнать больше об этом <a href="https://www.python.org/dev/peps/pep-3101/">здесь</a>.</li> +</ul> +</div> + +<h3 id="Модель_автора">Модель автора</h3> + +<p>Скопируйте модель автора (показано ниже) под существующим кодом в models.py.</p> + +<p>Теперь все поля/методы должны быть знакомы. Модель определяет автора как имя, фамилию, дату рождения и (необязательную) дату смерти. Он указывает, что по умолчанию __str __ () возвращает имя в фамилии, порядковый номер первого имени. Метод get_absolute_url () отменяет сопоставление URL-адреса автора с целью получения URL-адреса для отображения отдельного автора.</p> + +<pre class="brush: python notranslate">class Author(models.Model): + """ + Model representing an author. + """ + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + """ + Returns the url to access a particular author instance. + """ + return reverse('author-detail', args=[str(self.id)]) + + + def __str__(self): + """ + String for representing the Model object. + """ + return '%s, %s' % (self.last_name, self.first_name) +</pre> + +<h2 id="Повторно_выполнить_миграцию_базы_данных">Повторно выполнить миграцию базы данных</h2> + +<p>Теперь все ваши модели созданы. Теперь переустановите миграцию базы данных, чтобы добавить их в свою базу данных.</p> + +<pre class="notranslate"><code>python3 manage.py makemigrations +python3 manage.py migrate</code></pre> + +<h2 id="Языковая_модель_-_вызов">Языковая модель - вызов</h2> + +<p>Представьте себе, что местный благотворитель жертвует ряд новых книг, написанных на другом языке (скажем, фарси). Задача состоит в том, чтобы определить, как они будут лучше всего представлены на нашем веб-сайте библиотеки, а затем добавить их в модели.</p> + +<p>Некоторые вещи, которые следует учитывать:</p> + +<ul> + <li>Должен ли «язык» ассоциироваться с Book, BookInstance или каким-либо другим объектом?</li> + <li>Должны ли быть представлены разные языки с использованием модели, свободного текстового поля или жестко запрограммированного списка выбора?</li> +</ul> + +<p>После того, как вы решили, добавьте поле. Вы можете увидеть наше решение на Github <a href="https://github.com/mdn/django-locallibrary-tutorial/blob/master/catalog/models.py">here</a>.</p> + +<ul> +</ul> + +<ul> +</ul> + +<h2 id="Резюме">Резюме</h2> + +<p>В этой статье мы узнали, как определять модели, а затем использовать эту информацию в разработке и внедрении соответствующих моделей для сайта LocalLibrary.</p> + +<p>На этом этапе мы отвлечемся от создания сайта и проверим <em>Django Administration site</em>. Этот сайт позволит нам добавить некоторые данные в библиотеку, которые мы можем отобразить с помощью наших (еще не созданных) представлений и шаблонов.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/intro/tutorial02/">Writing your first Django app, part 2</a> (Django Docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/db/queries/">Making queries</a> (Django Docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/ref/models/querysets/">QuerySet API Reference</a> (Django Docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/django/skeleton_website/index.html b/files/ru/learn/server-side/django/skeleton_website/index.html new file mode 100644 index 0000000000..48dda2c3b8 --- /dev/null +++ b/files/ru/learn/server-side/django/skeleton_website/index.html @@ -0,0 +1,357 @@ +--- +title: 'Руководство по Django часть 2: создание скелета' +slug: Learn/Server-side/Django/skeleton_website +tags: + - django + - Введение + - Для новичков + - Программирование + - Руководство + - Статья +translation_of: Learn/Server-side/Django/skeleton_website +--- +<div>{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}</div> + +<p class="summary">Это вторая статья из нашего <a href="/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">руководства по Django</a>, которая показывает, как можно создать "скелет" сайта, как фундамент, на котором можно строить всё остальное: настройки, ссылки, модели, контроллеры и представления.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимо:</th> + <td> + <p><a href="/ru/docs/Learn/Server-side/Django/development_environment">Настройка окружения</a>. Прочитать первую статью <a href="/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">руководства по Django</a>.</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Научиться использовать инструменты Django для создания новых веб-сайтов.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>Эта статья показывает, как можно создать "скелет"(прототип) сайта, который затем можно расширить при помощи различных настроек, url адресов, моделей, представлений, и шаблонов (эти темы будут объясняться в последующих статьях).</p> + +<p>Алгоритм следующий:</p> + +<ol> + <li><span style="line-height: 1.5;">Использовать </span><code style="font-style: normal; font-weight: normal; line-height: 1.5;">django-admin</code><span style="line-height: 1.5;"> для создания папки проекта, шаблонов остальных файлов, и скрипта для управления проектом (</span><strong style="line-height: 1.5;">manage.py</strong><span style="line-height: 1.5;">).</span></li> + <li><span style="line-height: 1.5;">Использовать </span><strong style="line-height: 1.5;">manage.py</strong><span style="line-height: 1.5;"><em> </em>для создания одного или нескольких <em>приложений</em></span><span style="line-height: 1.5;">.</span> + <div class="note"> + <p><strong>Заметка: </strong>Сайт может состоять из одной или нескольких различных частей, например: основная часть, блог, вики, раздел загрузок, и так далее. Философия Django подталкивает разработчиков создавать эти части, как разные <strong>приложения</strong>, которые, если понадобится, могут быть использованы повторно в других проектах. </p> + </div> + </li> + <li><span style="line-height: 1.5;">Зарегистрировать в настройках эти приложения, чтобы использовать их в проекте. </span></li> + <li><span style="line-height: 1.5;">Настроить маршруты url адресов для каждого из приложений.</span></li> +</ol> + +<p>Для <a href="/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">Сайта местной библиотеки</a> папка сайта и проекта будет называться <em>locallibrary</em>, и у нас будет одно приложение с названием <em>catalog</em>. Верхняя структура проекта будет следующей:</p> + +<pre class="brush: bash"><em>locallibrary/ # Папка сайта</em> + <strong>manage.py </strong># Скрипт для управления проектов (создан manage.py) + <em>locallibrary/ # Папка сайта/проекта </em>(создана manage.py) + <em>catalog/ # Папка приложения </em>(также создана manage.py) +</pre> + +<p><span style="line-height: 1.5;">Следующие разделы статьи разложат по полочкам этапы создания "скелета", и покажут вам, как можно проверить сделанные изменения. В конце статьи мы обсудим некоторые другие настройки сайта, которые можно назначить на этом этапе.</span></p> + +<h2 id="Создание_проекта">Создание проекта</h2> + +<p>Для начала откройте командную строку/терминал, перейдите в ту папку, куда вы хотите поместить проект<span style="line-height: 1.5;"> Django(лучше в папке профиля пользователя C:\Users\user_name, при запуске командной строки используется именно эта директория), и создайте папку для вашего нового сайта (в данном случае: </span><em>locallibrary</em>). Затем войдите в эту папку, используя команду cd:</p> + +<pre class="brush: bash">mkdir locallibrary +cd locallibrary</pre> + +<p>Создайте новую папку, используя команду <code>django-admin startproject</code> как в примере ниже, и затем зайдите в созданную папку.</p> + +<pre class="brush: bash"> django-admin startproject locallibrary . +cd locallibrary</pre> + +<p>Команда <code>django-admin</code> создаст файловую структуру, как в примере ниже:</p> + +<pre class="brush: bash"><em>locallibrary/</em> + <strong>manage.py</strong> + <em>locallibrary/</em> + settings.py + urls.py + wsgi.py</pre> + +<p>Подпапка проекта <em>locallibrary</em> это ключевая директория нашего проекта: </p> + +<ul> + <li><strong>settings.py</strong> содержит в себе все настройки проекта. Здесь мы регистрируем приложения, задаём размещение <em>статичных</em> файлов, настройки базы данных и так далее. </li> + <li><strong>urls.py</strong> задаёт ассоциации url адресов с представлениями. Несмотря на то, что этот файл может содержать <em>все</em> настройки url<span style="line-height: 1.5;">, обычно его делят на части, по одной на приложение, как будет показано далее. </span></li> + <li><strong style="line-height: 1.5;">wsgi.py</strong><span style="line-height: 1.5;"> используется для налаживания связи между вашим Django приложением и веб-сервером. Вы можете воспринимать его, как утилиту.</span></li> +</ul> + +<p>Скрипт <strong>manage.py</strong> используется для создания приложений, работы с базами данных и для запуска отладочного сервера. </p> + +<h2 id="Создание_приложения_Каталог">Создание приложения Каталог</h2> + +<p>Выполнив предыдущие шаги, запустите следующую команду для создания приложения <em>catalog</em>, который будет размещён внутри папки locallibrary (команду необходимо выполнять из папки, в которой находится <strong>manage.py</strong>):</p> + +<pre class="brush: bash">python3 manage.py startapp catalog</pre> + +<div class="note"> +<p><strong>Заметка</strong>: приведённая выше команда справедлива для GNU Linux/Mac OS. На Windows команда должна иметь вид: <code>py -3 manage.py startapp catalog</code></p> + +<p>Если вы работаете под Windows, заменяйте команду <code>python3</code> на <code>py -3</code> в этой и следующих статьях.</p> +</div> + +<p>Эта команда создаст новую папку и наполнит её файлами различных частей приложения (выделенные <strong>полужирным </strong>ниже). Большинство файлов названы, исходя из их назначения (например контроллеры(views) должны находится во <strong>views.py</strong>, модели в <strong>models.py</strong>, тесты в <strong>tests.py</strong>, настройки административной части в <strong>admin.py</strong>, регистрация приложения в <strong>apps.py</strong>) и уже содержат некоторый шаблонный код для работы с вышеназванными объектами.</p> + +<p>Обновлённая директория должна выглядеть следующим образом:</p> + +<pre class="brush: bash"><em>locallibrary/</em> + manage.py + <em>locallibrary/ +</em><strong> <em>catalog/</em> + admin.py + apps.py + models.py + tests.py + views.py + __init__.py + <em>migrations/</em></strong> +</pre> + +<p>Кроме перечисленных выше файлов были созданы:</p> + +<ul> + <li>Папка <em>migrations</em> используется, чтобы хранить"миграции" — файлы, которые позволяют вам автоматически обновлять базу данных по мере изменения моделей. </li> + <li><strong>__init__.py</strong> — пустой файл для того, чтобы Django и Python распознавали папку как <a href="https://docs.python.org/3/tutorial/modules.html#packages">Python модуль </a>и позволяет нам использовать его объекты внутри других частей проекта.</li> +</ul> + +<div class="note"> +<p><strong>Заметка</strong>: Заметили, что некоторых файлов не хватает? В то время, как там нашли себе место файлы для контроллеров(views) и моделей(models), файлов для настройки url соотносителя, шаблонов, и статичных файлов создано не было. Далее мы покажем, как их создать (они не обязательны для каждого сайта, но нужны в данном примере).</p> +</div> + +<h2 id="Регистрация_папки_с_приложением">Регистрация папки с приложением</h2> + +<p>После создания приложения, нам нужно зарегистрировать его в проекте, чтобы различные утилиты затрагивали его своим действием (например при добавлении моделей в базу данных). Приложения регистрируются добавлением их названий в список <code>INSTALLED_APPS</code> в настройках проекта(который, как мы помним, называется <strong>settings.py</strong>). </p> + +<p>Откройте файл <strong>locallibrary/locallibrary/settings.py</strong> и найдите в нём список <code>INSTALLED_APPS</code> . Затем добавьте новую строку в конец списка, как показано <strong>полужирным </strong>ниже.</p> + +<pre class="brush: bash">INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +<strong> 'catalog.apps.CatalogConfig', </strong> +]</pre> + +<p>Новая строка указывает на файл конфигурации приложения (<code>CatalogConfig</code>), который был создан в <strong>/locallibrary/catalog/apps.py</strong> , когда вы создали приложение.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Легко заметить, что в <code>INSTALLED_APPS</code> уже подключено большое количество приложений (и объектов <code>MIDDLEWARE</code>, ниже в файле конфигурации). Они добавляют поддержку <a href="/ru/docs/Learn/Server-side/Django/Admin_site">админ-панели Django</a> и, как следствие, огромное количество функционала (включая сессии, аутентификацию и прочее).</p> +</div> + +<h2 id="Настройка_базы_данных">Настройка базы данных</h2> + +<p>На этом шаге обычно указывают базу данных для будущего проекта — имеет смысл использовать для разработки и размещённого в Сети одну и ту же базу данных, по возможности, чтобы исключить различия в поведении. Про различные варианты вы можете прочитать в документации Django в разделе <a href="https://docs.djangoproject.com/en/1.10/ref/settings/#databases">Базы данных</a>. </p> + +<p>Мы будем использовать базу данных SQLite для этого проекта, потому что не предпологаем большое количество одновременных запросов на неё, а ещё потому, что для её настройки совсем не надо ничего делать! Вы можете видеть, что база данных уже настроена в <strong>settings.py</strong> (подробная информация указана ниже):</p> + +<pre class="brush: python">DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} +</pre> + +<p>Так как мы используем SQLite, то нам не нужно ничего делать.</p> + +<p>Давайте продолжим!</p> + +<h2 id="Другие_настройки_проекта">Другие настройки проекта</h2> + +<p>Файл <strong>settings.py</strong> так же применяется и для некоторых других настроек, но на данном шаге имеет смысл поменять разве что <a href="https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-TIME_ZONE">TIME_ZONE</a> — это значение должно быть представлено строкой, указанной в <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">списке часовых поясов tz </a>(колонка TZ в таблице, в строке временной зоны, которая вам нужна). Измените <code>TIME_ZONE</code> на одну из строк из таблицы, которая отвечает вашему часовому поясу. Например:</p> + +<pre class="brush: python">TIME_ZONE = 'Europe/Moscow'</pre> + +<p>В файле присутствует две настройки, которые не нужно менять сейчас, но о назначении которых следует знать:</p> + +<ul> + <li><code>SECRET_KEY</code>. Это секретный ключ, который используется Django для поддержки безопасности сайта. Если вы раскроете этот ключ в процессе разработки кому-либо, то необходимо будет его сменить (возможно считать его с какого-либо файла на сервере или переменной окружения) когда будете размещать проект на сервер. </li> + <li><code>DEBUG</code>. Включает подробные сообщения об ошибках, вместо стандартных HTTP статусов ответов. Должно быть изменено на <code>False</code> на сервере, так как эта информация очень много расскажет взломщикам. </li> +</ul> + +<h2 id="Подключение_URL-адреса">Подключение URL-адреса</h2> + +<p>При создании сайта, был создан файл сопоставления URL (<strong>urls.py</strong>) в корне проекта. Хотя можно использовать его для обработки всех URL адресов, более целесообразно подключать отдельные файлы сопоставлений для каждого приложения.</p> + +<p>Откройте <strong>locallibrary/locallibrary/urls.py</strong> и обратите внимание на закомментированный текст, который объясняет суть происходящего. </p> + +<pre class="brush: python">""" +locallibrary URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.10/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.conf.urls import url, include + 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) +""" +<code>from django.urls import path</code> +from django.contrib import admin + + +urlpatterns = [ + <code>path('admin/', admin.site.urls),</code> +] +</pre> + +<p>URL соотношения хранятся в переменной <code>urlpatterns</code>, которая является списком функций <code>path()</code>. Каждая <code>path()</code> функция или ассоциирует шаблон URL<em> </em>с контроллером(views) или же его с другим таким списком (во втором случае, первый URL становится "базовым" для других, которые определяются в дочернем списке). Список <code>urlpatterns</code> инициализирует список функции, которая, например, соотносит <em>admin/</em> с модулем <code>admin.site.urls</code> , который содержит собственный файл-соотноситель.</p> + +<p>Добавьте строчки, приведённые ниже в низ файла <strong>urls.py</strong> , чтобы добавить новый элемент в список <code>urlpatterns</code>. Этот элемент содержит <code>url()</code> который направляет запросы с URL <code>catalog/</code> к модулю <code>catalog.urls</code> (файл с относительным путём <strong>/catalog/urls.py</strong>).</p> + +<pre class="brush: python"># Используйте include() чтобы добавлять URL из каталога приложения +<code>from django.urls import include +from django.urls import path</code> +urlpatterns += [ + <code> path('catalog/', include('catalog.urls')),</code> +] +</pre> + +<p>Теперь давайте перенаправим корневой URL нашего сайта (например <code>127.0.0.1:8000</code>) на URL <code>127.0.0.1:8000/catalog/</code>; это единственное приложение, которое мы собираемся использовать, поэтому это вполне разумно. Чтобы это использовать, нам понадобится специальная функция (<code>RedirectView</code>), которая принимает первым параметром новый относительный URL на который следует перенаправлять (<code>/catalog/</code>) когда указанный в функции <code>url()</code> адрес соотносится с адресом запроса (корневой URL, в данном случае).</p> + +<p>Добавьте следующие строчки, тоже в конец файла:</p> + +<pre class="brush: python"># Добавьте URL соотношения, чтобы перенаправить запросы с корневового URL, на URL приложения +from django.views.generic import RedirectView +urlpatterns += [ + <code>path('', RedirectView.as_view(url='/catalog/', permanent=True)),</code> +]</pre> + +<p>Django не размещает <em>статические</em> файлы(CSS, JavaScript, и изображения) по умолчанию, но это было бы крайне полезно на этапе разработки нашего сайта. В самом конце нашего URL соотносителя, можно включить размещение статических файлов. </p> + +<p>Добавьте последнюю часть в конец файла:</p> + +<pre><code># Используйте static() чтобы добавить соотношения для статических файлов +# Только на период разработки +from django.conf import settings +from django.conf.urls.static import static + +urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)</code> +</pre> + +<div class="note"> +<p><strong>Заметка</strong>: Существуют различные способы дополнения списка <code>urlpatterns</code> (в примере мы просто добавляли объект, испольщуя оператор <code>+=</code> чтобы чётко разделить изначальный и дописанный код). Вместо этого, мы могли бы добавить соотношения внутрь определения переменной:</p> + +<pre>urlpatterns = [ path('admin/', admin.site.urls), +path('catalog/', include('catalog.urls')),path('', +RedirectView.as_view(url='/catalog/', permanent=True)), ] + +<code>static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)</code></pre> + +<p>Кроме того, мы добавили import вниз файла (<code>from django.urls import include</code>) ,чтобы видеть, что мы добавили, но обычно все import'ы добавляются в верхнюю часть файла.</p> +</div> + +<p>Напоследок, создайте файл <strong>urls.py</strong> внутри папки <strong>catalog</strong>, и добавьте следующий код, чтобы определить (пустой) <code>urlpatterns</code>. Сюда мы будем добавлять наши URL соотношения, по мере разработки сайта. </p> + +<pre class="brush: python">from django.urls import path +from . import views + + +urlpatterns = [ + +] +</pre> + +<h2 id="Тестирование_работы_скелета">Тестирование работы скелета</h2> + +<p>На этом, мы создали прототип сайта. Пока сайт ничего не умеет делать, но стоит запустить его, чтобы убедиться, что мы ничего не сломали. </p> + +<p>До этого, нам предстоит впервые запустить <em> миграцию базы данных</em>. Это обновит нашу базу данных и добавит туда необходимые модели (и уберёт некоторые предупреждения, которые были бы показаны при попытке запуска).</p> + +<h3 id="Запуск_миграций_базы_данных">Запуск миграций базы данных</h3> + +<p>Django использует Объектный Соотноситель Связей (ORM) чтобы соотносить определения моделей в Django приложении со структурами данных, которые используются базой данных. Когда мы меняем наши модели, Django отслеживает изменения и может создать файлы миграций (в папке <strong>/locallibrary/catalog/migrations/</strong>) чтобы применить соответствующие структуры данных к базе, чтобы та соответствовала модели.</p> + +<p>При создании сайта, Django автоматически добавил несколько моделей, чтобы мы могли их использовать в админ-панели (о которой мы поговорим позже). Выполните следующие команды, чтобы создать нужные таблицы в базе данных, соответствующие этим моделям (убедитесь, что вы находитесь в папке с<strong> manage.py</strong>):</p> + +<pre class="brush: bash">python3 manage.py makemigrations +python3 manage.py migrate +</pre> + +<div class="warning"> +<p><strong>Предупреждение</strong>: Необходимо выполнять команды выше каждый раз, когда вы меняете модели таким образом, что структура таблицы изменится(включая добавления и удаления как отдельных полей, так и целых моделей).</p> +</div> + +<p><code>Команда makemigrations</code> <em>создаёт</em> (но не применяет) миграции для всех приложений, которые установлены в ваш проект (вы так же можете указать в конце имя конкретного приложения, чтобы создать миграции только для него). Это даёт вам возможность проверить код перед тем, как их применить — когда вы станете хорошо разбираться в Django, то сможете даже менять их!</p> + +<p>Команда <code>migrate</code> применяет созданные миграции к базе (Django отслеживает, какие миграции были созданы для данной базы).</p> + +<div class="note"> +<p><strong>Заметка</strong>: Посмотрите раздел <a href="https://docs.djangoproject.com/en/2.2/topics/migrations/">Миграции</a> в документации Django чтобы получить информацию о менее распространённых командах для управления миграциями.</p> +</div> + +<h3 id="Запуск_сайта">Запуск сайта</h3> + +<p>Во время разработки, вы можете проверить свой сайт, разместив его на <em>встроенном отладочном сервере</em>, и просмотрев его в своём браузере. </p> + +<div class="note"> +<p><strong>Заметка</strong>: Отладочный веб-сервер не настолько функционален и производителен, для постоянного размещения , но это самый простой способ запустить свой сайт на Django и проверить его на наличие ошибок. По умолчанию, он разместит сайт на вашем компьютере (<code>http://127.0.0.1:8000/)</code>, но вы так же можете указать различные компьютеры в вашей сети для этой цели. Для получения большего количества информации загляните в раздел <a href="https://docs.djangoproject.com/en/2.2/ref/django-admin/">django-admin и manage.py: отладочный сервер</a> документации Django.</p> +</div> + +<p>Запустите веб-сервер, используя команду <em>runserver</em> (в той же папке, что и <strong>manage.py</strong>):</p> + +<pre class="brush: bash">python3 manage.py runserver + + Performing system checks... + + System check identified no issues (0 silenced). + September 22, 2016 - 16:11:26 + Django version 1.10, using settings 'locallibrary.settings' + Starting development server at http://127.0.0.1:8000/ + Quit the server with CTRL-BREAK. +</pre> + +<p>Когда сервер запустится, вы сможете посетить сайт по адресу <code>http://127.0.0.1:8000/</code> в вашем веб-браузере. Вы должны увидеть страницу с ошибкой, навроде этой:</p> + +<p><img alt="Django debug page for a 404 not found error" src="https://mdn.mozillademos.org/files/14009/django_404_debug_page.png" style="display: block; height: 545px; margin: 0px auto; width: 871px;"></p> + +<p>Не волнуйтесь! Эта страница должна появиться и сообщить нам, что мы ещё не настроили ни одной страницы в модуле <code>catalogs.urls</code> (на который мы были перенаправлены запросили корневой URL сайта). </p> + +<div class="note"> +<p><strong>Заметка</strong>: Показанная выше страница открывает нам одно из замечательных свойств Django — автоматические отчёты об ошибках. На экране с ошибкой отображается множество полезной информации, когда страница не найдена, или ошибка была вызвана кодом. В данном случае, мы видим, что запрошенный URL не соответствует ни одному шаблону (из указанных). Подобные отчёты будут выключены при DEBUG=False (когда мы разместим приложение в Сеть), в этом случае будет показана менее информативная, но более дружелюбная к пользователю страница(которую вам надо будет создать - прим. переводчика).</p> +</div> + +<p>На данном этапе, мы поняли, что Django работает должным образом! </p> + +<div class="note"> +<p><strong>Заметка</strong>: Вам следует перезапускать миграцию и заново тестировать сайт, после того как вы делаете важные изменения. Поверьте, это не займёт много времени!</p> +</div> + +<h2 id="Домашнее_задание">Домашнее задание</h2> + +<p>Папка <strong>catalog/</strong> содержит файлы контроллеров(views), моделей(models), и других частей приложения. Просмотрите эти файлы. </p> + +<p>Как было написано выше, URL соотноситель для админ-панели был подключен в файле <strong>urls.py</strong>. Войдите в административную часть и посмотрите, что произойдёт (вы можете найти URL из соотношения выше).</p> + +<ul> +</ul> + +<h2 id="Подводя_итоги">Подводя итоги</h2> + +<p>Теперь вы создали полноценный скелет веб-приложения, который теперь вы можете расширить url соотносителями, контроллерами(views) и моделями(models).</p> + +<p>Теперь скелет <a href="/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">Сайта местной библиотеки</a> сделан и запущен, теперь самое время начать писать код, который научит сайт делать то, что он должен делать. </p> + +<h2 id="Также_посмотрите_эти_статьи">Также посмотрите эти статьи</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.2/intro/tutorial01/">Пишем своё первое приложение на Django - часть 1</a> (документация Django)</li> + <li><a href="https://docs.djangoproject.com/en/2.2/ref/applications/">Приложения</a> (документация Django). содержит информацию о настройке приложений.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/django/testing/index.html b/files/ru/learn/server-side/django/testing/index.html new file mode 100644 index 0000000000..699f9f0d23 --- /dev/null +++ b/files/ru/learn/server-side/django/testing/index.html @@ -0,0 +1,892 @@ +--- +title: 'Руководство часть 10: Тестирование приложений Django' +slug: Learn/Server-side/Django/Testing +tags: + - TDD + - django + - Для начинающих + - Разработка через тесты + - Руководство + - Сервер + - Тестирование в django + - сторона сервера + - тестирование + - юнит-тесты +translation_of: Learn/Server-side/Django/Testing +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}</div> + +<p class="summary">Сайты, в процессе развития и разработки, становится все сложнее тестировать вручную. Кроме такого тестирования, сложными становятся внутренние взаимодействия между компонентами - внесение небольшого изменения в одной части приложения влияет на другие. При этом, чтобы все продолжало работать нужно вносить все больше и больше изменений и, желательно так, чтобы не добавлялись новые ошибки. Одним из способов который позволяет смягчить последствия добавления изменений, является внедрение в разработку автоматического тестирования - оно должно просто и надежно запускаться каждый раз, когда вы вносите изменения в свой код. Данное руководство рассматривает вопросы автоматизации<em> юнит-тестирования</em> вашего сайта при помощи фреймворка Django для тестов.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Изучить все предыдущие темы руководства, включая <a href="/en-US/docs/Learn/Server-side/Django/Forms">Руководство Django Часть 9: Работа с формами</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понимать как создавать юнит тесты для сайта на основе Django.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> в настоящий момент содержит страницы для показа списков всех книг, авторов, подробной информации о книгах <code>Book</code> и авторах <code>Author</code>, а также страницу для обновления информации об экземпляре книги <code>BookInstance</code> и, кроме того, страницы для создания, обновления и удаления записей модели <code>Author</code> (и модели <code>Book</code>, в том случае, если вы выполнили домашнее задание в руководстве <a href="/en-US/docs/Learn/Server-side/Django/Forms">работа с формами</a>). Даже в случае небольшого сайта, ручной переход на каждую страницу и <em>беглая</em> проверка того, что все работает как следует, может занять несколько минут. В процессе внесения изменений и роста сайта требуемое время для проведения проверок будет только возрастать. Если бы мы продолжили в том же духе, то в какой-то момент на проведение тестов мы тратили бы больше времени, чем на написание кода и внесение изменений.</p> + +<p>Автоматические тесты могут серьезно помочь нам справиться с этой проблемой! Очевидными преимуществами в таком случае являются значительно меньшие временные затраты на проведение тестов, их подробное выполнение, а кроме того, тесты имеют постоянную функциональность, или последовательность действий (человек никогда не сможет тестировать так надежно!). В связи с быстротой их выполнения автоматические тесты можно выполнять более часто, а если они провалятся, то укажут на соответствующее место (где что-то пошло не так как ожидалось).</p> + +<p>Кроме того, автоматические тесты могут действовать как первый "настоящий пользователь" вашего кода, заставляя вас строго следить за объявлениями и документированием поведения вашего сайта. Тесты часто являются основой для создания примеров вашего кода и документации. По этим причинам иногда некоторые процессы разработки программного обеспечения начинаются с определения тестов и их реализации, а уже после этого следует написание кода который должен иметь соответствующее поведение (так называемая разработка <a href="https://en.wikipedia.org/wiki/Test-driven_development">на основе тестов</a> и <a href="https://en.wikipedia.org/wiki/Behavior-driven_development">на основе поведения</a>).</p> + +<p>Данное руководство показывает процесс создания автоматических тестов в Django при помощи добавления их к разработке сайта <em>LocalLibrary</em>.</p> + +<h3 id="Типы_тестирования">Типы тестирования</h3> + +<p>Существует несколько типов, уровней, классификаций тестов и тестовых приемов. Наиболее важными автоматическими тестами являются:</p> + +<dl> + <dt>Юнит-тесты</dt> + <dd>Проверяют функциональное поведение для отдельных компонентов, часто классов и функций.</dd> + <dt><strong>Регрессионное тестирование</strong></dt> + <dd>Тесты которые воспроизводят исторические ошибки (баги). Каждый тест вначале запускается для проверки того, что баг был исправлен, а затем перезапускается для того, чтобы убедиться, что он не был внесен снова с появлением новых изменений в коде.</dd> + <dt>Интеграционные тесты</dt> + <dd>Проверка совместной работы групп компонентов. Данные тесты отвечают за совместную работу между компонентами, не обращяя внимания на внутренние процессы в компонентах. Они проводятся как для простых групп компонентов, так и для целых веб-сайтов.</dd> +</dl> + +<div class="note"> +<p><strong>Примечание: </strong>К другим типам тестов относятся методы чёрного ящика, белого ящика, ручные, автоматические, канареечные (canary), дымные (smoke), соответствия (conformance), принятия (acceptance), функциональные (functional), системные (system), эффективности (performance), загрузочные (load) и стресс-тесты (stress tests).</p> +</div> + +<h3 id="Что_Django_предоставляет_для_тестирования">Что Django предоставляет для тестирования?</h3> + +<p>Тестирование сайта это сложная задача, потому что она состоит их нескольких логических слоев – от HTTP-запроса и запроса к моделям, до валидации формы и их обработки, а кроме того, рендеринга шаблонов страниц.</p> + +<p>Django предоставляет фреймворк для создания тестов, построенного на основе иерархии классов, которые, в свою очередь, зависят от стандартной библиотеки Python <code><a href="https://docs.python.org/3/library/unittest.html#module-unittest" title="(in Python v3.5)">unittest</a></code>. Несмотря на название, данный фреймворк подходит и для юнит-, и для интеграционного тестирования. Фреймворк Django добавляет методы API и инструменты, которые помогают тестировать как веб так и, специфическое для Django, поведение. Это позволяет вам имитировать URL-запросы, добавление тестовых данных, а также проводить проверку выходных данных ваших приложений. Кроме того, Django предоставляет API (<a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#liveservertestcase">LiveServerTestCase</a>) и инструменты <a href="https://docs.djangoproject.com/en/1.10/topics/testing/advanced/#other-testing-frameworks">для применения различных фреймфорков тестирования</a>, например вы можете подключить популярный фреймворк <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Selenium</a> для имитации поведения пользователя в реальном браузере.</p> + +<p>Для написания теста вы должны наследоваться от любого из классов тестирования Django (или <em>юниттеста</em>) (<a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#simpletestcase">SimpleTestCase</a>, <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#transactiontestcase">TransactionTestCase</a>, <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#testcase">TestCase</a>, <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#liveservertestcase">LiveServerTestCase</a>), а затем реализовать отдельные методы проверки кода (тесты это функции-"утверждения", которые проверяют, что результатом выражения являются значения <code>True</code> или <code>False</code>, или что два значения равны и так далее). Когда вы запускаете тест, фреймворк выполняет соответствующие тестовые методы в вашем классе-наследнике. Методы тестирования запускаются независимо друг от друга, начиная с метода настроек и/или завершаясь методом разрушения (tear-down), определенном в классе, как показано ниже.</p> + +<pre class="brush: python">class YourTestClass(TestCase): + + def setUp(self): + # Установки запускаются перед каждым тестом + pass + + def tearDown(self): + # Очистка после каждого метода + pass + + def test_something_that_will_pass(self): + self.assertFalse(False) + + def test_something_that_will_fail(self): + self.assertTrue(False) +</pre> + +<p>Самый подходящий базовый класс для большинства тестов это <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#testcase">django.test.TestCase</a>. Этот класс создает чистую базу данных перед запуском своих методов, а также запускает каждую функцию тестирования в его собственной транзакции. У данного класса также имеется тестовый <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.Client" title="django.test.Client">Клиент</a>, который вы можете использовать для имитации взаимодействия пользователя с кодом на уровне отображения. В следующих разделах мы сконцентритуемся на юнит-тестах, которые будут созданы на основе класса <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#testcase">TestCase</a>.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Класс <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#testcase">django.test.TestCase</a> очень удобен, но он может приводить к замедленной работе в некоторых случаях (не для каждого теста необходимо настраивать базу данных, или имитировать взаимодействие с отображеним). Когда вы познакомитесь с работой данного класса, то сможете заменить некоторые из ваших тестов на более простые классы тестирования.</p> +</div> + +<h3 id="Что_вы_должны_тестировать">Что вы должны тестировать?</h3> + +<p>Вы должны тестировать все аспекты, касающиеся вашего кода, но не библиотеки, или функциональность, предоставляемые Python, или Django.</p> + +<p>Например, рассмотрим модель <code>Author</code>, определенную ниже. Вам не нужно проверять тот факт, что <code>first_name</code> и <code>last_name</code> были сохранены в базу данных как <code>CharField</code>, потому что за это отвечает непосредственно Django (хотя конечно, на практике в течение разработки вы косвенно будете проверять данную функциональность). Тоже касается и, например, проверки того, что поле <code>date_of_birth</code> является датой, поскольку это тоже часть реализации Django.</p> + +<p>Вы должны проверить текст для меток (<em>First name, Last_name, Date of birth, Died</em>), и размер поля, выделенного для текста (<em>100 символов</em>), потому что они являются частью вашей разработки и чем-то, что может сломаться/измениться в будущем.</p> + +<pre class="brush: python">class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + return '%s, %s' % (self.last_name, self.first_name)</pre> + +<p>Подобным же образом вы должны убедиться, что методы <code style="font-style: normal; font-weight: normal;">get_absolute_url()</code> и <code style="font-style: normal; font-weight: normal;">__str__()</code> ведут себя как требуется, потому что они являются частью вашей бизнес логики. В случае функции <code style="font-style: normal; font-weight: normal;">get_absolute_url()</code> вы можете быть уверены, что функция из Django <code>reverse()</code> была реализована правильно и, следовательно, вы тестируете только то, чтобы соответствующий вызов в отображении был правильно определен.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Проницательные читатели могут заметить, что мы можем некоторым образом ограничить дату рождения и смерти какими-то граничными значениями и выполнять проверку, чтобы дата смерти шла после рождения. В Django данное ограничение может быть добавлено к вашим классам форм (хотя вы и можете определить валидаторы для этих полей, они будут проявлять себя только на уровне форм, а не уровне модели).</p> +</div> + +<p>Ну что же, усвоив данную информацию, давайте перейдем к процессу определения и запуска тестов.</p> + +<h2 id="Обзор_стуктуры_тестов">Обзор стуктуры тестов</h2> + +<p>Перед тем как мы перейдем к тому "что тестировать", давайте кратко взглянем на моменты <em>где</em> и <em>как</em> определяются тесты.</p> + +<p>Django использует юнит-тестовый модуль - <a href="https://docs.python.org/3/library/unittest.html#unittest-test-discovery" title="(in Python v3.5)">встроенный "обнаружитель" тестов</a>, который находит тесты в текущей рабочей директории, в любом файле с шаблонным именем<strong> test*.py</strong>. Предоставляя соответствующие имена файлов, вы можете работать с любой структурой которая вас устраивает. Мы рекомендуем создать пакет для вашего тестирующего кода и, следовательно, отделить файлы моделей, отображений, форм и любые другие, от кода который будет использоваться для тестов. Например:</p> + +<pre>catalog/ + /tests/ + __init__.py + test_models.py + test_forms.py + test_views.py +</pre> + +<p>В проекте <em>LocalLibrary</em> создайте файловую структуру, указанную выше. Файл <strong>__init__.py</strong> должен быть пустым (так мы говорим Питону, что данная директория является пакетом). Вы можете создать три тестовых файла при помощи копирования и переименования файла-образца <strong>/catalog/tests.py</strong>.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Скелет тестового файла <strong>/catalog/tests.py</strong> был создан автоматически когда мы выполняли <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">построение скелета сайта Django</a>. Является абсолютно "легальным" действием - поместить все ваши тесты в данный файл, тем не менее, если вы проводите тесты "правильно", то вы очень быстро придете к очень большому и неуправляемому файлу тестирования.</p> + +<p>Можете удалить данный файл, поскольку больше он нам не понадобится.</p> +</div> + +<p>Откройте <strong>/catalog/tests/test_models.py</strong>. Файл должен импортировать <code>django.test.TestCase</code>, как показано ниже:</p> + +<pre class="brush: python">from django.test import TestCase + +# Поместите ваш код тестов здесь +</pre> + +<p>Вы часто будете добавлять соответствующий тестовый класс для каждой модели/отображения/формы с отдельными методами проверки каждой отдельной функциональности. В каких-то случаях вы захотите иметь отдельный класс для тестирования какого-то особого варианта работы, или функционала, с отдельными функциями тестирования, которые будут проверять элемент/элементы данного варианта (например, мы можем создать отдельный класс тестирования для проверки того, что поле валидно, - функции данного класса будут проверять каждый неверный вариант использования). Опять же, структура файлов и пакетов полностью зависит от вас и будет лучше если вы будете ее придерживаться.</p> + +<p>Добавьте тестовый класс, показанный ниже, в нижнюю часть файла. Данный класс демонстрирует как создать класс тестирования при помощи наследования от <code>TestCase</code>.</p> + +<pre class="brush: python">class YourTestClass(TestCase): + + @classmethod + def setUpTestData(cls): + print("setUpTestData: Run once to set up non-modified data for all class methods.") + pass + + def setUp(self): + print("setUp: Run once for every test method to setup clean data.") + pass + + def test_false_is_false(self): + print("Method: test_false_is_false.") + self.assertFalse(False) + + def test_false_is_true(self): + print("Method: test_false_is_true.") + self.assertTrue(False) + + def test_one_plus_one_equals_two(self): + print("Method: test_one_plus_one_equals_two.") + self.assertEqual(1 + 1, 2)</pre> + +<p>Этот класс определяет два метода которые вы можете использовать для дотестовой настройки (например, создание какой-либо модели, или других объектов, которые вам понадобятся):</p> + +<ul> + <li><code>setUpTestData()</code> вызывается каждый раз перед запуском теста на уровне настройки всего класса. Вы должны использовать данный метод для создания объектов, которые не будут модифицироваться/изменяться в каком-либо из тестовых методов.</li> + <li><code>setUp()</code> вызывается перед каждой тестовой функцией для настройки объектов, которые могут изменяться во время тестов (каждая функция тестирования будет получать "свежую" версию данных объектов).</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>. Классы тестирования также содержат метод <code>tearDown()</code>, который мы пока не используем. Этот метод не особенно полезен для тестирования баз данных, поскольку базовый класс <code>TestCase</code> автоматически разрывает соединения с ними.</p> +</div> + +<p>Далее идут несколько методов, которые используют функции <code>Assert</code>, проверяющие условия "истинно" (true), "ложно" (false) или равенство (<code>AssertTrue</code>, <code>AssertFalse</code>, <code>AssertEqual</code>). Если условия не выполняются как ожидалось, то это приводит к провалу теста и выводу соответствующего сообщения об ошибке на консоль.</p> + +<p>Функции проверки утверждений <code>AssertTrue</code>, <code>AssertFalse</code>, <code>AssertEqual</code> реализованы в <strong>unittest</strong>. В данном фреймворке существуют и другие подобные функции, а кроме того, <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#assertions">специфические для Django функции</a> проверки, например, перехода из/к отображению (<code>assertRedirects</code>), проверки использования какого-то конкретного шаблона (<code>assertTemplateUsed</code>) и так далее.</p> + +<div class="note"> +<p>В обычной ситуации у вас нет необходимости вызывать функции <strong>print()</strong> из методов теста, как во фрагменте выше. Мы поступили так только для того, чтобы вы в консоле увидели порядок вызова тестовых функций класса.</p> +</div> + +<h2 id="Как_запускать_тесты">Как запускать тесты</h2> + +<p>Простейшим способом запуска всех тестов является применение следующей команды:</p> + +<pre class="brush: bash">python3 manage.py test</pre> + +<p>Таким образом мы найдем в текущей директории все файлы с именем <strong>test*.py</strong> и запустим все тесты (у нас имеются несколько файлов для тестирования, но на данный момент, только <strong>/catalog/tests/test_models.py</strong> содержит какие-либо тесты). По умолчанию, тесты сообщат что-нибудь, только в случае провала.</p> + +<p>Запустите тесты из корневой папки сайта <em>LocalLibrary</em>. Вы должны увидеть вывод, который похож на следующий.</p> + +<pre class="brush: bash">>python manage.py test + +Creating test database for alias 'default'... +<strong>setUpTestData: Run once to set up non-modified data for all class methods. +setUp: Run once for every test method to setup clean data. +Method: test_false_is_false. +.setUp: Run once for every test method to setup clean data. +Method: test_false_is_true. +.setUp: Run once for every test method to setup clean data. +Method: test_one_plus_one_equals_two.</strong> +. +====================================================================== +FAIL: test_false_is_true (catalog.tests.tests_models.YourTestClass) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "D:\Github\django_tmp\library_w_t_2\locallibrary\catalog\tests\tests_models.py", line 22, in test_false_is_true + self.assertTrue(False) +AssertionError: False is not true + +---------------------------------------------------------------------- +Ran 3 tests in 0.075s + +FAILED (failures=1) +Destroying test database for alias 'default'...</pre> + +<p>Как видите, один тест провалился и мы можем точно увидеть в какой именно функции это произошло и почему (так и было задумано, поскольку <code>False</code> не равен <code>True</code>!).</p> + +<div class="note"> +<p><strong>Совет: </strong> Самая важная вещь, которую нужно извлечь из тестового выхода выше, заключается в том, что это гораздо более ценно, если вы используете описательные/информативные имена для ваших объектов и методов.</p> +</div> + +<p>Текст выделенный жирным, обычно не должен появляться в тестовом выводе (это результат работы функций <code>print()</code> в наших тестах). Он показывает, что вызов метода <code>setUpTestData()</code> происходит один раз для всего класса в целом, а вызовы<code>setUp()</code> осуществляются перед каждым методом.</p> + +<p>Следующий раздел показывает как запускать отдельные тесты и как контролировать процесс вывода информации.</p> + +<h3 id="Еще_больше_тестовой_информации">Еще больше тестовой информации</h3> + +<p>Если вы желаете получать больше информации о тестах вы должны изменить значение параметра <em>verbosity</em>. Например, для вывода списка успешных и неуспешных тестов (и всю информацию о том, как прошла настройка базы данных) вы можете установить значение verbosity равным "2":</p> + +<pre class="brush: bash">python3 manage.py test --verbosity 2</pre> + +<p>Доступными значениями для verbosity являются 0, 1 (значение по умолчанию), 2 и 3.</p> + +<h3 id="Запуск_определенных_тестов">Запуск определенных тестов</h3> + +<p>Если вы хотите запустить подмножество тестов, тогда вам надо указать полный путь к вашему пакету, модулю/подмодулю, классу наследнику<code>TestCase</code>, или методу:</p> + +<pre class="brush: bash">python3 manage.py test catalog.tests # Run the specified module +python3 manage.py test catalog.tests.test_models # Run the specified module +python3 manage.py test catalog.tests.test_models.YourTestClass # Run the specified class +python3 manage.py test catalog.tests.test_models.YourTestClass.test_one_plus_one_equals_two # Run the specified method +</pre> + +<h2 id="Тестирование_LocalLibrary">Тестирование LocalLibrary</h2> + +<p>Теперь, когда мы знаем как запустить наши тесты и что именно мы должны тестировать, давайте рассмртрим некоторые практические примеры.</p> + +<div class="note"> +<p><strong>Примечание: </strong>Мы не будем расписывать все тесты, а просто покажем вам пример того, как они должны работать и что еще вы можете с ними сделать.</p> +</div> + +<h3 id="Модели">Модели</h3> + +<p>Как было отмечено ранее, мы должны тестировать все то, что является частью нашего кода, а не библиотеки/код, которые уже были протестированы командами разработчиков Django, или Python.</p> + +<p>Рассмотрим модель <code>Author</code>. Мы должны провести тесты текстовых меток всех полей, поскольку, даже несмотря на то, что не все они определены, у нас есть проект, в котором сказано, что все их значения должны быть заданы. Если мы не проведем их тестирование, тогда мы не будем знать, что данные метки действительно содержат необходимые значения. Мы уверены в том, что Django создаст поле заданной длины, таким образом наши тесты будут проверять нужный нам размер поля, а заодно и его содержимое.</p> + +<pre class="brush: python">class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + return '%s, %s' % (self.last_name, self.first_name)</pre> + +<p>Откройте файл <strong>/catalog/tests/test_models.py</strong> и замените все его содержимое кодом, приведенном во фрагменте для тестирования модели <code>Author</code> (фрагмент представлен ниже).</p> + +<p>В первой строке мы импортируем класс <code>TestCase</code>, а затем наследуемся от него, создавая класс с описательным именем (<code>AuthorModelTest</code>), оно поможет нам идентифицировать места провалов в тестах во время вывода информации на консоль. Затем мы создаем метод <code>setUpTestData()</code>, в котором создаем объект автора, который мы будем использовать в тестах, но нигде не будем изменять.</p> + +<pre class="brush: python">from django.test import TestCase + +# Create your tests here. + +from catalog.models import Author + +class AuthorModelTest(TestCase): + + @classmethod + def setUpTestData(cls): + #Set up non-modified objects used by all test methods + Author.objects.create(first_name='Big', last_name='Bob') + + def test_first_name_label(self): + author=Author.objects.get(id=1) + field_label = author._meta.get_field('first_name').verbose_name + self.assertEquals(field_label,'first name') + + def test_date_of_death_label(self): + author=Author.objects.get(id=1) + field_label = author._meta.get_field('date_of_death').verbose_name + self.assertEquals(field_label,'died') + + def test_first_name_max_length(self): + author=Author.objects.get(id=1) + max_length = author._meta.get_field('first_name').max_length + self.assertEquals(max_length,100) + + def test_object_name_is_last_name_comma_first_name(self): + author=Author.objects.get(id=1) + expected_object_name = '%s, %s' % (author.last_name, author.first_name) + self.assertEquals(expected_object_name,str(author)) + + def test_get_absolute_url(self): + author=Author.objects.get(id=1) + #This will also fail if the urlconf is not defined. + self.assertEquals(author.get_absolute_url(),'/catalog/author/1')</pre> + +<p>Тесты полей проверяют значения текстовых меток (<code>verbose_name</code>), включая их ожидаемую длину. Все методы имеют описательные имена, а их логика придерживается одной и той же структуры:</p> + +<pre class="brush: python"># Получение объекта для тестирования +author=Author.objects.get(id=1) + +# Получение метаданных поля для получения необходимых значений +field_label = author._meta.get_field('first_name').verbose_name + +# Сравнить значение с ожидаемым результатом +self.assertEquals(field_label,'first name') </pre> + +<p>Интересно отметить следующее:</p> + +<ul> + <li>Мы не можем получить поле <code>verbose_name</code> напрямую через <code>author.first_name.verbose_name</code>, потому что <code>author.first_name</code> является <em>строкой</em>. Вместо этого, нам надо использовать атрибут <code>_meta</code> объекта автора для получения того экземпляра поля, который будет использоваться для получения дополнительной информации.</li> + <li>Мы выбрали метод <code>assertEquals(field_label,'first name')</code> вместо <code>assertTrue(field_label == 'first name')</code>, потому что, в случае провала теста, в выводе будет указано какое именно значение содержит метка и это немного облегчит нам задачу по отладке кода.</li> +</ul> + +<div class="note"> +<p><strong>Примечание:</strong> Тесты для текстовых меток <code>last_name</code> и <code>date_of_birth</code>, а также тест длины поля <code>last_name</code> были опущены. Добавьте свою версию этих тестов, соблюдая соглашение об именовании и следуя структуре логики, представленной выше.</p> +</div> + +<p>Кроме того, нам надо провести тесты наших собственных методов. Они просто проверяют, что имена объектов имеют следующие значения "Last Name, First Name" и что URL-адрес, по которому мы получаем экземпляр <code>Author</code>, такой как ожидается.</p> + +<pre class="brush: python">def test_object_name_is_last_name_comma_first_name(self): + author=Author.objects.get(id=1) + expected_object_name = '%s, %s' % (author.last_name, author.first_name) + self.assertEquals(expected_object_name,str(author)) + +def test_get_absolute_url(self): + author=Author.objects.get(id=1) + #This will also fail if the urlconf is not defined. + self.assertEquals(author.get_absolute_url(),'/catalog/author/1')</pre> + +<p>Теперь запустите тесты. Если вы создали модель Author, в соответствии с разделом о моделях данного руководства, то весьма вероятно, что вы получите сообщение об ошибке для метки <code>date_of_death</code>, как показано ниже. Тест провалился потому что, в соответствии с соглашением Django, первый символ имени метки должен быть в верхнем регистре (Django делает это автоматически).</p> + +<pre class="brush: bash">====================================================================== +FAIL: test_date_of_death_label (catalog.tests.test_models.AuthorModelTest) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "D:\...\locallibrary\catalog\tests\test_models.py", line 32, in test_date_of_death_label + self.assertEquals(field_label,'died') +AssertionError: 'Died' != 'died' +- Died +? ^ ++ died +? ^</pre> + +<p>Это несущественный баг, но он демонстрирует нам то, что написание тестов может более тщательно проверить все неточности, которые вы можете сделать.</p> + +<div class="note"> +<p><strong>Примечание: </strong>Измените значение метки для поля date_of_death (/catalog/models.py) на "died" и перезапустите тесты.</p> +</div> + +<p>Тот же подход применяется к тестированию других моделей. Самостоятельно создайте свои собственные тесты для оставшихся моделей.</p> + +<h3 id="Формы">Формы</h3> + +<p>Смысл проведения тестов для форм тот же, что и для моделей; надо проверить весь собственный код и другие особенности проекта, но не то, что касается фреймворка, или сторонних библиотек.</p> + +<p>В основном это означает, что вы должны протестировать то, что формы имеют соответствующие поля и что они показываются с соответствующими метками и вспомогательными текстами. Вам не надо проверять то, что Django правильно осуществляет валидацию полей (если только вы не создали свое собственное поле и валидацию) — то есть вам не надо проверять что, например, поле ввода имейл-адреса принимает только имейл-адреса. Но вы должны протестировать каждую дополнительную валидацию, которую вы добавляете для полей и любые сообщения, который ваш код генерирует в случае ошибок.</p> + +<p>Рассмотрим форму для обновления книг. Она имеет только одно поле обновления даты, которое будет иметь текстовую метку и вспомогательный текст, который вам надо проверить.</p> + +<pre class="brush: python">class RenewBookForm(forms.Form): + """ + Форма обновления книг для библиотекарей + """ + renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).") + + def clean_renewal_date(self): + data = self.cleaned_data['renewal_date'] + + #Проверка, что дата не в прошлом. + if data < datetime.date.today(): + raise ValidationError(_('Invalid date - renewal in past')) + #Если дата в "далеком" будущем (+4 недели) + if data > datetime.date.today() + datetime.timedelta(weeks=4): + raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) + + # Всегда надо возвращать очищенные данные. + return data</pre> + +<p>Откройте файл <strong>/catalog/tests/test_forms.py</strong> и замените весь существующий в нем код, следующим кодом теста для формы <code>RenewBookForm</code>. Мы начали его с импорта нашей формы и некоторых библиотек Python и Django, которые погут нам провести тесты. Затем, тем же способом как мы делали для моделей, объявляем тестовый класс нашей формы, то есть применяя описательное имя класс наследника <code>TestCase</code>.</p> + +<pre class="brush: python">from django.test import TestCase + +# Создайте ваши тесты здесь + +import datetime +from django.utils import timezone +from catalog.forms import RenewBookForm + +class RenewBookFormTest(TestCase): + + def test_renew_form_date_field_label(self): + form = RenewBookForm() + self.assertTrue(form.fields['renewal_date'].label == None or form.fields['renewal_date'].label == 'renewal date') + + def test_renew_form_date_field_help_text(self): + form = RenewBookForm() + self.assertEqual(form.fields['renewal_date'].help_text,'Enter a date between now and 4 weeks (default 3).') + + def test_renew_form_date_in_past(self): + date = datetime.date.today() - datetime.timedelta(days=1) + form_data = {'renewal_date': date} + form = RenewBookForm(data=form_data) + self.assertFalse(form.is_valid()) + + def test_renew_form_date_too_far_in_future(self): + date = datetime.date.today() + datetime.timedelta(weeks=4) + datetime.timedelta(days=1) + form_data = {'renewal_date': date} + form = RenewBookForm(data=form_data) + self.assertFalse(form.is_valid()) + + def test_renew_form_date_today(self): + date = datetime.date.today() + form_data = {'renewal_date': date} + form = RenewBookForm(data=form_data) + self.assertTrue(form.is_valid()) + + def test_renew_form_date_max(self): + date = timezone.now() + datetime.timedelta(weeks=4) + form_data = {'renewal_date': date} + form = RenewBookForm(data=form_data) + self.assertTrue(form.is_valid()) +</pre> + +<p>Первые две функции проверяют текст который должны содержать поля <code>label</code> и <code>help_text</code>. Доступ к полю мы получаем при помощи словаря (то есть, <code>form.fields['renewal_date']</code>). Отметим, что мы должны проверять содержит ли метка значение <code>None</code>, иначе в поле текста метки вы увидите "<code>None</code>".</p> + +<p>Оставшиеся функции проверяют валидность дат, то есть их нахождение внутри определенного интервала, а также невалидность для значений, которые находятся вне заданного интервала. Для получения исходного значения мы использовали функцию получения текущей даты (<code>datetime.date.today()</code>), а также функцию <code>datetime.timedelta()</code> (которая принимает определенное число дней, или недель). Затем мы просто создали форму, передавая ей наши данные и проверяя ее на валидность.</p> + +<div class="note"> +<p><strong>Примечание:</strong> В данном примере мы не использовали ни базу данных, ни тестовый клиент. Рассмотрите модификацию этих тестов при помощи класса <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.SimpleTestCase">SimpleTestCase</a>.</p> + +<p>Нам также надо бы проверять возникновение ошибок, которые появляются если форма не валидна. Но, обычно, это относится к процессу вывода информации, таким образом, мы позаботимся об этом в следующем разделе.</p> +</div> + +<p>На этом с формами можно закончить; у нас имеются и другие тесты, но они были созданы обобщенными классами отображения для редактирования! Запустите тесты и убедитесь, что наш код все еще им соответствует!</p> + +<h3 id="Отображения">Отображения</h3> + +<p>Для проверки поведения отображения мы используем тестовый клиет Django <a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.Client">Client</a>. Данный класс действует как упрощенный веб-браузер который мы применяем для имитации <code>GET</code> и <code>POST</code> запросов и проверки ответов. Про ответы мы можем узнать почти все, начиная с низкоуровневого HTTP (итоговые заголовки и коды статусов) и вплоть до применяемых шаблонов, которые используются для HTML-рендера, а также контекста, который передается в соответствующий шаблон. Кроме того, мы можем отследить последовательность перенаправлений (если имеются), проверить URL-адреса и коды статусов на каждом шаге. Все это позволит нам проверить, что каждое отображение выполняет то, что ожидается.</p> + +<p>Давайте начнем с одного из простейших отображений которое возвращает список всех авторов. Вы можете его увидеть по URL-адресу <strong>/catalog/authors/</strong> (данный URL-адрес можно найти в разделе приложения catalog, в файле настроек urls.py по имени 'authors').</p> + +<pre class="brush: python">class AuthorListView(generic.ListView): + model = Author + paginate_by = 10 +</pre> + +<p>Поскольку это обобщенное отображение списка, то почти все за нас делает Django. Если вы доверяете Django, то единственной вещью, которую вам нужно протестировать, является переход к данному отображению по указанному URL-адресу. Таким образом, если вы применяете методику TDD (test-driven development, разработка через тесты), то начните проект с написания тестов, которые будут проверять, что данное отображение выводит всех авторов и, к тому же, например, блоками по 10.</p> + +<p>Откройте файл <strong>/catalog/tests/test_views.py</strong> замените все его содержимое на следующий код теста для класса <code>AuthorListView</code>. Как и ранее, мы импортируем нашу модель и некоторые полезные классы. В методе <code>setUpTestData()</code> мы задаем число объектов класса <code>Author</code> которые мы тестируем при постраничном выводе.</p> + +<pre class="brush: python">from django.test import TestCase + +# Create your tests here. + +from catalog.models import Author +from django.urls import reverse + +class AuthorListViewTest(TestCase): + + @classmethod + def setUpTestData(cls): + #Create 13 authors for pagination tests + number_of_authors = 13 + for author_num in range(number_of_authors): + Author.objects.create(first_name='Christian %s' % author_num, last_name = 'Surname %s' % author_num,) + + def test_view_url_exists_at_desired_location(self): + resp = self.client.get('/catalog/authors/') + self.assertEqual(resp.status_code, 200) + + def test_view_url_accessible_by_name(self): + resp = self.client.get(reverse('authors')) + self.assertEqual(resp.status_code, 200) + + def test_view_uses_correct_template(self): + resp = self.client.get(reverse('authors')) + self.assertEqual(resp.status_code, 200) + + self.assertTemplateUsed(resp, 'catalog/author_list.html') + + def test_pagination_is_ten(self): + resp = self.client.get(reverse('authors')) + self.assertEqual(resp.status_code, 200) + self.assertTrue('is_paginated' in resp.context) + self.assertTrue(resp.context['is_paginated'] == True) + self.assertTrue( len(resp.context['author_list']) == 10) + + def test_lists_all_authors(self): + #Get second page and confirm it has (exactly) remaining 3 items + resp = self.client.get(reverse('authors')+'?page=2') + self.assertEqual(resp.status_code, 200) + self.assertTrue('is_paginated' in resp.context) + self.assertTrue(resp.context['is_paginated'] == True) + self.assertTrue( len(resp.context['author_list']) == 3)</pre> + +<p>Все тесты используют клиент (принадлежащего классу <code>TestCase</code>, от которого мы наследовались) для имитации <code>GET</code>-запроса и получения ответа (<code>resp</code>). Первая версия проверяет заданный URL-адрес (заметьте, - просто определенный путь без указания домена), в то время как второй генерирует URL-адрес при помощи его имени, указанного в настройках.</p> + +<pre class="brush: python">resp = self.client.get('/catalog/authors/') +resp = self.client.get(reverse('authors')) +</pre> + +<p>Когда мы получаем ответ, то мы извлекаем код статуса, используемый шаблон, "включен" ли постраничный вывод, количество элементов в подмножестве (на странице) и общее число элементов.</p> + +<p>Наиболее интересной переменной является <code>resp.context</code>, которая является объектом контекста, который передается шаблону из отображения. Он (объект контекста) очень полезен для тестов, поскольку позволяет нам убедиться, что наш шаблон получает все данные которые ему необходимы. Другими словами мы можем проверить, что мы используем правильный шаблон с данными, которые проделывают долгий путь проверок чтобы соответствовать данному шаблону.</p> + +<h4 id="Отображения_и_регистрация_пользователей">Отображения и регистрация пользователей</h4> + +<p>В некоторых случаях вам нужно провести тесты отображений к которым имеют доступ только зарегистрированные пользователи. Например, <code>LoanedBooksByUserListView</code> очень похоже на наше предыдущее отображение, но доступно только для залогинившихся пользователей и показывает только те записи (<code>BookInstance)</code>, которые соответствуют текущему пользователю, имеют статус 'on loan' (книга взята домой), а также забронированны.</p> + +<pre class="brush: python">from django.contrib.auth.mixins import LoginRequiredMixin + +class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView): + """ + Обобщенный класс отображения списка взятых книг текущим пользователем + """ + model = BookInstance + template_name ='catalog/bookinstance_list_borrowed_user.html' + paginate_by = 10 + + def get_queryset(self): + return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')</pre> + +<p>Добавьте тестовый код следующего фрагмента в <strong>/catalog/tests/test_views.py</strong>. В нем, для создания нескольких аккаунтов и объектов <code>BookInstance</code> которые будут использоваться в дальнейших тестах, мы используем метод <code>SetUp()</code> (вместе с соответствующими книгами и другими записями). Половина книг бронируется тестовыми пользователями, но в начале для них всех мы устанавливаем статус "доступно". Использование метода <code>SetUp()</code> предпочтительнее чем <code>setUpTestData()</code>, поскольку в дальнейшем мы будем модифицировать некоторые объекты.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Метод <code>setUp()</code> создает книгу с заданным языком <code>Language</code>, но <em>ваш</em> код может не включать в себя модель <code>Language</code>, поскольку это было <em>домашним заданием</em>. В таком случае просто закомментируйте соответствующие строки. Поступите также и в следующем разделе, посвященном <code>RenewBookInstancesViewTest.</code></p> +</div> + +<pre class="brush: python">import datetime +from django.utils import timezone + +from catalog.models import BookInstance, Book, Genre, Language +from django.contrib.auth.models import User # Необходимо для представления User как borrower + +class LoanedBookInstancesByUserListViewTest(TestCase): + + def setUp(self): + # Создание двух пользователей + test_user1 = User.objects.create_user(username='testuser1', password='12345') + test_user1.save() + test_user2 = User.objects.create_user(username='testuser2', password='12345') + test_user2.save() + + # Создание книги + test_author = Author.objects.create(first_name='John', last_name='Smith') + test_genre = Genre.objects.create(name='Fantasy') + test_language = Language.objects.create(name='English') + test_book = Book.objects.create(title='Book Title', summary = 'My book summary', isbn='ABCDEFG', author=test_author, language=test_language) + # Create genre as a post-step + genre_objects_for_book = Genre.objects.all() + test_book.genre.set(genre_objects_for_book) # Присвоение типов many-to-many напрямую недопустимо + test_book.save() + + # Создание 30 объектов BookInstance + number_of_book_copies = 30 + for book_copy in range(number_of_book_copies): + return_date= timezone.now() + datetime.timedelta(days=book_copy%5) + if book_copy % 2: + the_borrower=test_user1 + else: + the_borrower=test_user2 + status='m' + BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=the_borrower, status=status) + + def test_redirect_if_not_logged_in(self): + resp = self.client.get(reverse('my-borrowed')) + self.assertRedirects(resp, '/accounts/login/?next=/catalog/mybooks/') + + def test_logged_in_uses_correct_template(self): + login = self.client.login(username='testuser1', password='12345') + resp = self.client.get(reverse('my-borrowed')) + + # Проверка что пользователь залогинился + self.assertEqual(str(resp.context['user']), 'testuser1') + # Проверка ответа на запрос + self.assertEqual(resp.status_code, 200) + + # Проверка того, что мы используем правильный шаблон + self.assertTemplateUsed(resp, 'catalog/bookinstance_list_borrowed_user.html') +</pre> + +<p>Если пользователь не залогирован то, чтобы убедиться в том что отображение перейдет на страницу входа (логирования), мы используем метод <code>assertRedirects</code>, что продемонстрировано в методе <code>test_redirect_if_not_logged_in()</code>. Затем мы осуществляем вход для пользователя и проверям что полученный статус <code>status_code</code> равен 200 (успешно). </p> + +<p>Остальные тесты проверяют, соответственно, что наше отображение показывает только те книги которые взяты текущим пользователем. Скопируйте код, показанный ниже, в нижнюю часть предыдущего класса.</p> + +<pre class="brush: python"> def test_only_borrowed_books_in_list(self): + login = self.client.login(username='testuser1', password='12345') + resp = self.client.get(reverse('my-borrowed')) + + #Проверка, что пользователь залогинился + self.assertEqual(str(resp.context['user']), 'testuser1') + #Check that we got a response "success" + self.assertEqual(resp.status_code, 200) + + #Проверка, что изначально у нас нет книг в списке + self.assertTrue('bookinstance_list' in resp.context) + self.assertEqual( len(resp.context['bookinstance_list']),0) + + #Теперь все книги "взяты на прокат" + get_ten_books = BookInstance.objects.all()[:10] + + for copy in get_ten_books: + copy.status='o' + copy.save() + + #Проверка, что все забронированные книги в списке + resp = self.client.get(reverse('my-borrowed')) + #Проверка, что пользователь залогинился + self.assertEqual(str(resp.context['user']), 'testuser1') + #Проверка успешности ответа + self.assertEqual(resp.status_code, 200) + + self.assertTrue('bookinstance_list' in resp.context) + + #Подтверждение, что все книги принадлежат testuser1 и взяты "на прокат" + for bookitem in resp.context['bookinstance_list']: + self.assertEqual(resp.context['user'], bookitem.borrower) + self.assertEqual('o', bookitem.status) + + def test_pages_ordered_by_due_date(self): + + #Изменение статуса на "в прокате" + for copy in BookInstance.objects.all(): + copy.status='o' + copy.save() + + login = self.client.login(username='testuser1', password='12345') + resp = self.client.get(reverse('my-borrowed')) + + #Пользователь залогинился + self.assertEqual(str(resp.context['user']), 'testuser1') + #Check that we got a response "success" + self.assertEqual(resp.status_code, 200) + + #Подтверждение, что из всего списка показывается только 10 экземпляров + self.assertEqual( len(resp.context['bookinstance_list']),10) + + last_date=0 + for copy in resp.context['bookinstance_list']: + if last_date==0: + last_date=copy.due_back + else: + self.assertTrue(last_date <= copy.due_back)</pre> + +<p>Если хотите, то вы, безусловно, можете добавить тесты проверяющие постраничный вывод!</p> + +<h4 id="Тестирование_форм_и_отображений">Тестирование форм и отображений</h4> + +<p>Процесс тестирования отображений с формами немного более сложен, чем в представленных ранее случаях, поскольку вам надо протестировать большее количество кода: начальное состояние показа формы, показ формы и ее данных в случае ошибок, а также показ формы в случае успеха. Хорошей новостью является то, что мы применяем клиент для тестирования практически тем же способом, как мы делали это в случае отображений, которые отвечают только за вывод информации.</p> + +<p>В качестве демонстрации давайте напишем некоторые тесты для отображения, которые отвечают за обновление книг(<code>renew_book_librarian()</code>):</p> + +<pre class="brush: python">from .forms import RenewBookForm + +@permission_required('catalog.can_mark_returned') +def renew_book_librarian(request, pk): + """ + Функция отображения обновления экземпляра BookInstance библиотекарем + """ + book_inst=get_object_or_404(BookInstance, pk = pk) + + # Если это POST-запрос, тогда обработать данные формы + if request.method == 'POST': + + # Создать объект формы и заполнить ее данными из запроса (связывание/биндинг): + form = RenewBookForm(request.POST) + + # Проверка валидности формы: + if form.is_valid(): + # process the data in form.cleaned_data as required (here we just write it to the model due_back field) + book_inst.due_back = form.cleaned_data['renewal_date'] + book_inst.save() + + # переход по URL-адресу: + return HttpResponseRedirect(reverse('all-borrowed') ) + + # Если это GET-запрос (или что-то еще), то создаем форму по умолчанию + else: + proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) + form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,}) + + return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre> + +<p>Нам надо проверить что к данному отображению имеют доступ только те пользователи, которые имеют разрешение типа <code>can_mark_returned</code>, а кроме того, что пользователи перенаправляются на страницу ошибки HTTP 404 если они пытаются обновить экземпляр книги <code>BookInstance</code>, который не существует. Мы должны проверить что начальное значение формы соответствует дате через 3 недели в будущем, а также то, что если форма прошла валидацию, то мы переходим на страницу отображения книг "all-borrowed" (забронированных). Для тестов, отвечающих за проверку "провалов", мы также должны удостовериться что они отправляют соответствующие сообщения об ошибках.</p> + +<p>В нижнюю часть файла <strong>/catalog/tests/test_views.py</strong> добавьте класс тестрования (показан во фрагменте, ниже). Он создает двух пользователей и два экземпляра книги, но только один пользователь получает необходимый доступ к соответствующему отображению. Код, который "присваивает" соответствующий доступ, выделен в коде жирным:</p> + +<pre class="brush: python">from django.contrib.auth.models import Permission # Required to grant the permission needed to set a book as returned. + +class RenewBookInstancesViewTest(TestCase): + + def setUp(self): + #Создание пользователя + test_user1 = User.objects.create_user(username='testuser1', password='12345') + test_user1.save() + + test_user2 = User.objects.create_user(username='testuser2', password='12345') + test_user2.save() +<strong> permission = Permission.objects.get(name='Set book as returned') + test_user2.user_permissions.add(permission) + test_user2.save()</strong> + + #Создание книги + test_author = Author.objects.create(first_name='John', last_name='Smith') + test_genre = Genre.objects.create(name='Fantasy') + test_language = Language.objects.create(name='English') + test_book = Book.objects.create(title='Book Title', summary = 'My book summary', isbn='ABCDEFG', author=test_author, language=test_language,) + #Создание жанра Create genre as a post-step + genre_objects_for_book = Genre.objects.all() + test_book.genre=genre_objects_for_book + test_book.save() + + #Создание объекта BookInstance для для пользователя test_user1 + return_date= datetime.date.today() + datetime.timedelta(days=5) + self.test_bookinstance1=BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=test_user1, status='o') + + #Создание объекта BookInstance для для пользователя test_user2 + return_date= datetime.date.today() + datetime.timedelta(days=5) + self.test_bookinstance2=BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=test_user2, status='o')</pre> + +<p>В нижнюю часть класса тестирования добавьте следующие методы (из следующего фрагмента). Они проверяют, что только пользователь с соответствущим доступом (<em>testuser2</em>) имеет доступ к отображению. Мы проверяем все случаи: когда пользователь не залогинился, когда залогинился, но не имеет соответствующего доступа, когда имеет доступ, но не является заемщиком книги (тест должен быть успешным), а также, что произойдет если попытаться получить доступ к книге <code>BookInstance</code> которой не существует. Кроме того, мы проверям то, что используется правильный (необходимый) шаблон.</p> + +<pre class="brush: python"> def test_redirect_if_not_logged_in(self): + resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) ) + #Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable) + self.assertEqual( resp.status_code,302) + self.assertTrue( resp.url.startswith('/accounts/login/') ) + + def test_redirect_if_logged_in_but_not_correct_permission(self): + login = self.client.login(username='testuser1', password='12345') + resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) ) + + #Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable) + self.assertEqual( resp.status_code,302) + self.assertTrue( resp.url.startswith('/accounts/login/') ) + + def test_logged_in_with_permission_borrowed_book(self): + login = self.client.login(username='testuser2', password='12345') + resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance2.pk,}) ) + + #Check that it lets us login - this is our book and we have the right permissions. + self.assertEqual( resp.status_code,200) + + def test_logged_in_with_permission_another_users_borrowed_book(self): + login = self.client.login(username='testuser2', password='12345') + resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) ) + + #Check that it lets us login. We're a librarian, so we can view any users book + self.assertEqual( resp.status_code,200) + + def test_HTTP404_for_invalid_book_if_logged_in(self): + import uuid + test_uid = uuid.uuid4() #unlikely UID to match our bookinstance! + login = self.client.login(username='testuser2', password='12345') + resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':test_uid,}) ) + self.assertEqual( resp.status_code,404) + + def test_uses_correct_template(self): + login = self.client.login(username='testuser2', password='12345') + resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) ) + self.assertEqual( resp.status_code,200) + + #Check we used correct template + self.assertTemplateUsed(resp, 'catalog/book_renew_librarian.html') +</pre> + +<p>Добавьте еще один тестовый метод, показанный ниже. Он проверяет что начальная дата равна трем неделям в будущем. Заметьте, что мы имеем возможность получить доступ к начальному значению из поля формы (выделено жирным).</p> + +<pre class="brush: python"> def test_form_renewal_date_initially_has_date_three_weeks_in_future(self): + login = self.client.login(username='testuser2', password='12345') + resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) ) + self.assertEqual( resp.status_code,200) + + date_3_weeks_in_future = datetime.date.today() + datetime.timedelta(weeks=3) + self.assertEqual(<strong>resp.context['form'].initial['renewal_date']</strong>, date_3_weeks_in_future ) +</pre> + +<p>Следующий тест (тоже добавьте его в свой класс) проверяет что отображение, в случае успеха, перенаправляет пользователя к списку всех забронированных книг. Здесь мы показываем как при помощи клиента вы можете создать и передать данные в <code>POST</code>-запросе. Данный запрос передается вторым аргументом в пост-функцию и представляет из себя словарь пар ключ/значение.</p> + +<pre class="brush: python"> def test_redirects_to_all_borrowed_book_list_on_success(self): + login = self.client.login(username='testuser2', password='12345') + valid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=2) + resp = <strong>self.client.<em>post</em>(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future} )</strong> + self.assertRedirects(resp, reverse('all-borrowed') ) +</pre> + +<div class="warning"> +<p>Вместо перехода к отображению <em>all-borrowed</em>, добавленого в качестве <em>домашнего задания</em>, вы можете перенаправить пользователя на домашнюю страницу '/'. В таком случае, исправьте две последние строки тестового кода на код, показанный ниже. Присваивание <code>follow=True</code>, в запросе, гарантирует что запрос вернет окончательный URL-адрес пункта назначения (следовательно проверяется <code>/catalog/</code>, а не <code>/</code>).</p> + +<pre class="brush: python"> resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future},<strong>follow=True</strong> ) + <strong>self.assertRedirects(resp, '/catalog/')</strong></pre> +</div> + +<p>Скопируйте две последние функции в класс, представленные ниже. Они тоже проверяют <code>POST</code>-запросы, но для случая неверных дат. Мы используем функцию <code>assertFormError()</code>, чтобы проверить сообщения об ошибках.</p> + +<pre class="brush: python"> def test_form_invalid_renewal_date_past(self): + login = self.client.login(username='testuser2', password='12345') + date_in_past = datetime.date.today() - datetime.timedelta(weeks=1) + resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':date_in_past} ) + self.assertEqual( resp.status_code,200) + <strong>self.assertFormError(resp, 'form', 'renewal_date', 'Invalid date - renewal in past')</strong> + + def test_form_invalid_renewal_date_future(self): + login = self.client.login(username='testuser2', password='12345') + invalid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=5) + resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':invalid_date_in_future} ) + self.assertEqual( resp.status_code,200) + <strong>self.assertFormError(resp, 'form', 'renewal_date', 'Invalid date - renewal more than 4 weeks ahead')</strong> +</pre> + +<p>Такие же способы тестрования могут применяться для проверок других отображений.</p> + +<h3 id="Шаблоны">Шаблоны</h3> + +<p>Django предоставляет API для тестирования, которое проверяет что функции отображения вызывают правильные шаблоны, а также позволяют убедиться, что им передается соответствующая информация. Кроме того, в Django имеется возможность использовать сторонние API для проверок того, что ваш HTML показывает то, что надо.</p> + +<h2 id="Другие_рекомендованные_инструменты_для_тестирования">Другие рекомендованные инструменты для тестирования</h2> + +<p>Django фреймворк для тестирования помогает вам создавать эффективные юнит- и интеграционные тесты — мы рассмотрели только небольшую часть того, что может делать фреймворк <strong>unittest</strong> и совсем не упоминали дополнения Django (например, посмотрите на модуль <a href="https://docs.python.org/3.5/library/unittest.mock-examples.html">unittest.mock</a>, который подключает сторонние библиотеки тестирования).</p> + +<p>Из всего множества сторонних инструментов тестирования, мы кратко опишем возможности двух:</p> + +<ul> + <li><a href="http://coverage.readthedocs.io/en/latest/">Coverage</a>: Это инструмент Python, который формирует отчеты о том, какое количество кода выполняется во время проведения тестов. Это полезно для уточнения степени "покрытия" кода тестами.</li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Selenium</a> это фреймворк проведения автоматического тестирования в настоящем браузере. Он позволяет вам имитировать взаимодействие пользователя с вашим сайтом (что является следующим шагом в проведении интеграционных тестов).</li> +</ul> + +<h2 id="Домашняя_работы">Домашняя работы</h2> + +<p>Существуют другие модели и отображения, которые мы могли бы протестировать. В качестве простого упражнения, попробуйте создать тестовый вариант для отображения <code>AuthorCreate</code>.</p> + +<pre class="brush: python">class AuthorCreate(PermissionRequiredMixin, CreateView): + model = Author + fields = '__all__' + initial={'date_of_death':'12/10/2016',} + permission_required = 'catalog.can_mark_returned'</pre> + +<p>Помните, - вам надо проверить все, что касается вашего кода, или структуры. Это включает в себя: кто имеет доступ к отображению, начальную дату, применяемый шаблон, а также перенаправление из отображения в случае успеха.</p> + +<h2 id="Итоги">Итоги</h2> + +<p>Написание тестов не является ни весельем, ни развлечением и, соответственно, при создании сайтов часто остается напоследок (или вообще не используется). Но тем не менее, они являются действенным механизмом, который позволяет вам убедиться, что ваш код в находится безопасности, даже если в него добавляются какие-либо изменения. Кроме того, тесты повышают эффективность поддержки вашего кода.</p> + +<p>В данном руководстве мы продемонстрировали вам принципы написания тестов для ваших моделей, форм и отображений. Мы кратко перечислили что именно необходимо тестировать, что обычно сложно выявить в самом начале разработки. Существует много аспектов которые необходимо изучить, но даже с тем что мы уже узнали, вы имеете возможность создавать эффективные юнит-тесты для значительного улучшения процесса разработки.</p> + +<p>Следующая и последняя часть руководства покажет вам как запустить ваш чудесный (и полностью протестированный!) веб-сайт Django.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/testing/overview/">Написание и запуск тестов</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/intro/tutorial05/">Написание вашего первого приложения Django, часть 5 > Введение в автоматическое тестирование</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/testing/tools/">Инструменты для тестирования</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/testing/advanced/">Продвинутое тестирование</a> (Django docs)</li> + <li><a href="http://toastdriven.com/blog/2011/apr/10/guide-to-testing-in-django/">Путеводитель по тестированию в Django</a> (Toast Driven Blog, 2011)</li> + <li><a href="http://test-driven-django-development.readthedocs.io/en/latest/index.html">Мастерская: Разработка через тесты с Django (TDD)</a> (San Diego Python, 2014)</li> + <li><a href="https://realpython.com/blog/python/testing-in-django-part-1-best-practices-and-examples/">Тестирование в Django (Часть 1) - Лучшие практики и Примеры </a>(RealPython, 2013)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/django/tutorial_local_library_website/index.html b/files/ru/learn/server-side/django/tutorial_local_library_website/index.html new file mode 100644 index 0000000000..36ad7aa9cb --- /dev/null +++ b/files/ru/learn/server-side/django/tutorial_local_library_website/index.html @@ -0,0 +1,74 @@ +--- +title: 'Руководство по Django: сайт местной библиотеки' +slug: Learn/Server-side/Django/Tutorial_local_library_website +tags: + - django + - Для начинающих + - Программирование + - Руководство + - Серверная часть +translation_of: Learn/Server-side/Django/Tutorial_local_library_website +--- +<div>{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}</div> + +<p class="summary">Первая статья в нашем цикле объясняет, что вы узнаете, и разбирает пример сайта "местная библиотека", который мы будем разрабатывать и улучшать в последующих статьях.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимо:</th> + <td>Прочитайте наше <a href="/ru/docs/Learn/Server-side/Django/Introduction">вступление</a>. Для последующих статей вам так же потребуется настроить <a href="/ru/docs/Learn/Server-side/Django/development_environment">среду разработки.</a></td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Представить читателю пример веб-приложения, которое будет использоваться в нашем руководстве и показать, какие темы будут изучены в этом цикле статей.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор_руководства">Обзор руководства</h2> + +<p>Добро пожаловать на руководство MDN "Сайт местной библиотеки" по фреймворку Django, который может использоваться для управления архивом библиотеки.</p> + +<p>В цикле статей мы научимся:</p> + +<ul> + <li>При помощи Django создавать прототип сайта. </li> + <li>Запускать и останавливать сервер для разработки.</li> + <li>Создавать модели для представления данных.</li> + <li>Использовать админ-панель Django для управления сайтом</li> + <li>Создавать представления для того, чтобы формировать из данных ответы на различные запросы и превращать их в HTML разметку, которая будет отображаться в браузере.</li> + <li>Создавать маршруты, чтобы определённые URL адреса ассоциировались сервером с определёнными представлениями</li> + <li>Создавать авторизацию пользователей и сессии, чтобы управлять доступом к сайту.</li> + <li>Работать с формами.</li> + <li>Тестировать ваше веб-приложение.</li> + <li>Эффективно использовать средства безопасности Django.</li> + <li>Размещать ваш сайт в Сети.</li> +</ul> + +<p>С некоторыми темами вы уже сталкивались, а про некоторые только знаете, что они существуют. По окончанию цикла статей вы должны будете иметь достаточно знаний, чтобы разрабатывать несложные сайты на Django для своих целей.</p> + +<h2 id="Сайт_местной_библиотеки">Сайт местной библиотеки</h2> + +<p><em>Это </em>название сайта, который мы создадим и будем улучшать, в течение этого цикла статей. Как можно догадаться, цель этого сайта в том, чтобы представить небольшой онлайн каталог маленькой местной библиотеки, где пользователи смогут загружать доступные книги и управлять своими профилями.</p> + +<p>Этот пример был выбран потому, что его можно масштабировать, чтобы рассказать настолько детально или поверхностно, насколько это требуется, о почти любой оссобенности Django. Что более важно, этот пример позволяет показать <em>последовательный</em> путь по самым важным функциям фреймворка Django:</p> + +<ul> + <li>В самом начале, мы создадим библиотеку, в которой пользователи смогут только просматривать доступные книги. Это позволит нам исследовать операции, которые присутствуют почти на каждом сайте: чтение и отображение информации из базы данных.</li> + <li>По мере продвижения, на сайте станут использоваться более продвинутые возможности Django. Например, мы сможем расширить библиотеку и позволить пользователям резервировать книги, чтобы показать как использовать формы и авторизацию.</li> +</ul> + +<p>Несмотря на то, что это довольно обширный пример, проект называется сайтом <em>местной</em> библиотеки потому, что мы надеемся показать минимум достаточной информации, которая поможет вам быстро научиться разрабатывать на Django. Поэтому мы будем хранить данные о книгах, копиях книг, авторах и другую ключевую информацию. Однако мы не будем хранить другую информацию, которая могла бы быть полезной библиотеке, или создавать обширную инфраструктуру для поддержки нескольких сайтов библиотек или другие особенности "крупных библиотек". </p> + +<h2 id="Я_застрял_где_мне_взять_код">Я застрял, где мне взять код?</h2> + +<p>По мере усложнения руководства, мы будем предоставлять необходимый код, который можно скопировать и вставить, а так же будет и другой код, который, мы надеемся, вы улучшите самостоятельно.</p> + +<p>Если вы застряли, то можете найти полноценную версию сайта на <a href="https://github.com/mdn/django-locallibrary-tutorial">Github</a>.</p> + +<h2 id="Подводя_итоги">Подводя итоги</h2> + +<p>Теперь вы знаете чуть больше о сайте, который мы будем разрабатывать, и теперь самое время создать <a href="/ru/docs/Learn/Server-side/Django/skeleton_website">скелет</a> нашего сайта.</p> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/django/web_application_security/index.html b/files/ru/learn/server-side/django/web_application_security/index.html new file mode 100644 index 0000000000..84448f9eb3 --- /dev/null +++ b/files/ru/learn/server-side/django/web_application_security/index.html @@ -0,0 +1,179 @@ +--- +title: Безопасность веб-приложения Django +slug: Learn/Server-side/Django/web_application_security +translation_of: Learn/Server-side/Django/web_application_security +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}</div> + +<p class="summary">Защита пользовательских данных - важная часть проектирования любого веб-сайта.Ранее мы рассматривали некоторые наиболее распространенные угрозы безопасности в теме <a href="https://developer.mozilla.org/en-US/docs/Web/Security">Веб безопасность</a>. В данной статье будет представлена практическая демонстрация того, как встроенные механизмы защиты Django's обрабатывают подобные угрозы.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Прочитайте тему <a href="https://developer.mozilla.org/en-US/docs/Web/Security">Веб безопасность</a>. Завершите изучение предыдущих частей руководства до <a href="/en-US/docs/Learn/Server-side/Django/Forms">Руководство часть 9: Работа с формами </a>включительно.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять, что нужно делать (или наоборот не делать), для обеспечения безопасности вашего веб-приложения.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>Тема <a href="https://developer.mozilla.org/en-US/docs/Web/Security">Веб безопасность</a> рассматривает значение безопасности веб-приложения для проектирования серверного приложения и некоторые из наиболее распространенных угроз, от которых вам может потребоваться защита. Одна из ключевых идей этой темы состоит в том, что практически все атаки будут успешны, если веб-приложение доверяет пользовательским данным (например данным из браузера).</p> + +<div class="warning"> +<p><strong>Важно:</strong> Наиболее важный урок, который вы должны усвоить, состоит в том - что никогда не стоит доверять переданным пользователем данным. Они включают в себя GET параметры в URL, тело POST запроса, HTTP заголовки, cookies, загруженные пользователем данные и т.д. Всегда проверяйте и обрабатывайте все входные данные. Всегда готовьтесь к худшему.</p> +</div> + +<p>Хорошей новостью для всех разработчиков, использующих Django, является то, что большинство известных атак обрабатывается фреймворком! Статья <a href="https://docs.djangoproject.com/en/2.0/topics/security/">Безопасность в Django</a> (Django docs) описывает методы обеспечения безопасности Django и стратегии защиты веб-приложения разработанного на данном фреймворке.</p> + +<h2 id="Распространенные_угрозыметоды_защиты">Распространенные угрозы/методы защиты</h2> + +<p>Мы не будем дублировать документацию Django и в данной статье продемонстрируем некоторые основные методы обеспечения безопасности в контексте разрабатываемого в данном руководстве приложения <a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>.</p> + +<h3 id="Межсайтовый_скриптинг_(XSS)">Межсайтовый скриптинг (XSS)</h3> + +<p>XSS это термин, применяющийся для описания класса атак, позволяющего атакующему, через веб-сайт внедрить скрипты, которые будут выполнены на устройстве зашедшего на страницу пользователя. Часто это происходит через сохранение вредоносного кода в базе данных, откуда данный код будет возвращен и выполнен для запросившего некие данные пользователя (типичный пример - сохранение тега <script> с вредоносным кодом в комментарии, который может увидеть другой пользователь). Другой вектор атаки - в том чтобы сгенерировать определенную ссылку, при клике на которую пользователь запустит выполнение некоего замаскированного кода JavaScript в своем браузере.</p> + +<p>Система шаблонов Django защищает от большинства XSS атак, <a href="https://docs.djangoproject.com/en/2.0/ref/templates/language/#automatic-html-escaping">экранируя определенные символы</a>, считающиеся "опасными" в HTML. Мы можем продемонстрировать это, попытавшись внедрить произвольный JavaScript код в наше приложение LocalLibrary через форму добавления автора, созданную в <a href="/en-US/docs/Learn/Server-side/Django/Forms">Руководство часть 9: Работа с формами</a>.</p> + +<ol> + <li>Запустите веб-сайт, используя сервер разработки (<code>python3 manage.py runserver</code>).</li> + <li>Откройте сайт в вашем браузере и войдите под аккаунтом супер-пользователя.</li> + <li>Перейдите на страницу добавления автора (она должна быть доступна по URL: <code><a href="http://127.0.0.1:8000/catalog/author/create/">http://127.0.0.1:8000/catalog/author/create/</a></code>).</li> + <li>Введите данные об имени и фамилии, датах рождения и смерти автора. Затем добавьте следующую строку в поле фамилии:<br> + <code><script>alert('Test alert');</script></code>.<br> + <img alt="Author Form XSS test" src="https://mdn.mozillademos.org/files/14305/author_create_form_alert_xss.png" style="border-style: solid; border-width: 1px; height: 245px; width: 594px;"> + <div class="note"> + <p><strong>Примечание:</strong> Это безобидный скрипт, который, если будет выполнен, отобразит окно с сообщением "Test alert" в вашем браузере. Если данное окно отображается при открытии страницы с созданной подобным образом записью - значит сайт уязвим перед атаками XSS.</p> + </div> + </li> + <li>Нажмите <strong>Submit</strong> для сохранения записи.</li> + <li>После сохранения автора - он должен быть отображен, как показано ниже. Так как сработала защита от XSS - команда <code>alert()</code> не будет запущена. Вместо этого скрипт будет отображаться как обычный текст.<img alt="Author detail view XSS test" src="https://mdn.mozillademos.org/files/14307/author_detail_alert_xss.png" style="border-style: solid; border-width: 1px; height: 248px; width: 986px;"></li> +</ol> + +<p>Если вы посмотрите исходный HTML код, вы увидите, что "опасные" символы - например такие как скобки тегов - были заменены на их безопасные эквивалентные html сущности (к примеру <code>></code> на <code>&gt;</code>)</p> + +<pre class="brush: html"><h1>Author: Boon&lt;script&gt;alert(&#39;Test alert&#39;);&lt;/script&gt;, David (Boonie) </h1> +</pre> + +<p>Использование шаблонов Django защищает вас от большинтсва XSS атак. Однако существует возможность отключения данной защиты, при котором экранирование не будет автоматически применятся ко всем полям, которые не должны будут заполнятся пользователем(к примеру, поле <code>help_text</code> обычно заполняется не пользователем, поэтому Django не будет экранировать его значение).</p> + +<p>Так же XSS атаки могут быть осуществлены через другие ненадежные источники данных, такие как cookies, сторонние сервисы или загруженные файлы (и прочие источники, данные которых не были специально обработаны перед отображением на странице). Если вы отображаете данные из этих источников, вы должны добавить ваш собственный обработчик для "санитаризации" данных.</p> + +<h3 id="Межсайтовая_подделка_запроса_(CSRF)">Межсайтовая подделка запроса (CSRF)</h3> + +<p>CSRF атаки позволяют атакующему выполнять действия от имени другого пользователя без его согласия. Например, предположим что есть хакер, который хочет добавить авторов в наше приложение LocalLibrary.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Очевидно, что наш хакер делает это не ради денег! Более амбициозные хакеры могут использовать описываемый подход для выполнения более опасных задач (например, переводы денег пользователей на их личные счета и т.д).</p> +</div> + +<p>Для того, чтобы сделать это, хакер может создать HTML файл, подобный продемонстрированному ниже, который будет содержать форму создания автора (похожую на ту, что мы разрабатывали в предыдущих частях руководства), которая будет отправлена как только данный файл будет загружен в браузер. Хакер отправит данный файл всем Библиотекарям и будет ждать пока кто-либо из них откроет файл (он содержит только безобидную информацию, честно!). Если файл будет открыт любым залогиненным пользователм, с правами Библиотекаря - тогда форма будет отправлена от его имени и создаст нового пользователя.</p> + +<pre class="brush: html"><html> +<body onload='document.EvilForm.submit()'> + +<form action="http://127.0.0.1:8000/catalog/author/create/" method="post" name='EvilForm'> + <table> + <tr><th><label for="id_first_name">First name:</label></th><td><input id="id_first_name" maxlength="100" name="first_name" type="text" value="Mad" required /></td></tr> + <tr><th><label for="id_last_name">Last name:</label></th><td><input id="id_last_name" maxlength="100" name="last_name" type="text" value="Man" required /></td></tr> + <tr><th><label for="id_date_of_birth">Date of birth:</label></th><td><input id="id_date_of_birth" name="date_of_birth" type="text" /></td></tr> + <tr><th><label for="id_date_of_death">Died:</label></th><td><input id="id_date_of_death" name="date_of_death" type="text" value="12/10/2016" /></td></tr> + </table> + <input type="submit" value="Submit" /> +</form> + +</body> +</html> +</pre> + +<p>Запустите веб-сервер разработки и войдите в аккаунт супер-пользователя. Скопируйте приведенный выше текст в файл и затем откройте его в браузере. Вы должны получить CSRF ошибку, потому что у Django есть защита от атак данного вида!</p> + +<p>Механизм защиты заключается в том, что вы добавляете тег шаблона <code>{% csrf_token %}</code> в вашу форму. Этот токен будет отображен в вашем HTML как показано ниже, со значением, уникальным для каждого запрашивающего форму пользователя.</p> + +<pre class="brush: html"><input type='hidden' name='csrfmiddlewaretoken' value='0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL2mpH29YZ39PW' /> +</pre> + +<p>Django генерирует уникальный для пользователя/браузера токен и отклоняет все формы, которые не содержат его или содержат его неверное значение.</p> + +<p>Для продолжения использования данного вида атак, хакер теперь должен найти и добавить верный CSRF токен для каждого выбранного целью пользователя. Это означает, что хакер теперь не может использовать массовые рассылки одного вредоносного файла всем Библиотекарям, так как для каждого из них CSRF токен будет уникальным.</p> + +<p>Защита Django от CSRF атак по умолчанию включена. Вам всегда следует использовать тег<code>{% csrf_token %}</code> в ваших формах и использовать <code>POST</code> для запросов, которые могут изменить или добавить данные в вашу базу данных.</p> + +<h3 id="Другие_атаки">Другие атаки</h3> + +<p>Django так же предоставляет защиту от других видов атак ( демонстрация большинства из которых была бы сложна новичкам для понимания и не слишком полезна ):</p> + +<dl> + <dt>Защита от SQL инъекции</dt> + <dd>Уязвимость SQL инъекции позволяет атакующему выполнить произвольный SQL код в базе данных и получить доступ к данным (прочитать, отредактировать и изменить) независимо от текущих прав доступа пользователя. В большинстве случаев вы будете получать доступ к данным базы данных, используя сущности queryset/model Django. Используя их для генерации SQL запросов, вы получите корректно сформированный и экранированный запрос для выбранной базы данных. Если вам необходимо писать "сырые" запросы, вам так же нужно будет продумать защиту от инъекций.</dd> + <dt><span class="ILfuVd yZ8quc">Защита от Кликджекинга</span></dt> + <dd>В данном виде атак атакующий перехватывает ввод на видимом слое страницы и перенаправляет их на скрытый слой под ним. Этот метод может быть использован к примеру для отображения официального сайта банка, с перехватом данных для входа в невидимом <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe" title="The HTML Inline Frame Element (<iframe>) represents a nested browsing context, effectively embedding another HTML page into the current page. In HTML 4.01, a document may contain a head and a body or a head and a frameset, but not both a body and a frameset. However, an <iframe> can be used within a normal document body. Each browsing context has its own session history and active document. The browsing context that contains the embedded content is called the parent browsing context. The top-level browsing context (which has no parent) is typically the browser window."><code><iframe></code></a>, который контролирует атакующий. Django содержит <a href="https://docs.djangoproject.com/en/2.0/ref/clickjacking/#clickjacking-prevention">защиту от кликджекинга</a> в виде <code><a href="https://docs.djangoproject.com/en/2.0/ref/middleware/#django.middleware.clickjacking.XFrameOptionsMiddleware" title="django.middleware.clickjacking.XFrameOptionsMiddleware">промежуточного програмного обеспечения (middleware) X-Frame-Options</a>,</code> который поддерживается браузерами и может запретить отображение страницы внутри <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe" title="The HTML Inline Frame Element (<iframe>) represents a nested browsing context, effectively embedding another HTML page into the current page. In HTML 4.01, a document may contain a head and a body or a head and a frameset, but not both a body and a frameset. However, an <iframe> can be used within a normal document body. Each browsing context has its own session history and active document. The browsing context that contains the embedded content is called the parent browsing context. The top-level browsing context (which has no parent) is typically the browser window."><code><iframe></code></a>.</dd> + <dt>SSL/HTTPS</dt> + <dd>SSL/HTTPS может быть использован на веб-сервере для шифрования всего трафика между сервером и пользователем, включая данные входа, которые иначе будут отправлятся как обычный текст (который сможет прочитать любой перехвативший запрос человек). Использование HTTPS высоко рекомендовано. Если используется HTTPS, Django позволяет использовать следующие методы защиты:</dd> +</dl> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_PROXY_SSL_HEADER"><code>SECURE_PROXY_SSL_HEADER</code></a> может быть использовано для проверки что всегда используется безопасное подключение, даже если данные поступают из прокси, использующего протокол отличный от HTTP.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_SSL_REDIRECT"><code>SECURE_SSL_REDIRECT</code></a> используется для перенаправления всех запросов с HTTP на HTTPS.</li> + <li>Используйте <a href="https://docs.djangoproject.com/en/2.0/ref/middleware/#http-strict-transport-security">HTTP Strict Transport Security</a> (HSTS). Этот HTTP заголовок информирует браузер о том, что все последующие запросы должны всегда использовать HTTPS. Совместно с перенаправлением HTTP запросов на HTTPS, эта опция позволяет обеспечить использование HTTPS в каждом запросе. HSTS может так же быть настроен опциями <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_HSTS_SECONDS"><code>SECURE_HSTS_SECONDS</code></a> и <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_HSTS_INCLUDE_SUBDOMAINS"><code>SECURE_HSTS_INCLUDE_SUBDOMAINS</code></a> или на веб-сервере.</li> + <li>Используйте ‘безопасные’ cookies выставив <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SESSION_COOKIE_SECURE"><code>SESSION_COOKIE_SECURE</code></a> и <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-CSRF_COOKIE_SECURE"><code>CSRF_COOKIE_SECURE</code></a> в <code>True</code>. Это позволит обеспечить пересылку данных cookies только через протокол HTTPS.</li> +</ul> + +<dl> + <dt>Валидация заголовка Host</dt> + <dd>Используйте <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-ALLOWED_HOSTS"><code>ALLOWED_HOSTS</code></a> чтобы принимать только запросы от доверенных хостов.</dd> +</dl> + +<p>Так же существует множество других техник защиты и указаний по их использованию. Мы надеемся, что данная статья дала вам понимание, какие техники Django предлагает для обеспечения безопасности. Мы надеемся, что вы продолжите изучение этого вопроса по документации Django.</p> + +<ul> +</ul> + +<h2 id="Подводим_итоги">Подводим итоги</h2> + +<p>Django имеет методы обеспечения защиты от распространенных видов атак, включая XSS и CSRF атаки. В данной статье мы продемонстрировали, как различные виды атак обрабатываются Django на примере нашего приложения <em>LocalLibrary</em>. Мы так же кратко рассмотрели другие виды уязвимостей и методы защиты от них.</p> + +<p>Это было очень краткое погружение в вопрос веб-безопасности. Мы крайне рекомендуем вам прочитать <a href="https://docs.djangoproject.com/en/2.0/topics/security/">Безопасность в Django</a> для более глубокого понимания.</p> + +<p>Следующим и последним шагом в данном руководстве будет выполнение <a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">самостоятельной работы</a>.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/security/">Безопасность в Django</a> (Django docs)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/Security">Веб безопасность</a> (MDN)</li> + <li><a href="/en-US/docs/Web/Security/Securing_your_site">Безопасность вашего сайта</a> (MDN)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/server-side/django/аутентификация/index.html b/files/ru/learn/server-side/django/аутентификация/index.html new file mode 100644 index 0000000000..807db42a90 --- /dev/null +++ b/files/ru/learn/server-side/django/аутентификация/index.html @@ -0,0 +1,688 @@ +--- +title: 'Руководство Django Часть 8: Аутентификация и авторизация пользователя' +slug: Learn/Server-side/Django/Аутентификация +tags: + - Python + - Аутентификация + - Аутентификация django + - Джанго + - Начинающий + - Обучение + - Разграничение доступа + - Руководство + - Сервер + - Статья + - Формы + - на стороне сервера + - сессии +translation_of: Learn/Server-side/Django/Authentication +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</div> + +<p class="summary">В данном руководстве мы продемонстрируем вам систему входа пользователя на ваш сайт используя его собственный аккаунт. Кроме того, мы покажем как реализовать контроль того, что может видеть и делать пользователь, в зависимости от того, залогинен он, или нет, а также имеет ли он соответствующий уровень прав доступа <em>(permissions)</em>. Для того чтобы продемонстрировать все это, мы расширим <a href="https://developer.mozilla.org/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, добавив страницы для входа/выхода, а также страницы просмотра/редактирования книг, специфические для пользователя и персонала.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Завершить изучение предыдущих тем руководства, включая <a href="/ru/docs/Learn/Server-side/Django/Sessions">Руководство Django Часть 7: Работа с сессиями</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понимать как настроить и использовать механизм аутентификации пользователя и разграничений прав доступа.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>Django предоставляет систему аутентификации и авторизации ("permission") пользователя, реализованную на основе фреймворка работы с сессиями, который мы рассматривали в <a href="/ru/docs/Learn/Server-side/Django/Sessions">предыдущей части</a>. Система аутентификации и авторизации позволяет вам проверять учетные данные пользователей и определять какие действия какой пользователь может выполнять. Данный фреймворк включает в себя встроенные модели для <code>Пользователей</code> и <code>Групп</code> (основной способ применения прав доступа для более чем одного пользователя), непосредственно саму систему прав доступа (permissions)/флаги, которые определяют может ли пользователь выполнить задачу, с какой формой и отображением для авторизованых пользователей, а так же получить доступ к контенту с ограниченым доступом.</p> + +<div class="note"> +<p><strong>Примечание</strong>: В соответствии с идеологией Django система аутентификации является очень общей и, таким образом, не предоставляет некоторые возможности, которые присутствуют в других системах веб-аутентификации. Решениями некоторых общих задач занимаются пакеты сторонних разработчиков, например, защита от подбора пароля (через стороннюю библиотеку OAuth).</p> +</div> + +<p>В данном разделе руководства мы покажем вам реализацию аутентификации пользователя на сайте <a href="https://developer.mozilla.org/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, создание страниц входа/выхода, добавления разграничения доступа (permissions) к вашим моделям, а также продемонстрируем контроль за доступом к некоторым страницам. Мы будем использовать аутентификацию/авторизацию для показа пользователям и сотрудникам библиотеки, списков книг, которые были взяты на прокат.</p> + +<p>Система аутентификации является очень гибкой и позволяет вам формировать свои собственные URL-адреса, формы, отображения, а также шаблоны страниц, если вы пожелаете, с нуля, через простой вызов функций соответствующего API для авторизации пользователя. Тем не менее, в данной статье мы будем использовать "встроенные" в Django методы отображений и форм аутентификации, а также методы построения страниц входа и выхода. Нам все еще необходимо создавать шаблоны страниц, но это будет достаточно несложно.</p> + +<p>Мы покажем вам как реализовать разграничение доступа (permissions), а также выполнять соответствующую проверку статусов авторизации и прав доступа, в отображениях, и в шаблонах страниц.</p> + +<h2 id="Подключение_аутентификации">Подключение аутентификации</h2> + +<p>Аутентификация была подключена автоматически когда мы создали <a href="/ru/docs/Learn/Server-side/Django/skeleton_website">скелет сайта</a> (в части 2), таким образом на данный момент вам ничего не надо делать.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Необходимые настройки были выполнены для нас, когда мы создали приложение при помощи команды <code>django-admin startproject</code>. Таблицы базы данных для пользователей и модели авторизации были созданы, когда в первый раз выполнили команду <code>python manage.py migrate</code>.</p> +</div> + +<p>Соответствующие настройки сделаны в параметрах <code>INSTALLED_APPS</code> и <code>MIDDLEWARE</code> файла проекта (<strong>locallibrary/locallibrary/settings.py</strong>), как показано ниже:</p> + +<pre class="brush: python notranslate">INSTALLED_APPS = [ + ... +<strong> 'django.contrib.auth', </strong># Фреймворк аутентификации и моделей по умолчанию. +<strong> 'django.contrib.contenttypes', # </strong>Django контент-типовая система (даёт разрешения, связанные с моделями). + .... + +MIDDLEWARE = [ + ... +<strong> 'django.contrib.sessions.middleware.SessionMiddleware',</strong> # Управление сессиями между запросами + ... +<strong> 'django.contrib.auth.middleware.AuthenticationMiddleware',</strong> # Связывает пользователей, использующих сессии, запросами. + .... +</pre> + +<h2 id="Создание_пользователей_и_групп">Создание пользователей и групп</h2> + +<p>Вы уже создали своего первого пользователя когда мы рассматривали <a href="/ru/docs/Learn/Server-side/Django/Admin_site">Административная панель сайта Django</a> в части 4 (это был суперпользователь, созданный при помощи команды<code> python manage.py createsuperuser</code>). Наш суперпользователь уже авторизован и имеет все необходимые уровни доступа к данным и функциям, таким образом нам необходимо создать тестового пользователя для отработки соответствующей работы сайта. В качестве наиболее быстрого способа, мы будем использовать административную панель сайта для создания соответствующих групп и акканутов <em>locallibrary</em>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете создавать пользователей программно, как показано ниже. Например, вам мог бы подойти данный способ в том случае, если вы разрабатываете интерфейс, который позволяет пользователям создавать их собственные аккаунты (вы не должны предоставлять доступ пользователям к административной панели вашего сайта).</p> + +<pre class="brush: python notranslate">from django.contrib.auth.models import User + +# Создайте пользователя и сохраните его в базе данных +user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword') + +# Обновите поля и сохраните их снова +user.first_name = 'John' +user.last_name = 'Citizen' +user.save() +</pre> +</div> + +<p>Ниже мы создадим группу, а затем пользователя. Несмотря на то, что у нас пока нет никаких разрешений для добавления к нашей библиотеке каких-либо членов, если мы захотим это сделать в будущем, то будет намного проще добавлять их к уже созданной группе, с заданной аутентификацией.</p> + +<p>Запустите сервер разработки и перейдите к административной панели вашего сайта (<a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin/</a>). Залогиньтесь на сайте при помощи параметров (имя пользователя и пароля) аккаунта суперпользователя. Самая "верхняя" страница панели Администратора показывает все наши модели. Для того, чтобы увидеть записи в разделе <strong>Authentication and Authorisation</strong> вы можете нажать на ссылку <strong>Users</strong>, или <strong>Groups</strong>.</p> + +<p><img alt="Admin site - add groups or users" src="https://mdn.mozillademos.org/files/14091/admin_authentication_add.png" style="border-style: solid; border-width: 1px; display: block; height: 364px; margin: 0px auto; width: 661px;"></p> + +<p>В первую очередь, в качестве нового члена нашего сайта, давайте создадим новую группу.</p> + +<ol> + <li>Нажмите на кнопку <strong>Add</strong> <strong>(Добавить)</strong> (рядом с Group) и создайте новую <em>группу</em>; для данной группы введите <strong>Name (Имя) </strong>"Library Members".<img alt="Admin site - add group" src="https://mdn.mozillademos.org/files/14093/admin_authentication_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 561px; margin: 0px auto; width: 800px;"></li> + <li>Для данной группы не нужны какие-либо разрешения, поэтому мы просто нажимаем кнопку <strong>SAVE (Сохранить)</strong> (вы перейдете к списку групп).</li> +</ol> + +<p>Теперь давайте создадим пользователя:</p> + +<ol> + <li>Перейдите обратно на домашнюю страницу административной панели</li> + <li>Для перехода к диалогу добавления пользователя нажмите на кнопку <strong>Add</strong>, соответствующую строке <em>Users (Пользователи)</em>.<img alt="Admin site - add user pt1" src="https://mdn.mozillademos.org/files/14095/admin_authentication_add_user_prt1.png" style="border-style: solid; border-width: 1px; display: block; height: 409px; margin: 0px auto; width: 800px;"></li> + <li>Введите соответствующие <strong>Username</strong> (имя пользователя) и <strong>Password</strong>/<strong>Password confirmation (пароль/подтверждение пароля)</strong> для вашего тестового пользователя</li> + <li>Нажмите <strong>SAVE</strong> для завершения процесса создания пользователя.<br> + <br> + Административная часть сайта создаст нового пользователя и немедленно перенаправит вас на страницу <em>Change user (Изменение параметров пользователя)</em> где вы можете, соответственно, изменить ваш <strong>username</strong>, а кроме того добавить информацию для дополнительных полей модели User. Эти поля включают в себя имя пользователя, фамилию, адрес электронной почты, статус пользователя, а также соответствующие параметры доступа (может быть установлен только флаг <strong>Active</strong>). Ниже вы можете определить группу для пользователя и необходимые параметры доступа, а кроме того, вы можете увидеть важные даты, относящиеся к пользователю (дату подключения к сайту и дату последнего входа).<img alt="Admin site - add user pt2" src="https://mdn.mozillademos.org/files/14097/admin_authentication_add_user_prt2.png" style="border-style: solid; border-width: 1px; display: block; height: 635px; margin: 0px auto; width: 800px;"></li> + <li>В разделе <em>Groups</em>, из списка <em>Доступные группы</em> выберите группу <strong>Library Member</strong>, а затем переместите ее в блок "Выбранные группы" (нажмите <strong>стрелку-"направо"</strong>, находящуюся между блоками).<img alt="Admin site - add user to group" src="https://mdn.mozillademos.org/files/14099/admin_authentication_user_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 414px; margin: 0px auto; width: 933px;"></li> + <li>Больше нам не нужно здесь нечего делать, просто нажмите "Save"(Сохранить), и вы вернетесь к списку созданых пользователей.</li> +</ol> + +<p>Вот и все! Теперь у вас есть учетная запись «обычного члена библиотеки», которую вы сможете использовать для тестирования (как только добавим страницы, чтобы пользователи могли войти в систему).</p> + +<div class="note"> +<p><strong>Note</strong>: Попробуйте создать другого пользователя, например "Библиотекаря". Так же создайте группу "Библиотекарей" и добавьте туда своего только что созданного библиотекаря</p> +</div> + +<h2 id="Настройка_представлений_проверки">Настройка представлений проверки</h2> + +<p>Django предоставляет почти все, что нужно для создания страниц аутентификации входа, выхода из системы и управления паролями из коробки. Это включает в себя url-адреса, представления (views) и формы,но не включает шаблоны — мы должны создать свой собственный шаблон!</p> + +<p>В этом разделе мы покажем, как интегрировать систему по умолчанию в Сайт LocalLibrary и создать шаблоны. Мы поместим их в основные URL проекта.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Вы не должны использовать этот код, но вполне вероятно, что вы хотите, потому что это делает вещи намного проще. Вам почти наверняка потребуется изменить код обработки формы, если вы измените свою модель пользователя (сложная тема!) но даже в этом случае вы все равно сможете использовать функции просмотра запасов.</p> +</div> + +<div class="note"> +<p><strong>Заметка: </strong>В этом случае мы могли бы разумно поместить страницы аутентификации, включая URL-адреса и шаблоны, в наше приложение каталога. Однако, если бы у нас было несколько приложений, было бы лучше отделить это общее поведение входа в систему и иметь его доступным на всем сайте, так что это то, что мы показали здесь!</p> +</div> + +<h3 id="Проектирование_URLs">Проектирование URLs</h3> + +<p>Добавьте следующее в нижней части проекта urls.py файл (<strong>locallibrary/locallibrary/urls.py</strong>) файл:</p> + +<pre class="brush: python notranslate">#Add Django site authentication urls (for login, logout, password management) +urlpatterns += [ + path('accounts/', include('django.contrib.auth.urls')), +] +</pre> + +<p>Перейдите по <a href="http://127.0.0.1:8000/accounts/">http://127.0.0.1:8000/accounts/</a> URL (обратите внимание на косую черту!), Django покажет ошибку, что он не смог найти этот URL, и перечислить все URL, которые он пытался открыть. Из этого Вы можете увидеть URL-адреса, которые будут работать, например:</p> + +<div class="note"> +<p><span id="result_box" lang="ru"><span>Примечание. Использование вышеуказанного метода добавляет следующие URL-адреса с именами в квадратных скобках, которые могут использоваться для изменения сопоставлений URL-адресов.</span> <span>Вам не нужно реализовывать что-либо еще - приведенное выше сопоставление URL-адресов автоматически отображает указанные ниже URL-адреса.</span></span></p> +</div> + +<div class="note"> +<pre class="brush: python notranslate">accounts/ login/ [name='login'] +accounts/ logout/ [name='logout'] +accounts/ password_change/ [name='password_change'] +accounts/ password_change/done/ [name='password_change_done'] +accounts/ password_reset/ [name='password_reset'] +accounts/ password_reset/done/ [name='password_reset_done'] +accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm'] +accounts/ reset/done/ [name='password_reset_complete']</pre> +</div> + +<p><span id="result_box" lang="ru"><span>Теперь попробуйте перейти к URL-адресу входа (<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>).</span> <span>Это приведет к сбою снова, но с ошибкой, сообщающей вам, что нам не хватает требуемого шаблона (registration / login.html) в пути поиска шаблона.</span> <span>Вы увидите следующие строки, перечисленные в желтом разделе вверху:</span></span></p> + +<pre class="brush: python notranslate">Exception Type: TemplateDoesNotExist +Exception Value: <strong>registration/login.html</strong></pre> + +<p><span id="result_box" lang="ru"><span>Следующий шаг - создать каталог регистрации в пути поиска, а затем добавить файл login.html.</span></span></p> + +<h3 id="Каталог_шаблонов">Каталог шаблонов</h3> + +<p><span id="result_box" lang="ru"><span>URL-адреса (и неявные представления), которые мы только что добавили, ожидают найти связанные с ними шаблоны в каталоге / регистрации / где-то в пути поиска шаблонов.</span><br> + <br> + <span>Для этого сайта мы разместим наши HTML-страницы в каталоге <strong>templates / registration /</strong>.</span> <span>Этот каталог должен находиться в корневом каталоге проекта, то есть в том же каталоге, что и в каталоге и папках <strong>locallibrary</strong>).</span> <span>Создайте эти папки сейчас.</span></span></p> + +<div class="note"> +<p><strong>Примечание:</strong> Ваша структура папок теперь должна выглядеть как показано внизу:<br> + locallibrary (django project folder)<br> + |_catalog<br> + |_locallibrary<br> + |_templates <strong>(new)</strong><br> + |_registration</p> +</div> + +<p>Чтобы сделать эти директории видимыми для загрузчика шаблонов (<span id="result_box" lang="ru"><span>т. е. помещать этот каталог в путь поиска шаблона</span></span>) откройте настройки проекта (<strong>/locallibrary/locallibrary/settings.py</strong>), и обновите в секции <code>TEMPLATES</code> строку <code>'DIRS'</code> как показано.</p> + +<pre class="brush: python notranslate">TEMPLATES = [ + { + ... +<strong> </strong><strong>'DIRS': [os.path.join(BASE_DIR, 'templates')],</strong> + 'APP_DIRS': True, + ... +</pre> + +<h3 id="Шаблон_аутентификации">Шаблон <span id="result_box" lang="ru"><span>аутентификации</span></span></h3> + +<div class="warning"> +<p><strong>Важно</strong>: <span id="result_box" lang="ru"><span>Шаблоны аутентификации, представленные в этой статье, являются очень простой / слегка измененной версией шаблонов логина демонстрации Django.</span> <span>Возможно, вам придется настроить их для собственного использования!</span></span></p> +</div> + +<p>Создайте новый HTML файл, названный /<strong>locallibrary/templates/registration/login.html</strong>. <span class="short_text" id="result_box" lang="ru"><span>дайте ему следующее содержание</span></span>:</p> + +<pre class="brush: html line-numbers language-html notranslate">{% extends "base_generic.html" %} + +{% block content %} + +{% if form.errors %} + <p>Your username and password didn't match. Please try again.</p> +{% endif %} +<code class="language-html"> +{% if next %} + {% if user.is_authenticated %} + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>Your account doesn't have access to this page. To proceed, + please login with an account that has access.<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span> + {% else %} + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>Please login to see this page.<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span> + {% endif %} +{% endif %} + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>form</span> <span class="attr-name token">method</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>post<span class="punctuation token">"</span></span> <span class="attr-name token">action</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>{% url 'login' %}<span class="punctuation token">"</span></span><span class="punctuation token">></span></span> +{% csrf_token %} +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>table</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>tr</span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>td</span><span class="punctuation token">></span></span>\{{ form.username.label_tag }}<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>td</span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>td</span><span class="punctuation token">></span></span>\{{ form.username }}<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>td</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>tr</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>tr</span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>td</span><span class="punctuation token">></span></span>\{{ form.password.label_tag }}<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>td</span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>td</span><span class="punctuation token">></span></span>\{{ form.password }}<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>td</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>tr</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>table</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>input</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>submit<span class="punctuation token">"</span></span> <span class="attr-name token">value</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>login<span class="punctuation token">"</span></span> <span class="punctuation token">/></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>input</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>hidden<span class="punctuation token">"</span></span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>next<span class="punctuation token">"</span></span> <span class="attr-name token">value</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>\{{ next }}<span class="punctuation token">"</span></span> <span class="punctuation token">/></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>form</span><span class="punctuation token">></span></span> + +{# Assumes you setup the password_reset view in your URLconf #} +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>a</span> <span class="attr-name token">href</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>{% url 'password_reset' %}<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>Lost password?<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>a</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span> + +{% endblock %}</code></pre> + +<p id="sect1"><span id="result_box" lang="ru"><span>Этот шаблон имеет сходство с тем, что мы видели раньше - он расширяет наш базовый шаблон и переопределяет блок контента.</span> <span>Остальная часть кода - это довольно стандартный код обработки формы, о котором мы поговорим в следующем учебном пособии.</span> <span>Все, что вам нужно знать, это показ формы, в которой вы можете ввести свое имя пользователя и пароль, а если вы введете недопустимые значения, вам будет предложено ввести правильные значения, когда страница обновится.</span></span></p> + +<p>Перейдите на страницу входа (<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>) когда вы сохраните свой шаблон, и вы должны увидеть что-то наподобие этого:</p> + +<p><img alt="Library login page v1" src="https://mdn.mozillademos.org/files/14101/library_login.png" style="border-style: solid; border-width: 1px; display: block; height: 173px; margin: 0px auto; width: 441px;"></p> + +<p><span id="result_box" lang="ru"><span>Если ваша попытка войти в систему будет успешной, вы будете перенаправлены на другую страницу (по умолчанию это будет <a href="http://127.0.0.1:8000/accounts/profile/">http://127.0.0.1:8000/accounts/profile/</a>).</span> <span>Проблема здесь в том, что по умолчанию Django ожидает, что после входа в систему вы захотите перейти на страницу профиля, что может быть или не быть.</span> <span>Поскольку вы еще не определили эту страницу, вы получите еще одну ошибку!</span><br> + <br> + <span>Откройте настройки проекта (<strong>/locallibrary/locallibrary/settings.py</strong>) и добавьте текст ниже.</span> <span>Теперь, когда вы входите в систему, вы по умолчанию должны перенаправляться на домашнюю страницу сайта.</span></span></p> + +<pre class="brush: python notranslate"># Redirect to home URL after login (Default redirects to /accounts/profile/) +LOGIN_REDIRECT_URL = '/' +</pre> + +<h3 id="Шаблон_выхода">Шаблон выхода</h3> + +<p><span id="result_box" lang="ru"><span>Если вы перейдете по URL-адресу выхода (<a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a>), то увидите странное поведение - </span></span>ваш пользователь наверняка выйдет из системы<span lang="ru"><span>, </span></span>но вы попадете на страницу выхода администратора<span lang="ru"><span>.</span> </span>Это не то, что вам нужно, хотя бы потому, что ссылка для входа на этой странице приведет вас к экрану входа в систему администратора.<span lang="ru"><span> (и это доступно только для пользователей, у которых есть разрешение <code>is_staff</code>).</span><br> + <br> + <span>Создайте и откройте <strong>/locallibrary/templates/registration/logged_out.html</strong>.</span> <span>Скопируйте текст ниже:</span></span></p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} +<p>Logged out!</p> + +<a href="{% url 'login'%}">Click here to login again.</a> +{% endblock %}</pre> + +<p><span id="result_box" lang="ru"><span>Этот шаблон очень прост.</span> <span>Он просто отображает сообщение, информирующее вас о том, что вы вышли из системы, и предоставляет ссылку, которую вы можете нажать, чтобы вернуться на экран входа в систему.</span> <span>Если вы снова перейдете на страницу выхода из системы, вы увидите эту страницу:</span></span></p> + +<p><img alt="Library logout page v1" src="https://mdn.mozillademos.org/files/14103/library_logout.png" style="border-style: solid; border-width: 1px; display: block; height: 169px; margin: 0px auto; width: 385px;"></p> + +<h3 id="Шаблон_сброса_пароля">Шаблон сброса пароля</h3> + +<p><span id="result_box" lang="ru"><span>Система сброса пароля по умолчанию использует электронную почту, чтобы отправить пользователю ссылку на сброс.</span> <span>Вам необходимо создать формы, чтобы получить адрес электронной почты пользователя, отправить электронное письмо, разрешить им вводить новый пароль и отметить, когда весь процесс будет завершен.</span><br> + <br> + <span>В качестве отправной точки можно использовать следующие шаблоны.</span></span></p> + +<h4 id="Форма_сброса_пароля">Форма сброса пароля</h4> + +<p><span id="result_box" lang="ru"><span>Это форма, используемая для получения адреса электронной почты пользователя (для отправки пароля для сброса пароля).</span> <span>Создайте <strong>/locallibrary/templates/registration/password_reset_form.html</strong> и дайте ему следующее содержание:</span></span></p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} +{% block content %} + +<form action="" method="post">{% csrf_token %} + {% if form.email.errors %} \{{ form.email.errors }} {% endif %} + <p>\{{ form.email }}</p> + <input type="submit" class="btn btn-default btn-lg" value="Reset password" /> +</form> + +{% endblock %} +</pre> + +<h4 id="Сброс_пароля">Сброс пароля</h4> + +<p>Эта форма отображается после того, как ваш адрес электронной почты будет собран. Создайте <strong>/locallibrary/templates/registration/password_reset_done.html</strong>, и дайте ему следующее содержание:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} +{% block content %} +<p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p> +{% endblock %} +</pre> + +<h4 id="Сброс_пароля_по_email">Сброс пароля по email</h4> + +<p>Этот шаблон предоставляет текст электронной почты HTML, содержащий ссылку на сброс, которую мы отправим пользователям. Создайте /locallibrary/templates/registration/password_reset_email.html и дайте ему следующее содержание:</p> + +<pre class="brush: html notranslate">Someone asked for password reset for email \{{ email }}. Follow the link below: +\{{ protocol}}://\{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} +</pre> + +<h4 id="Подтверждение_на_сброс_пароля">Подтверждение на сброс пароля</h4> + +<p>На этой странице вы вводите новый пароль после нажатия ссылки в электронном письме с возвратом пароля. Создайте /locallibrary/templates/registration/password_reset_confirm.html и дайте ему следующее содержание:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + + {% if validlink %} + <p>Please enter (and confirm) your new password.</p> + <form action="" method="post"> + <code class="language-html">{% csrf_token %}</code> + <table> + <tr> + <td>\{{ form.new_password1.errors }} + <label for="id_new_password1">New password:</label></td> + <td>\{{ form.new_password1 }}</td> + </tr> + <tr> + <td>\{{ form.new_password2.errors }} + <label for="id_new_password2">Confirm password:</label></td> + <td>\{{ form.new_password2 }}</td> + </tr> + <tr> + <td></td> + <td><input type="submit" value="Change my password" /></td> + </tr> + </table> + </form> + {% else %} + <h1>Password reset failed</h1> + <p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p> + {% endif %} + +{% endblock %} +</pre> + +<h4 id="Сброс_пароля_завершен">Сброс пароля завершен</h4> + +<p>Это последний шаблон сброса пароля, который отображается, чтобы уведомить вас о завершении сброса пароля. Создайте /locallibrary/templates/registration/password_reset_complete.html и дайте ему следующее содержание:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} +{% block content %} + +<h1>The password has been changed!</h1> +<p><a href="{% url 'login' %}">log in again?</a></p> + +{% endblock %}</pre> + +<h3 id="Тестирование_новых_страниц_аутентификации">Тестирование новых страниц аутентификации</h3> + +<p>Теперь, когда вы добавили конфигурацию URL и создали все эти шаблоны, теперь страницы аутентификации должны работать! Вы можете протестировать новые страницы аутентификации, попытавшись войти в систему, а затем выйдите из учетной записи суперпользователя, используя эти URL-адреса:</p> + +<ul> + <li><a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a></li> + <li><a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a></li> +</ul> + +<p>Вы сможете проверить функцию сброса пароля по ссылке на странице входа. <strong>Имейте в виду, что Django отправляет только сбросные электронные письма на адреса (пользователи), которые уже хранятся в его базе данных!</strong></p> + +<div class="note"> +<p><strong>Заметка</strong>: Система сброса пароля требует, чтобы ваш сайт поддерживал электронную почту, что выходит за рамки этой статьи, поэтому эта часть <strong>еще не будет работать.</strong> Чтобы разрешить тестирование, поместите следующую строку в конец файла settings.py. Это регистрирует любые письма, отправленные на консоль (чтобы вы могли скопировать ссылку на сброс пароля с консоли).</p> + +<pre class="brush: python notranslate">EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +</pre> + +<p>Для получения дополнительной информации см. <a href="https://docs.djangoproject.com/en/2.0/topics/email/">Отправка email</a> (Django docs).</p> +</div> + +<h2 id="Тестирование_проверки_подлинности_пользователей">Тестирование проверки подлинности пользователей</h2> + +<p>В этом разделе мы рассмотрим, что мы можем сделать, чтобы выборочно контролировать контент, который видят пользователи, на основе того, вошли ли они в систему или нет.</p> + +<h3 id="Тестирование_в_шаблонах">Тестирование в шаблонах</h3> + +<p>Вы можете получить информацию о текущем зарегистрированном пользователе в шаблонах с переменной шаблона \{{user}} (это добавляется в контекст шаблона по умолчанию при настройке проекта, как и в нашем скелете).</p> + +<p>Обычно вы сначала проверяете переменную шаблона \{{user.is_authenticated}}, чтобы определить, имеет ли пользователь право видеть конкретный контент. Чтобы продемонстрировать это, мы обновим нашу боковую панель, чтобы отобразить ссылку «Вход», если пользователь вышел из системы, и ссылку «Выход», если он вошёл в систему.</p> + +<p>Откройте базовый шаблон (/locallibrary/catalog/templates/base_generic.html) и скопируйте следующий текст в sidebar блок непосредственно перед тегом шаблона endblock.</p> + +<pre class="brush: python notranslate"> <ul class="sidebar-nav"> + + ... + + <strong>{% if user.is_authenticated %}</strong> + <li>User: <strong>\{{ user.get_username }}</strong></li> + <li><a href="{% url 'logout'%}?next=\{{request.path}}">Logout</a></li> + <strong>{% else %}</strong> + <li><a href="{% url 'login'%}?next=\{{request.path}}">Login</a></li> + <strong>{% endif %} </strong> + </ul></pre> + +<p>Как вы можете видеть, мы используем теги шаблона if-else-endif для условного отображения текста на основе того, является ли \{{user.is_authenticated}} истинным. Если пользователь аутентифицирован, мы знаем, что у нас есть действительный пользователь, поэтому мы вызываем \{{user.get_username}}, чтобы отобразить их имя.</p> + +<p>Мы создаем URL-адрес для входа и выхода из системы, используя тег шаблона URL-адреса и имена соответствующих конфигураций URLs. Также обратите внимание на то, как мы добавили <code>?next=\{{request.path}}</code> в конец URLs. Это означает, что следующий URL-адрес содержит адрес (URL) текущей страницы, в конце связанного URL-адреса. После того, как пользователь успешно выполнил вход в систему, представления будут использовать значение "<code>next</code>" чтобы перенаправить пользователя обратно на страницу, где они сначала нажали ссылку входа / выхода из системы.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Попробуйте! Если вы находитесь на главной странице и вы нажимаете «Вход / Выход» на боковой панели, то после завершения операции вы должны вернуться на ту же страницу.</p> +</div> + +<h3 id="Тестирование_в_представлениях">Тестирование в представлениях</h3> + +<p>Если вы используете функциональные представления, самым простым способом ограничить доступ к вашим функциям является применение <code>login_required</code> декоратор к вашей функции просмотра, как показано ниже. Если пользователь вошел в систему, ваш код просмотра будет выполняться как обычно. Если пользователь не вошел в систему, это перенаправит URL-адрес входа, определенный в настройках проекта. (<code>settings.LOGIN_URL</code>), передав текущий абсолютный путь в качестве <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">next</span></font> параметра URL. Если пользователю удастся войти в систему, они будут возвращены на эту страницу, но на этот раз аутентифицированы.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.decorators import login_required + +@login_required +def my_view(request): + ...</pre> + +<div class="note"> +<p><strong>Заметка:</strong> Вы можете сделать то же самое вручную, путём тестирования <code>request.user.is_authenticated</code>, но декоратор намного удобнее!</p> +</div> + +<p>Аналогичным образом, самый простой способ ограничить доступ к зарегистрированным пользователям в ваших представлениях на основе классов - это производные от <code>LoginRequiredMixin</code>. Вы должны объявить этот mixin сначала в списке суперкласса, перед классом основного представления.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin + +class MyView(LoginRequiredMixin, View): + ...</pre> + +<p>Это имеет такое же поведение при переадресации, что и <code>login_required</code> декоратор. Вы также можете указать альтернативное местоположение для перенаправления пользователя, если он не аутентифицирован (<code>login_url</code>), и имя параметра URL вместо "<code>next</code>" , чтобы вставить текущий абсолютный путь (<code>redirect_field_name</code>).</p> + +<pre class="brush: python notranslate">class MyView(LoginRequiredMixin, View): + login_url = '/login/' + redirect_field_name = 'redirect_to' +</pre> + +<p>Для получения дополнительной информации ознакомьтесь с <a href="https://docs.djangoproject.com/en/1.10/topics/auth/default/#limiting-access-to-logged-in-users">Django docs here</a>.</p> + +<h2 id="Пример_-_перечисление_книг_текущего_пользователя">Пример - перечисление книг текущего пользователя</h2> + +<p>Теперь, когда мы знаем, как ограничить страницу определенному пользователю, создайте представление о книгах, которые заимствовал текущий пользователь.</p> + +<p>К сожалению, у нас пока нет возможности пользователям использовать книги! Поэтому, прежде чем мы сможем создать список книг, мы сначала расширим <code>BookInstance</code> модель для поддержки концепции заимствования и использования приложения Django Admin для заимствования ряда книг нашему тестовому пользователю.</p> + +<h3 id="Модели">Модели</h3> + +<p>Прежде всего, мы должны предоставить пользователям возможность кредита на <code>BookInstance</code> (у нас уже есть <code>status</code> и <code>due_back</code> дата, но у нас пока нет связи между этой моделью и пользователем. Мы создадим его с помощью поля <code>ForeignKey</code> (один ко многим). Нам также нужен простой механизм для проверки того, просрочена ли заемная книга.</p> + +<p>Откройте <strong>catalog/models.py</strong>, и импортируйте модель <code>User</code> из <code>django.contrib.auth.models</code> (добавьте это чуть ниже предыдущей строки импорта в верхней части файла, так <code>User</code> доступен для последующего кода, что позволяет использовать его):</p> + +<pre class="brush: python notranslate">from django.contrib.auth.models import User +</pre> + +<p>Затем добавьте поле <code>borrower</code> в модель <code>BookInstance</code>:</p> + +<pre class="brush: python notranslate">borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) +</pre> + +<p>Пока мы здесь, давайте добавим свойство, которое мы можем вызвать из наших шаблонов, чтобы указать, просрочен ли конкретный экземпляр книги. Хотя мы могли бы рассчитать это в самом шаблоне, использование свойства, как показано ниже, будет намного более эффективным. Добавьте это где-нибудь в верхней части файла:</p> + +<pre class="syntaxbox notranslate">from datetime import date</pre> + +<p>Теперь добавьте следующее определение свойства внутри класса BookInstance:</p> + +<pre class="brush: python notranslate">@property +def is_overdue(self): + if self.due_back and date.today() > self.due_back: + return True + return False</pre> + +<div class="note"> +<p><strong>Примечание.</strong> Сначала мы проверим, является ли <code>due_back</code> пустым, прежде чем проводить сравнение. Пустое поле <code>due_back</code> заставило Django выкидывать ошибку, а не показывать страницу: пустые значения не сопоставимы. Это не то, что мы хотели бы, чтобы наши пользователи испытывали!</p> +</div> + +<p>Теперь, когда мы обновили наши модели, нам нужно будет внести новые изменения в проект, а затем применить эти миграции:</p> + +<pre class="brush: bash notranslate">python3 manage.py makemigrations +python3 manage.py migrate +</pre> + +<h3 id="Admin">Admin</h3> + +<p>Теперь откройте каталог <strong>catalog/admin.py</strong>, и добавьте поле <code>borrower</code> в класс <code>BookInstanceAdmin</code> , как в <code>list_display</code> , так и в полях <code>fieldsets</code> , как показано ниже. Это сделает поле видимым в разделе Admin, так что мы можем при необходимости назначить <code>User</code> в <code>BookInstance</code>.</p> + +<pre class="brush: python notranslate">@admin.register(BookInstance) +class BookInstanceAdmin(admin.ModelAdmin): + list_display = ('book', 'status'<strong>, 'borrower'</strong>, 'due_back', 'id') + list_filter = ('status', 'due_back') + + fieldsets = ( + (None, { + 'fields': ('book','imprint', 'id') + }), + ('Availability', { + 'fields': ('status', 'due_back'<strong>,'borrower'</strong>) + }), + )</pre> + +<h3 id="Займите_несколько_книг">Займите несколько книг</h3> + +<p>Теперь, когда возможно кредитовать книги конкретному пользователю, зайдите и заработайте на нескольких записей в <code>BookInstance</code>. Установите <code>borrowed</code> поле вашему тестовому пользователю, сделайте <code>status</code> «В займе» и установите сроки оплаты как в будущем, так и в прошлом.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Мы не будем описывать процесс, так как вы уже знаете, как использовать Admin сайт!</p> +</div> + +<h3 id="Займ_в_представлении">Займ в представлении</h3> + +<p>Теперь мы добавим представление для получения списка всех книг, которые были предоставлены текущему пользователю. Мы будем использовать один и тот же общий класс, с которым мы знакомы, но на этот раз мы также будем импортировать и выводить из <code>LoginRequiredMixin</code>, так что только вошедший пользователь сможет вызвать это представление. Мы также решили объявить <code>template_name</code>, вместо того, чтобы использовать значение по умолчанию, потому что у нас может быть несколько разных списков записей BookInstance, с разными представлениями и шаблонами.</p> + +<p>Добавьте следующее в catalog/views.py:</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin + +class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView): + """ + Generic class-based view listing books on loan to current user. + """ + model = BookInstance + template_name ='catalog/bookinstance_list_borrowed_user.html' + paginate_by = 10 + + def get_queryset(self): + return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')</pre> + +<p>Чтобы ограничить наш запрос только объектами BookInstance для текущего пользователя, мы повторно реализуем <code>get_queryset()</code>, как показано выше. Обратите внимание, что "o" это сохраненный код для "on loan" и мы сортируем по дате <code>due_back</code>, чтобы сначала отображались самые старые элементы.</p> + +<h3 id="URL-адрес_для_заёмных_книг">URL-адрес для заёмных книг</h3> + +<p>Теперь откройте <strong>/catalog/urls.py</strong> и добавьте <code>url()</code> , указывая на приведённое выше представление (вы можете просто скопировать текст ниже в конец файла).</p> + +<pre class="brush: python notranslate">urlpatterns += [ + url(r'^mybooks/$', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'), +]</pre> + +<h3 id="Шаблон_для_заёмных_книг">Шаблон для заёмных книг</h3> + +<p>Теперь все, что нам нужно сделать для этой страницы, - это добавить шаблон. Сначала создайте файл шаблона <strong>/catalog/templates/catalog/bookinstance_list_borrowed_user.html</strong> и дайте ему следующее содержание:</p> + +<pre class="brush: python notranslate">{% extends "base_generic.html" %} + +{% block content %} + <h1>Borrowed books</h1> + + {% if bookinstance_list %} + <ul> + + {% for bookinst in bookinstance_list %} + <li class="{% if bookinst.is_overdue %}text-danger{% endif %}"> + <a href="{% url 'book-detail' bookinst.book.pk %}">\{{bookinst.book.title}}</a> (\{{ bookinst.due_back }}) + </li> + {% endfor %} + </ul> + + {% else %} + <p>There are no books borrowed.</p> + {% endif %} +{% endblock %}</pre> + +<p>Этот шаблон очень похож на тот, который мы создали ранее для объектов <code>Book</code> и <code>Author</code>. Единственное, что «новое» здесь, это то, что мы проверяем метод, который мы добавили в модель <code>(bookinst.is_overdue</code>) с целью использовать его для изменения цвета просроченных предметов.</p> + +<p>Когда сервер разработки запущен, вы должны теперь иметь возможность просматривать список для зарегистрированного пользователя в своем браузере по адресу <a href="http://127.0.0.1:8000/catalog/mybooks/">http://127.0.0.1:8000/catalog/mybooks/</a>. Попробуйте это, когда ваш пользователь войдет в систему и выйдет из системы (во втором случае вы должны быть перенаправлены на страницу входа в систему).</p> + +<h3 id="Добавить_список_на_боковую_панель">Добавить список на боковую панель</h3> + +<p>Последний шаг - добавить ссылку на эту новую страницу в sidebar. Мы поместим это в тот же раздел, где мы покажем другую информацию для зарегистрированного пользователя.</p> + +<p>Откройте базовый шаблон (<strong>/locallibrary/catalog/templates/base_generic.html</strong>) и добавьте выделенную строку из sidebar, как показано на рисунке.</p> + +<pre class="brush: python notranslate"> <ul class="sidebar-nav"> + {% if user.is_authenticated %} + <li>User: \{{ user.get_username }}</li> +<strong> <li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li></strong> + <li><a href="{% url 'logout'%}?next=\{{request.path}}">Logout</a></li> + {% else %} + <li><a href="{% url 'login'%}?next=\{{request.path}}">Login</a></li> + {% endif %} + </ul> +</pre> + +<h3 id="На_что_это_похоже">На что это похоже?</h3> + +<p>Когда любой пользователь войдет в систему, он будет видеть ссылку «Мной позаимствовано (<em>My Borrowed)</em>» в боковой колонке, и список книг, показанных ниже (первая книга не имеет установленной даты, что является ошибкой, которую мы надеемся исправить в более позднем уроке!).</p> + +<p><img alt="Library - borrowed books by user" src="https://mdn.mozillademos.org/files/14105/library_borrowed_by_user.png" style="border-style: solid; border-width: 1px; display: block; height: 215px; margin: 0px auto; width: 530px;"></p> + +<h2 id="Права_доступа">Права доступа</h2> + +<p>Права доступа связаны с моделями и определяют операции, которые могут выполняться на экземпляре модели самим пользователем, у которого есть разрешение. По умолчанию Django автоматически дает <em>добавить</em>, <em>изменить</em>, и <em>удалить</em> разрешения у всех моделей, которые позволяют пользователям с правом доступа выполнять связанные действия через администратора сайта. Вы можете определить свои собственные разрешения для моделей и предоставить их конкретным пользователям. Вы также можете изменить разрешения, связанные с разными экземплярами одной и той же модели. Тестирование разрешений в представлениях и шаблонах очень похоже на тестирование по статусу аутентификации (фактически, тестирование прав доступа также проверяет аутентификацию).</p> + +<h3 id="Модели_2">Модели</h3> + +<p>Определение разрешений выполняется в разделе моделей "<code>class Meta</code>" , используется <code>permissions</code> поле. Вы можете указать столько разрешений, сколько необходимо в кортеже, причем каждое разрешение определяется во вложенном кортеже, содержащем имя разрешения и отображаемое значение разрешения. Например, мы можем определить разрешение, позволяющее пользователю отметить, что книга была возвращена, как показано здесь:</p> + +<pre class="brush: python notranslate">class BookInstance(models.Model): + ... + class Meta: + ... +<strong> permissions = (("can_mark_returned", "Set book as returned"),) </strong> </pre> + +<p>Затем мы могли бы назначить разрешение группе «Библиотекарь» (Librarian) на сайте администратора.</p> + +<p>Откройте <strong>catalog/models.py</strong>, и добавьте разрешение, как показано выше. Вам нужно будет повторно выполнить миграцию (вызвав <code>python3 manage.py makemigrations</code> и <code>python3 manage.py migrate</code>) для надлежащего обновления базы данных.</p> + +<h3 id="Шаблоны">Шаблоны</h3> + +<p>Разрешения текущего пользователя хранятся в переменной шаблона, называемой <code>\{{ perms }}</code>. Вы можете проверить, имеет ли текущий пользователь определенное разрешение, используя конкретное имя переменной в соответствующем приложении «Django» - например, <code>\{{ perms.catalog.can_mark_returned }}</code> будет <code>True</code> если у пользователя есть это разрешение, а <code>False</code> - в противном случае. Обычно мы проверяем разрешение с использованием шаблона <code>{% if %}</code>, как показано в:</p> + +<pre class="brush: python notranslate">{% if perms.catalog.<code>can_mark_returned</code> %} + <!-- We can mark a BookInstance as returned. --> + <!-- Perhaps add code to link to a "book return" view here. --> +{% endif %} +</pre> + +<h3 id="Представления">Представления</h3> + +<p>Разрешения можно проверить в представлении функции, используя <code>permission_required</code> декоратор или в представлении на основе классов, используя <code>PermissionRequiredMixin</code>. шаблон и поведение такие же, как для аутентификации входа в систему, хотя, конечно, вы можете разумно добавить несколько разрешений.</p> + +<p>Функция в представлении с декоратором:</p> + +<pre class="brush: python notranslate">from django.contrib.auth.decorators import permission_required + +@permission_required('catalog.<code>can_mark_returned</code>') +@permission_required('catalog.<code>can_edit</code>') +def my_view(request): + ...</pre> + +<p>Требуется разрешение mixin для представлений на основе классов.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import PermissionRequiredMixin + +class MyView(PermissionRequiredMixin, View): + permission_required = 'catalog.<code>can_mark_returned</code>' + # Or multiple permissions + permission_required = ('catalog.<code>can_mark_returned</code>', 'catalog.can_edit') + # Note that 'catalog.can_edit' is just an example + # the catalog application doesn't have such permission!</pre> + +<h3 id="Пример">Пример</h3> + +<p>Мы не будем обновлять LocalLibrary здесь; возможно, в следующем уроке!</p> + +<h2 id="Испытайте_себя">Испытайте себя</h2> + +<p> Ранее в этой статье мы показали вам, как создать страницу для текущего пользователя, в которой перечислены книги, которые они заимствовали. Теперь задача состоит в том, чтобы создать аналогичную страницу, которая видна только для библиотекарей, которая отображает <em>все</em> книги, которые были заимствованы, и которая показывает имя каждого заемщика.</p> + +<p> Вы должны следовать той же схеме, что и для другого представления. Главное отличие состоит в том, что вам нужно ограничить представление только библиотекарями. Вы можете сделать это на основе того, является ли пользователь сотрудником (декоратор функции: <code>staff_member_required</code>, переменная шаблона: <code>user.is_staff</code>) но мы рекомендуем вам вместо этого использовать <code>can_mark_returned</code> разрешения и <code>PermissionRequiredMixin</code>, как описано в предыдущем разделе.</p> + +<div class="warning"> +<p><strong>Важно</strong>: Не забудьте использовать вашего суперпользователя для тестирования на основе разрешений (проверки разрешений всегда возвращают true для суперпользователей, даже если разрешение еще не определено!). Вместо этого создайте пользователя-библиотекаря и добавьте необходимые возможности.</p> +</div> + +<p> Когда вы закончите, ваша страница должна выглядеть примерно, как на скриншоте ниже.</p> + +<p><img alt="All borrowed books, restricted to librarian" src="https://mdn.mozillademos.org/files/14115/library_borrowed_all.png" style="border-style: solid; border-width: 1px; display: block; height: 283px; margin: 0px auto; width: 500px;"></p> + +<ul> +</ul> + +<h2 id="Подводим_итоги">Подводим итоги</h2> + +<p> Отличная работа - теперь вы создали веб-сайт, на котором участники библиотеки могут входить в систему и просматривать собственный контент, и библиотекари (с правом доступа) могут просматривать все заемные книги с их читатетелями. На данный момент мы все еще просто просматриваем контент, но те же принципы и методы используются, когда вы хотите начать изменять и добавлять данные.</p> + +<p> В следующей статье мы рассмотрим, как вы можете использовать формы Django для сбора пользовательского ввода, а затем начнём изменять некоторые из наших сохраненных данных.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/auth/">User authentication in Django</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/auth/default//">Using the (default) Django authentication system</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/class-based-views/intro/#decorating-class-based-views">Introduction to class-based views > Decorating class-based views</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/django/введение/index.html b/files/ru/learn/server-side/django/введение/index.html new file mode 100644 index 0000000000..1eaffac0cf --- /dev/null +++ b/files/ru/learn/server-side/django/введение/index.html @@ -0,0 +1,259 @@ +--- +title: Django введение +slug: Learn/Server-side/Django/Введение +tags: + - Python + - Вступление + - Джанго + - Начинающим + - Серверное программирование +translation_of: Learn/Server-side/Django/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}</div> + +<p class="summary">В первой статье о Django мы отвечаем на вопрос «Что есть Django?» и даём обзор того, что делает его особенным. Мы опишем основные функции, в том числе некоторые из расширенных функций, которые у нас не будет времени подробно рассмотреть в этом модуле. Мы также покажем вам некоторые основные строительные блоки приложения Django (хотя на данный момент у вас еще не будет среды разработки для тестирования).</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Базовая компьютерная грамотность. Общее понимание <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps">server-side website programming</a>, и в частности, механики <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">client-server interactions in websites</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Узнать, что такое Django, какие функции он предоставляет, и основные строительные блоки приложения Django.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_есть_Django">Что есть Django?</h2> + +<p>Django - это высокоуровневый Python веб-фреймворк, который позволяет быстро создавать безопасные и поддерживаемые веб-сайты. Созданный опытными разработчиками, Django берет на себя большую часть хлопот веб-разработки, поэтому вы можете сосредоточиться на написании своего веб-приложения без необходимости изобретать велосипед . Он бесплатный и с открытым исходным кодом, имеет активное процветающее сообщество, отличную документацию и множество вариантов как бесплатной, так и платной поддержки.</p> + +<p>Django помогает писать программное обеспечение, которое будет:</p> + +<dl> + <dt>Полным</dt> + <dd>Django следует философии «Батарейки в комплекте» и предоставляет почти все, что разработчики могут захотеть сделать «из коробки». Поскольку все, что вам нужно, является частью единого «продукта», все это безупречно работает вместе, соответствует последовательным принципам проектирования, и имеет обширную и <a href="https://docs.djangoproject.com/en/3.0/">актуальную документацию</a>.</dd> + <dt>Разносторонним</dt> + <dd>Django может быть (и был) использован для создания практически любого типа веб-сайтов - от систем управления контентом и wiki до социальных сетей и новостных сайтов. Он может работать с любой клиентской средой и может доставлять контент практически в любом формате (включая HTML, RSS-каналы, JSON, XML и т.д.). Сайт, который вы сейчас читаете, создан с помощью Django!</dd> + <dd>Хотя оDjango предоставляет решения практически для любой функциональности, которая вам может понадобиться (например, для нескольких популярных баз данных, шаблонизаторов и т. д.), внутренне он также может быть расширен сторонними компонентами, если это необходимо.</dd> + <dt>Безопасным</dt> + <dd>Django помогает разработчикам избежать многих распространенных ошибок безопасности, предоставляя фреймворк, разработанный чтобы «делать правильные вещи» для автоматической защиты сайта. Например, Django предоставляет безопасный способ управления учетными записями пользователей и паролями, избегая распространенных ошибок, таких как размещение информации о сеансе в файлы cookie, где она уязвима (вместо этого файлы cookie содержат только ключ, а фактические данные хранятся в базе данных) или непосредственное хранение паролей. вместо хэша пароля.<br> + <br> + Хэш пароля - это значение фиксированной длины, созданное путем обработки пароля через <em><a href="https://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D1%85%D0%B5%D1%88-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F">криптографическую хэш-функцию</a>. </em>Django может проверить правильность введенного пароля, пропустив его через хэш-функцию и сравнив вывод с сохраненным значением хэша. Благодаря «одностороннему» характеру функции, даже если сохраненное хэш-значение скомпрометировано, злоумышленнику будет сложно определить исходный пароль.<br> + <br> + Django, по умолчанию, обеспечивает защиту от многих уязвимостей, включая SQL-инъекцию, межсайтовый скриптинг, подделку межсайтовых запросов и кликджекинг (см. <a href="/ru/docs/Web/Security">Website security</a> для получения дополнительной информации об этих атаках).</dd> + <dt>Масштабируемым</dt> + <dd>Django использует компонентную “<a href="https://en.wikipedia.org/wiki/Shared_nothing_architecture">shared-nothing</a>” архитектуру (каждая её часть независима от других и, следовательно, может быть заменена, либо изменена). Четкое разделение между частями означает, что Django может масштабироваться при увеличении трафика путем добавления оборудования на любом уровне: серверы кэширования, серверы баз данных или серверы приложений. Одни из самых загруженных сайтов успешно масштабировали Django (например, Instagram и Disqus).</dd> + <dt>Удобным в сопровождении</dt> + <dd>Код Django написан с использованием принципов и шаблонов проектирования, которые поощряют создание поддерживаемого и повторно используемого кода. В частности, в нем используется принцип «Don't Repeat Yourself» (DRY, не повторяйся), поэтому нет ненужного дублирования, что сокращает объем кода. Django также способствует группированию связанных функциональных возможностей в повторно используемые «приложения» и, на более низком уровне, группирует связанный код в модули (в соответствии с шаблоном Model View Controller (MVC)).</dd> + <dt>Переносным</dt> + <dd>Django написан на Python, который работает на многих платформах. Это означает, что вы не привязаны к какой-либо конкретной серверной платформе и можете запускать приложения на многих версиях Linux, Windows и Mac OS X. Кроме того, Django хорошо поддерживается многими веб-хостингами, которые часто предоставляют определенную инфраструктуру и документацию для размещения сайтов Django.</dd> +</dl> + +<h2 id="Как_он_появился">Как он появился?</h2> + +<p>Django был разработан в период с 2003 по 2005 год командой, которая занималась созданием и обслуживанием газетных веб-сайтов. После создания нескольких сайтов, команда начала повторно использовать множество общего кода и шаблонов проектирования. Этот общий код эволюционировал в веб-фреймворк "Django", как open-source проект в Июле 2005 года.</p> + +<p>Django продолжает расти и улучшаться с момента его первого релиза (1.0) в сентябре 2008 года до недавно выпущенной версии 2.0 (2017). В каждой версии добавлены новые функциональные возможности и исправлены ошибки, начиная от поддержки новых типов баз данных, шаблонизаторов и кэширования, до добавления «общих» функций и классов (уменьшающих объем кода, который разработчики должны писать для ряда задач).</p> + +<div class="note"> +<p><strong>Заметка</strong>: Ознакомтесь с <a href="https://docs.djangoproject.com/en/stable/releases/">примечаниями к версии </a> на сайте <span style="line-height: 1.5;">Django, чтобы увидеть что изменилось в последних версиях, и как много работы было проделано чтобы улучшить Django.</span></p> +</div> + +<p>Django - это процветающий совместный проект с открытым исходным кодом, в котором заняты многие тысячи пользователей и участников. Несмотря на то, что у него все еще есть некоторые особенности, которые отражают его происхождение, Django превратился в универсальную среду, способную разрабатывать веб-сайты любого типа.</p> + +<h2 id="Насколько_популярен_Django">Насколько популярен Django?</h2> + +<p>Нет никаких доступных и окончательных оценок популярности серверных фреймворков (хотя сайты, подобные Hot Framework, пытаются оценить популярность, используя такие механизмы, как подсчет количества проектов на GitHub и вопросов на StackOverflow для каждой платформы). Лучший вопрос - "Достаточно ли Django популярен, чтобы избежать проблем непопулярных платформ?". Продолжает ли он развиваться? Можете ли вы получить помощь, если вам это нужно? Найдёте ли вы работу, если вы изучите Django?</p> + +<p>Основываясь на количестве крупных сайтов, которые используют Django, количестве участников и количестве людей, предоставляющих как бесплатную, так и платную поддержку, можно полагать, что Django - популярный фреймворк.</p> + +<p>Django используют такие крупные сайты, как Disqus, Instagram, Knight Foundation, MacArthur Foundation, Mozilla, National Geographic, Open Knowledge Foundation, Pinterest, и Open Stack (источник: <a href="https://www.djangoproject.com/">домашняя страница Django</a>).</p> + +<h2 id="Является_ли_Django_гибким">Является ли Django гибким?</h2> + +<p>Веб-фрейморки часто можно поделить на "гибкие" и "негибкие".</p> + +<p>Негибкие - это те, у которых есть "правильный путь" для решения какой-либо конкретной задачи. Они часто поддерживают быстрое развёртывание в <em>определенной области</em> (решение проблем определенного типа), потому что правильный способ сделать что-либо обычно хорошо понимается и хорошо документируется. Однако они могут быть менее гибкими при решении проблем за пределами их основной сферы и, как правило, предлагают меньше вариантов того, какие компоненты и подходы они могут использовать.</p> + +<p>Напротив, у гибких фреймворков гораздо меньше ограничений на лучший способ склеивания компонентов для достижения цели или даже того, какие компоненты следует использовать. Они облегчают разработчикам использование наиболее подходящих инструментов для выполнения конкретной задачи, хотя и за счет того, что вам нужно самим найти эти компоненты.</p> + +<p>Django «умеренно гибкий» и, следовательно, обеспечивает «лучшее из обоих миров». Он предоставляет набор компонентов для обработки большинства задач веб-разработки и один (или два) предпочтительных способа их использования. Однако такая архитектура Django означает, что вы обычно можете выбирать из нескольких различных опций или при необходимости добавлять поддержку для совершенно новых.</p> + +<h2 id="Как_выглядит_код_Django">Как выглядит код Django?</h2> + +<p>В традиционном информационом веб-сайте, веб-приложение ожидает запросов HTTP от веб-браузера (или другого клиента). Когда запрос получен, приложение разрабатывает то, что необходимо на основе URL-адреса и, возможно, информации в <code>POST</code> или в <code>GET</code> запросах. В зависимости от того, что требуется, он может читать или записывать информацию из базы данных или выполнять другие задачи, необходимые для удовлетворения запроса. Приложение затем вернет ответ веб-браузеру, часто динамически создавая страницу HTML для отображения браузера, вставляя полученные данные в HTML шаблон.</p> + +<p>Веб-приложения написанные на Django обычно группируют код, который обрабатывает каждый из этих шагов, в отдельные файлы:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13931/basic-django.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<ul> + <li><strong>URLs: </strong>Хотя можно обрабатывать запросы с каждого URL-адреса с помощью одной функции, гораздо удобнее писать отдельную функцию для обработки каждого ресурса. URL-mapper используется для перенаправления HTTP-запросов в соответствующее представление на основе URL-адреса запроса. URL-mapper также может извлекать данные из URL-адреса в соответствии с заданным шаблоном и передавать их в соответствующую функцию в виде аргументов.</li> + <li><strong>View:</strong> Представление (view) - это функция обработчика запросов, которая получает HTTP-запросы и возвращает ответы. View имеет доступ к данным через модели (необходимым для удовлетворения запросов и делегирования ответа в шаблоны).</li> + <li><strong>Models:</strong> Модели представляют собой объекты Python, которые определяют структуру данных приложения и предоставляют механизмы для управления (добавления, изменения, удаления) и выполнения запросов в базу данных.</li> + <li><strong>Templates:</strong> Template (шаблон) - это текстовый файл определяющий структуру или разметку страницы (например HTML страницы), с полями для подстановки используемыми для представления актуального содержимого. <em>View</em> может динамически создавать HTML страницы, используя HTML шаблоны и заполняя их данными из модели (<em>model).</em> Шаблон может быть использован для определения структуры файлов любых типов, не обязательно HTML.</li> +</ul> + +<div class="note"> +<p><strong>Заметка</strong>: Django реализует уровневую архитектуру "Model View Template (MVT)". Она имеет много общего с более известной архитектурой <a href="/en-US/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">Model View Controller</a>. </p> +</div> + +<ul> +</ul> + +<p>Далее разделы дадут Вам понимание того как выглядят основные части Django (мы их изучим более детально чуть позже на курсе, когда будет настраивать окружение разработчика). </p> + +<h3 id="Отправка_запроса_в_правильное_view_urls.py">Отправка запроса в правильное view (urls.py)</h3> + +<p>Сопоставитель URL-адресов обычно хранится в файле <strong>urls.py</strong>. В примере ниже сопоставитель (<code>urlpatterns</code>) определяет список соответствия между определенными URL-<em>шаблонами </em>и соотвествующими функциями отображения (view). Если полученный HTTP запрос подходит под определенный шаблон ( такой как <code>r'^$'</code>, ниже), то будет вызвана ассоциированная функция отображения<strong> </strong>(такая как <code>views.index</code>) и передана в запрос.</p> + +<pre class="notranslate">urlpatterns = [ + <strong>url(r'^$', views.index),</strong> + url(r'^([0-9]+)/$', views.best), +] +</pre> + +<div class="note"> +<p><strong>Note</strong>: Немного Python:</p> + +<ul> + <li>Объект <code>urlpatterns</code> является списком функций <code>url()</code>. В Python, списки определяются с помощью квадратных скобок. Элементы разделены запятыми и могут содержать <a href="https://docs.python.org/2/faq/design.html#why-does-python-allow-commas-at-the-end-of-lists-and-tuples">необязательную завершающую запятую</a>. Например: <code>[item1, item2, item3,]</code>.</li> + <li>Странный на вид синтаксис шаблона известен как регулярное выражение (regular expression). Мы о нем поговорим позже!</li> + <li>Второй аргумент функции <code>url()</code> это другая функция, которая будет вызвана, когда шаблон будет удачно сопоставлен. Обозначение <code>views.index</code> обозначает, что будет вызвана функция <code>index()<font face="x-locale-heading-primary, zillaslab, Palatino, Palatino Linotype, x-locale-heading-secondary, serif"><span style="background-color: #fff3d4; font-size: 18px;">, которая может быть найдена в модуле под названием </span></font></code><code>views</code> (т.е. в файле <code>views.py</code>).</li> +</ul> +</div> + +<h3 id="Обработка_запроса_views.py">Обработка запроса (views.py)</h3> + +<p>Отображения (views) - это сердце веб-приложения, принимающего HTTP-запросы от веб-клиентов и возвращающего HTTP-ответы. В промежутке они собирают другие ресурсы платформы для доступа к базам данных, шаблонам визуализации и т. д. </p> + +<p>В приведенном ниже примере показана минимальная функция представления <code>index()</code>, которая могла быть вызвана нашим преобразователем URL в предыдущем разделе. Как и все функции представления, она получает объект <code>HttpRequest</code> в качестве параметра <code>(request)</code> и возвращает объект <code>HttpResponse</code>. В этом случае мы ничего не делаем с запросом, и наш ответ просто возвращает жестко запрограммированную строку. Мы покажем вам запрос, который делает что-то более интересное в следующем разделе.</p> + +<pre class="brush: python notranslate">## filename: views.py (Django view functions) + +from django.http import HttpResponse + +def index(request): + # Получить HttpRequest - параметр запроса + # Выполнить операции, используя информацию из запроса. + # Вернуть HttpResponse + return HttpResponse('Hello from Django!') +</pre> + +<div class="note"> +<p><strong>Заметка</strong>: Немного Python:</p> + +<ul> + <li><a href="https://docs.python.org/3/tutorial/modules.html">Модули Python</a> это библиотеки функций, сохраненные в различных файлах, которые мы можем использовать в нашем коде. Здесь мы импортируем только объект <code>HttpResponse</code> из <code>django.http</code> модуля, таким образом мы можем использовать его в нашем отображении (view): <code>from django.http import HttpResponse</code> . Так же есть другие способы импортирования некоторых или всех объектов модуля.</li> + <li>Функции объявляются с помощью ключевого слова <code>def</code> как показано выше, с именованными параметрами, перечисленными в скобках после имени функции; строка завершается двоеточием. Заметьте, что следующие строки содержат отступы. Отступы важны, так как они определяют какие строки кода находятся внутри конкретного блока (обязательные отступы - это ключевая особенность Python и одна из причин, почему код на Python так легко читать).</li> +</ul> +</div> + +<ul> +</ul> + +<p>Отображения (View) обычно сохранены в файле <strong>views.py</strong>.</p> + +<h3 id="Определение_данных_модели_models.py">Определение данных модели (models.py)</h3> + +<p>Веб-приложения Django обрабатывают и запрашивают данные через объекты Python, называемые моделями. Модели определяют структуру хранимых данных, включая типы полей и, возможно, их максимальный размер, значения по умолчанию, параметры списка выбора, текст справки для документации, текст меток для форм и т. д. Определение модели не зависит от СУБД (MySQL или PostgreSQL) - ваши модели будут работать в любой из них. После того, как вы выбрали базу данных, которую хотите использовать, Вам не нужно напрямую обращатся к ней - вы просто пишете свою структуру модели и другой код, а Django обрабатывает всю грязную работу по обращению к базе данных за вас.</p> + +<p>В приведенном ниже фрагменте кода показана очень простая модель Django для объекта <code>Team</code> . Класс <code>Team</code> наследуется от класса <code>models.Model</code>. Он определяет имя команды и командный уровень в качестве полей символов и задает максимальное количество символов, которые должны быть сохранены для каждой записи. <code>Team_level</code> может быть одним из нескольких значений, поэтому мы определяем его как поле выбора и предоставляем сопоставление между отображаемыми вариантами и хранимыми данными вместе со значением по умолчанию. </p> + +<pre class="brush: python notranslate"># filename: models.py + +from django.db import models + +class Team(models.Model): + team_name = models.CharField(max_length=40) + + TEAM_LEVELS = ( + ('U09', 'Under 09s'), + ('U10', 'Under 10s'), + ('U11', 'Under 11s'), + ... #список других командных уровней + ) + team_level = models.CharField(max_length=3,choices=TEAM_LEVELS,default='U11') +</pre> + +<div class="note"> +<p><strong>Заметка</strong>: Немного Python'а:</p> + +<ul> + <li>Python поддерживает «объектно-ориентированное программирование», стиль программирования, в котором мы организуем наш код в объекты, которые включают связанные данные и функции для работы с этими данными. Объекты также могут наследовать / расширять / выводить из других объектов, позволяя совместное поведение между связанными объектами. В Python мы используем ключевое слово <code>class</code> , чтобы определить "скелет" для объекта. Мы можем создать несколько конкретных <em>экземпляров</em> типа объекта на основе модели в классе.<br> + <br> + Так например, мы имеем класс <code>Team</code>, который происходит от класса <code>Model</code>. Это означает, что эта модель будет содержать все методы модели, но мы также можем дать ей специализированные возможности. В нашей модели мы определяем поля нашей базы данных, в которой будем хранить данные, присваивая им конкретные имена. Django использует эти определения, включая имена полей, для создания основной базы данных.</li> +</ul> +</div> + +<h3 id="Запросы_данных_views.py">Запросы данных (views.py)</h3> + +<p>Модель Django предоставляет простой API запросов для поиска в базе данных. Поиск может осуществляться по нескольким полям одновременно с использованием разных критериев (таких как exact, case-insensitive, greater than и т.д.), и может поддерживать сложные выражения (например, вы можете указать поиск в командах U11, у которых есть имя команды, начинающееся с «Fr» или заканчивается на «al»).</p> + +<p>Фрагмент кода показывает функцию view (обработчик ресурсов) для отображения всех команд U09. Жирная строка показывет как мы можем использовать модель API запросов для того, чтобы отфильтровать все записи где поле <code>team_level</code> в точности содержит текст 'U09' (обратите внимание, как эти критерии передаются функции <code>filter()</code> в качестве аргумента с именем поля и типом соответствия, разделенным двойным подчеркиванием: <strong>team_level__exact</strong>).</p> + +<pre class="brush: python notranslate">## filename: views.py + +from django.shortcuts import render +from .models import Team + +def index(request): + <strong>list_teams = Team.objects.filter(team_level__exact="U09")</strong> + context = {'youngest_teams': list_teams} + return render(request, '/best/index.html', context) +</pre> + +<dl> +</dl> + +<p>Данная функция использует функцию <code>render()</code> для того, чтобы создать <code>HttpResponse</code>, который будет отправлен назад браузеру. Эта функция является ярлыком; она создает HTML-файл, комбинируя указанный шаблон HTML и некоторые данные для вставки в шаблон (предоставляется в переменной с именем "<code>context</code>"). В следующем разделе мы покажем как данные вставляются в шаблон для создания HTML-кода.</p> + +<h3 id="Отображение_данных_HTML_templates">Отображение данных (HTML templates)</h3> + +<p>Системы шаблонов позволяют указать структуру выходного документа, используя заполнители для данных, которые будут заполнены при создании страницы. Шаблоны часто используются для создания HTML, но также могут создавать другие типы документов. Django поддерживает как собственную систему шаблонов, так и другую популярную библиотеку Python под названием Jinja2 (она также может быть использована для поддержки других систем, если это необходимо).</p> + +<p>Фрагмент кода показывает, как выглядит HTML-шаблон, вызванный функцией <code>render()</code> из предыдущего раздела. Этот шаблон был написан в предположении, что во время рендеринга он будет иметь доступ к переменной списка, называемой <code>youngest_teams</code> (содержащейся в контекстной переменной внутри функции <code>render()</code> выше). Внутри скелета HTML мы имеем выражение, которое сначала проверяет, существует ли переменная <code>youngest_teams</code>, а затем выполняет итерацию в цикле <code>for</code>. На каждой итерации шаблон отображает значение <code>team_name</code> каждой команды в элементе {{htmlelement ("li")}}.</p> + +<pre class="brush: python notranslate">## filename: best/templates/best/index.html + +<!DOCTYPE html> +<html lang="en"> +<body> + + {% if youngest_teams %} + <ul> + {% for team in youngest_teams %} + <li>\{\{ team.team_name \}\}</li> + {% endfor %} + </ul> +{% else %} + <p>No teams are available.</p> +{% endif %} + +</body> +</html></pre> + +<h2 id="Что_еще_можно_сделать">Что еще можно сделать?</h2> + +<p>В предыдущих разделах показаны основные особенности, которые вы будете использовать почти в каждом веб-приложении: сопоставление URL, представления, модели и шаблоны. Также Django предоставляет несколько других вещей:</p> + +<ul> + <li><strong>Формы</strong>: HTML-формы используются для сбора пользовательских данных для обработки на сервере. Django упрощает создание, проверку и обработку формы.</li> + <li><strong>Аутентификация пользователя и разрешения</strong>: Django включает надежную систему аутентификации и авторизации пользователей, которая была построена с учетом безопасности.</li> + <li><strong>Кэширование:</strong> <span id="result_box" lang="ru"><span>Создание динамического </span></span><span lang="ru"><span>контента намного более интенсивно (и медленнее), чем обслуживание статического содержимого.</span> <span>Django обеспечивает гибкое кэширование, чтобы вы могли хранить всю или часть отображаемой страницы, для того, чтобы она не вызывалась повторно, за исключением случаев, когда это необходимо.</span></span></li> + <li><strong>Админ-панель: </strong>Административная панель в Django включена по умолчанию при создании приложения с использованием основного каркаса. Это упрощает управление админкой администраторам сайта для создания, редактирования и просмотра любых данных на вашем сайте.</li> + <li><strong>Сериализация данных (преобразование в последовательную форму)</strong>: Django упрощает сериализацию и обслуживание ваших данных в таких форматах как XML или JSON. Это может быть полезно при создании веб-сервисов (веб-сайтов, которые исключительно служат для использования данных другими приложениями или сайтами и сами ничего не отображают) или при создании веб-сайта, на котором клиентский код обрабатывает весь рендеринг данных.</li> +</ul> + +<h2 id="Резюме">Резюме</h2> + +<p>Поздравляем, вы завершили первый шаг в своем путешествии по Django! Теперь вы должны понимать основные преимущества Django, немного его истории, и примерно как может выглядеть каждая из основных частей приложения Django. Вы должны также изучить несколько вещей о языке программирования Python, включая синтаксис списков, функций и классов.</p> + +<p>Вы уже видели код на Django выше, но в отличие от клиентского кода вам нужно настроить среду разработки для ее запуска. Это наш следующий шаг</p> + +<div>{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}</div> diff --git a/files/ru/learn/server-side/django/разворачивание/index.html b/files/ru/learn/server-side/django/разворачивание/index.html new file mode 100644 index 0000000000..640527b63d --- /dev/null +++ b/files/ru/learn/server-side/django/разворачивание/index.html @@ -0,0 +1,680 @@ +--- +title: 'Django Руководство часть 11: Разворачивание сайта на сервере' +slug: Learn/Server-side/Django/Разворачивание +tags: + - Веб-сервер + - Для начинающих + - Разворачивание на сервере + - Развёртывание Django +translation_of: Learn/Server-side/Django/Deployment +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</div> + +<p class="summary">Теперь, когда вы создали (и протестировали) свой шикарный сайт <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, у вас скорее всего, есть желание разместить его на публичном веб-сервере, чтобы он стал доступен через интернет персоналу и посетителям библотеки. Данная статья дает общее представление о том, каким образом подойти к поиску хостинга для рамещения сайта, а также, что нужно сделать чтобы подготовить свой сайт к публикации.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Завершить изучение всех предыдущих частей руководства, включая <a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Руководство часть 10: Тестирование веб-приложений в Django</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Изучить, где и как вы можете развернуть приложение Django для публичного доступа.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>Даже когда разработка вашего сайта завершена (или "достаточно" завершена для начала публичного тестирования), то для публичного доступа вам надо его где-то разместить.</p> + +<p>До сего момента вы работали в каком-то рабочем окружении - чтобы получать отладочную и другую частную информацию, вы использовали веб-сервер Django в локальной сети при этом запускали сайт с (небезопасными) настройками разработки. Перед тем как разместить сайт публично, вы должны сделать следующее:</p> + +<ul> + <li>Сделать несколько изменений в настройках проекта.</li> + <li>Выбрать/Настроить окружение для хостинга приложения Django.</li> + <li>Выбрать/Настроить окружение для размещения статических файлов.</li> + <li>В целях обслуживания сайта настроить инфраструктуру для его развертывания.</li> +</ul> + +<p>Данное руководство предоставляет небольшой обзор выбора хостинга, приготовления сайта к публичному размещению, а также практический пример установки сайта LocalLibrary на облачный сервис <a href="https://www.heroku.com/">Heroku</a>.</p> + +<h2 id="Что_такое_окружение_развертывания">Что такое окружение развертывания?</h2> + +<p>Окружение развертывания - это среда, которое предоставляет сервер, на котором вы будете размещать свой веб-сайт для публичного запуска и доступа. Данное окружение включает в себя:</p> + +<ul> + <li>Железо на котором будет запускаться сайт.</li> + <li>Операционную систему (Linux, Windows).</li> + <li>Языки программирования времени выполнения (скриптовые) и библотеки, которые использует ваш сайт.</li> + <li>Веб-сервер, используемый для обслуживания страниц и другого контента (Nginx, Apache).</li> + <li>Сервер приложений, который передает "динамические" запросы между сайтом Django и веб-сервером.</li> + <li>Базу данных, от которой зависит ваш сайт.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: У вас может быть потребность в обратном прокси, балансировщике загрузки и так далее.</p> +</div> + +<p>Сервер может быть вашим собственным с подключением к интернету по скоростному каналу, но более общим подходом является применение "облачных решений". Что действительно имеет значение, так это то, что ваш код запускается на некотором удаленном компьютере (возможно и "виртуальном"), в хостинговом дата-центре. Удаленный сервер обычно предоставляет определенный доступ к компьютерным ресурсам (процессору, оперативной памяти, памяти на жестких носителях и так далее) и соединение с интернетом за некоторую цену.</p> + +<p>Такой тип удаленного доступа к вычислительному/сетевому железу называется <em>Инфраструктура как Сервис (Infrastructure as a Service - IaaS)</em>. Множество IaaS поставщиков предлагают услуги по предустановке какой-либо операционной системы, на которую вы можете установить необходимые для вашего рабочего окружения компоненты. Другие поставщики предлагают вам выбрать уже готовые полноценные рабочие окружения, возможно, включающие в себя Django и настроенный веб-сервер.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Готовые окружения могут сделать настройку вашего веб-сайта очень простой задачей, поскольку они имеют минимальную конфигурацию, однако, либо количество доступных опций может быть недостаточным, или они будут соответствовать устаревшей операционной системе. Часто, более предпочтительно установить необходимые компоненты самостоятельно, таким образом вы получите то, что вам необходимо, а в последующем, при обновлении системы, уже будете знать что нужно делать!</p> +</div> + +<p>Некоторые провайдеры поддерживают Django как часть своего предложения <em>Платформа как Сервис (Platform as a Service</em> - PaaS). При данном виде хостинга вам не нужно беспокоиться о большей части окружения (веб-сервере, сервере приложений, балансировщике загрузки), так как сама платформа берет это на себя (включая все моменты, касающиеся роста и развития вашего приложения). В данном случае развертывание приложения является достаточно простой задачей, - вам нужно сконцентрироваться только на вашем приложении, а не на инфраструктуре.</p> + +<p>Некоторые разработчики выбирают более гибкое решение, предоставляемое IaaS, в то время как другие предпочитают иметь наименьшие накладные расходы и простое масштабирование, предоставляемое PaaS. Когда вы только начинаете, то система типа PaaS является предпочтительной и это именно то, что мы будем использовать в данном руководстве.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Если вы выбираете хостинг с поддержкой Python/Django, то он должен иметь инструкцию по установке веб-сайта Django, учитывающую различные конфигурации веб-сервера, сервера приложений, обратного прокси и так далее (это не имеет значение, если вы выбрали PaaS). Например, существует множество инструкций "шаг-за-шагом" для различный конфигураций в <a href="https://www.digitalocean.com/community/tutorials?q=django">Документации DigitalOcean по Django</a>.</p> +</div> + +<h2 id="Выбор_хостинг_провайдера">Выбор хостинг провайдера</h2> + +<p>Существует более 100 хорошо известных хостинг провайдеров, которые либо активно поддерживают, или работают с Django (их список можно увидеть в <a href="https://djangofriendly.com/index.html">Django-дружественные хостинги</a>). Данные поставщики предоставляют различные типы окружений (IaaS, PaaS), и различные уровни доступа к вычислительным и сетевым ресурсам, за разную цену.</p> + +<p>Некоторые вещи на которые надо обратить внимание при выборе хостинга:</p> + +<ul> + <li>Насколько требовательным к вычислительным ресурсам является ваш сайт.</li> + <li>Уровень поддержки горизовантального (добавление большего количества машин) и вертикального масштабирования (переход на более мощное железо), а также стоимость всего этого.</li> + <li>Где расположены дата-центры и, следовательно, откуда будет более быстрый доступ.</li> + <li>Время непрерывной работы хостинга, а также время и количество простоя.</li> + <li>Инструменты, которые предоставляются для управления сайтом — простота и безопастность их использвания (SFTP и FTP).</li> + <li>Встроенные фреймворки для мониторинга вашего сервера.</li> + <li>Ограничения. Некоторые хостинги могут блокировать некоторые сервисы (например, электронную почту) . Другие предлагают только определенное количество часов "живого времени" за определенную цену, или небольшое количество места для данных.</li> + <li>Преимущества. Некоторые провайдеры могут предложить бесплатные доменные имена и поддержку сертификатов SSL, которые, в других случаях, должны были бы купить.</li> + <li>Что будет при истечении времени использования "бесплатного" хостинга, какова "стоимость" миграции на более "дорогие" тарифы и так далее?</li> +</ul> + +<p>Хорошей новостью является то, что для того, чтобы начать существует достаточное количество компаний, которые предоставляют пробные "бесплатные" тарифы типа "evaluation" (для пробы), "developer" (разработка), или "hobbyist" (хобби). Всегда существуют ресурсы с ограниченым окружением, при использовании которых вам надо беспокоиться лишь о том, что они могут быть доступны лишь в течении определенного периода времени. Тем не менее, они являются отличным решением для тестирования сайтов с небольшим трафиком в реальном окружении, а также могут предоставлять простой доступ к платным ресурсам, в случае необходимости. Наиболее популярными провайдерами являются <a href="https://www.heroku.com/">Heroku</a>, <a href="https://www.pythonanywhere.com/">Python Anywhere</a>, <a href="http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-free-tier.html">Amazon Web Services</a>, <a href="https://azure.microsoft.com/en-us/pricing/details/app-service/">Microsoft Azure</a> и так далее.</p> + +<p>Многие провайдеры имеют "basic" (базовый) тариф, предоставляющий достаточный уровень вычислительной мощности с небольшим количеством ограничений. <a href="https://www.digitalocean.com/">Digital Ocean</a> и <a href="https://www.pythonanywhere.com/">Python Anywhere</a> являются примерами провайдеров, которые предлагают относительно недорой базовый тариф (от $5 до $10USD в месяц).</p> + +<div class="note"> +<p><strong>Примечание:</strong> Необходимо помнить, что цена не является единственным критерием выбора. Если ваш сайт успешен, то может так случиться, что масштабирование станет самым важным элементом вашего внимания при выборе услуг хостинга.</p> +</div> + +<h2 id="Подготовка_веб-сайта_к_публикации">Подготовка веб-сайта к публикации</h2> + +<p><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Скелет сайта</a> был создан при помощи инструментов <em>django-admin</em> и <em>manage.py</em>, которые настроены таким образом, чтобы сделать разработку проще. Многие настройки файла проекта (определенных в <strong>settings.py</strong>) должны быть изменены перед публикацией сайта, либо из-за вопросов безопастности, либо производительности.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Общепринятым решением является иметь отдельный файл <strong>settings.py</strong> для публикации, который импортирует важные настройки из внешних файлов, или из переменных окружения. Доступ к данному файлу должен быть ограничен, даже если остальная часть исходного кода доступна в публичном репозитории.</p> +</div> + +<p>Критически важные настройки файла <strong>settings.py</strong>:</p> + +<ul> + <li><code>DEBUG</code>. При развертывании сайта должен быть установлен в <code>False</code> (<code>DEBUG = False</code>). Тем самым, прекратится вывод важной отладочной информации.</li> + <li><code>SECRET_KEY</code>. Это большое случайное число, применяемое для защиты от CRSF. Важно, чтобы ключ, используемый в продакшине, не указывался в исходном коде, и/или не запрашивался с другого сервера. Django рекомендует размещать значение ключа либо в переменной окружения, или в файле с доступом только на чтение. + <pre class="notranslate"># Чтение SECRET_KEY из переменной окружения +import os +SECRET_KEY = os.environ['SECRET_KEY'] + +#ИЛИ + +#Чтение ключа из файла +with open('/etc/secret_key.txt') as f: + SECRET_KEY = f.read().strip()</pre> + </li> +</ul> + +<p>Давайте изменим приложение <em>LocalLibrary</em> таким образом, чтобы читать <code>SECRET_KEY</code> и <code>DEBUG</code> из переменных окружения, если те определены, иначе использовать значения по умолчанию.</p> + +<p>Откройте <strong>/locallibrary/settings.py</strong>, закомментируйте исходное значение <code>SECRET_KEY</code> и добавьте новые строки, как указано ниже <strong>жирным</strong>. В течении разработки, никаких переменных окружения определено не было, таким образом будут использоваться значения по умолчанию (не имеет значения какой ключ вы используете в процессе разработки, поскольку при развертывании проекта вы будете использовать другой).</p> + +<pre class="brush: python notranslate"># SECURITY WARNING: keep the secret key used in production secret! +# SECRET_KEY = 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag' +<strong>import os</strong> +<strong>SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag')</strong> +</pre> + +<p>Затем закомментируйте строку с настройкой <code>DEBUG</code>, а затем, добавьте новую, указанную ниже.</p> + +<pre class="brush: python notranslate"># SECURITY WARNING: don't run with debug turned on in production! +# DEBUG = True +<strong>DEBUG = bool( os.environ.get('DJANGO_DEBUG', True) )</strong> +</pre> + +<p>Значение <code>DEBUG</code> будет <code>True</code> по умолчанию и станет <code>False</code>, в том случае, если переменная окружения <code>DJANGO_DEBUG</code> будет проинициализирована пустой строкой, то есть, <code>DJANGO_DEBUG=''</code>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Было бы более понятным, если бы мы могли просто установить и снять с <code>DJANGO_DEBUG</code> непосредственно на <code>True</code> и <code>False</code> , напрямую, а не использовать «любую строку» или «пустую строку» (соответственно). К сожалению, значения переменных среды хранятся как строки Python и единственная строка, которая оценивается как <code>False</code> является пустой строкой (например, <code>bool('')==False</code>).</p> +</div> + +<p>Весь перечень настроек для разворачивания вашего сайта находится по ссылке <a href="https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/">Deployment checklist</a> (Django docs). Кроме того, вы можете получить список настроек, выполнив в терминале команду:</p> + +<pre class="brush: python notranslate">python3 manage.py check --deploy +</pre> + +<h2 id="Пример_Установка_LocalLibrary_на_Heroku">Пример: Установка LocalLibrary на Heroku</h2> + +<p>Данный раздел предоставляет демонстрацию того, как установить <em>LocalLibrary</em> на <a href="http://heroku.com">Heroku PaaS cloud</a>.</p> + +<h3 id="Почему_Heroku">Почему Heroku?</h3> + +<p><span id="result_box" lang="ru"><span>Heroku - один из самых продолжительных и популярных облачных сервисов PaaS.</span> <span>Первоначально он поддерживал только приложения Ruby, но теперь его можно использовать для размещения приложений из многих сред программирования, включая Django!</span></span></p> + +<p>Мы выбираем для использования Heroku по нескольким причинам:</p> + +<ul> + <li><span id="result_box" lang="ru"><span>У Heroku есть <a href="https://www.heroku.com/pricing">свободный уровень</a>, который <em>действительно</em> свободен (хотя и с некоторыми ограничениями)</span></span></li> + <li><span id="result_box" lang="ru"><span title="As a PaaS, Heroku takes care of a lot of the web infrastructure for us.">Как PaaS, Heroku заботится о большой веб-инфраструктуре для нас. </span><span title="This makes it much easier to get started, because you don't worry about servers, load balancers, reverse proxies, or any of the other web infrastructure that Heroku provides for us under the hood. + ">Это значительно облегчает работу, потому что вы не беспокоитесь о серверах, балансирах нагрузки, обратных прокси или любой другой веб-инфраструктуре, которую Heroku предоставляет нам под капотом.</span></span></li> + <li><span id="result_box" lang="ru"><span title="While it does have some limitations these will not affect this particular application.">Хотя у этого есть некоторые ограничения, это не повлияет на это конкретное приложение. </span><span title="For example: + ">Например:</span></span> + <ul> + <li><span id="result_box" lang="ru"><span title="Heroku provides only short-lived storage so user-uploaded files cannot safely be stored on Heroku itself. + ">Heroku предоставляет только недолговечное хранилище, поэтому загруженные пользователем файлы нельзя безопасно хранить на самом Heroku.</span></span></li> + <li><span id="result_box" lang="ru"><span title="The free tier will sleep an inactive web app if there are no requests within a half hour period.">Свободный уровень будет спать с неактивным веб-приложением, если в течение получаса не будет запросов. </span><span title="The site may then take several seconds to respond when it is woken up. + ">После этого сайт может занять несколько секунд, чтобы ответить, когда он проснулся.</span></span></li> + <li><span id="result_box" lang="ru"><span title='The free tier limits the time that your site is running to a certain amount of hours every month (not including the time that the site is "asleep").'>Свободный уровень ограничивает время, в течение которого ваш сайт работает до определенного количества часов каждый месяц (не включая время, когда сайт «спит»). </span><span title="This is fine for a low use/demonstration site, but will not be suitable if 100% uptime is required. + ">Это нормально для сайта с низким уровнем использования / демонстрации, но не подходит, если требуется 100% время безотказной работы.</span></span></li> + <li>Другие ограничения перечислены в <a href="https://devcenter.heroku.com/articles/limits">Limits</a> (документы Heroku).</li> + </ul> + </li> + <li><span id="result_box" lang="ru"><span title="Mostly it just works, and if you end up loving it, scaling your app is very easy. + +">В основном это просто работает, и если вы в конечном итоге полюбите его, масштабирование вашего приложения будет очень простым.</span></span></li> +</ul> + +<p><span id="result_box" lang="ru"><span title="While Heroku is perfect for hosting this demonstration it may not be perfect for your real website.">Хотя Heroku идеально подходит для проведения этой демонстрации, она может быть не идеальна для вашего реального сайта. </span><span title="Heroku makes things easy to set up and scale, at the cost of being less flexible, and potentially a lot more expensive once you get out of the free tier.">Heroku упрощает настройку и масштабирование за счет меньшей гибкости и, возможно, обойдется намного дороже, когда вы выходите из свободного уровня.</span></span></p> + +<h3 id="Как_работает_Heroku">Как работает Heroku?</h3> + +<p>Heroku запускает сайты Django внутри одного, или более, изолированых друг от друга "<a href="https://devcenter.heroku.com/articles/dynos">Dynos</a>", которые являются виртуальными Unix-контейнерами, предоставляющими необходимое окружение для вашего приложения. Данные dynos полностью изолированы и имеют <em>эфемерную</em> файловую систему ("короткоживущая" файловая система, которая полностью очищается и обновляется каждый раз, когда dyno перезапускается). Единственной сущностью, которую предоставляет dynos по умолчанию, является приложение по <a href="https://devcenter.heroku.com/articles/config-vars">конфигурации переменных</a>. Heroku внутри себя применяет балансировщик загрузки для распределения веб-трафика среди всех "веб"-dynos. Поскольку dynos изолированы, Heroku может масштабировать приложение горизонтально, просто добавляя больше dynos (хотя, конечно, у вас может появиться необходимость расширить базу данных для обработки дополнительных соединений).</p> + +<p>Файловая система эфемерна, поэтому вы не можете напрямую установить необходимые для вашего приложения сервисы (то есть, базы данных, очереди, системы кэширования, хранения, сервисы электронной почты и так далее). Взамен этого, Heroku предоставляет сервисы, доступные как независимые "дополнения" ("add-ons") либо от самой Heroku, или от сторонних разработчиков. В тот момент когда ваше приложение запускается в системе, dynos получает доступ к сервисам, используя информацию, содержащуюся в переменных настройки вашего приложения.</p> + +<p>Для того, чтобы выполнить ваше приложение Heroku необходимо иметь возможность установить соответствующее окружение и зависимости, а также понимать как его (приложение) запустить. В случае приложений Django мы предоставляем соответствующую информацию в нескольких текстовых файлах:</p> + +<ul> + <li><strong>runtime.txt</strong>:<strong> </strong>язык программирования и его версию.</li> + <li><strong>requirements.txt</strong>: необходимые для Python компоненты, включая Django.</li> + <li><strong>Procfile</strong>: Список процессов, которые будут выполнены для старта веб-приложения. Для Django это обычно сервер веб-приложений Gunicorn (скрипт <code>.wsgi</code>).</li> + <li><strong>wsgi.py</strong>: конфигурация <a href="http://wsgi.readthedocs.io/en/latest/what.html">WSGI</a> для вызова нашего приложения Django в окружении Heroku.</li> +</ul> + +<p>Разработчики Developers взаимодействуют с Heroku при помощи специального клиентского приложения/терминала, который сильно похож на bash-скрипт Unix. Оно позволяет вам загружать код, находящийся в git-репозитории, контроллировать выполняемые процессы, смотреть логи, устанавливать конфигурационные переменные и многое другое!</p> + +<p>Для того, чтобы заставить ваше приложение работать с Heroku, нам нужно разместить наше веб-приложение в git-репозитории, добавить, перечисленные ранее, файлы, подключить дополнение (add-on) базы данных и выполнить настройки для правильной работы со статическими файлами.</p> + +<p>Когда мы выполним все, что необходимо для нашего сайта мы можем создать аккаунт Heroku, получить доступ к клиенту Heroku и использовать его, для установки нашего веб-сайта.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Инструкции, перечисленные ниже, соответствуют процессу работы с Heroku во время написания данной статьи (английской версии - прим. перев.). Если Heroku значительно изменит этот процесс, вы можете воспользоваться соответствующим описанием: <a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Heroku начало работы с Django</a>.</p> +</div> + +<p>На этом завершается краткий обзор начала работы с Heroku (более подробное руководство <a href="https://devcenter.heroku.com/articles/how-heroku-works">Как работает Heroku</a>).</p> + +<h3 id="Создание_репозитория_приложения_на_Github">Создание репозитория приложения на Github</h3> + +<p><span id="result_box" lang="ru"><span>Heroku тесно интегрирована с системой управления версиями исходного кода <strong>git</strong>, используя ее для загрузки / синхронизации любых изменений, которые вы вносите в живую систему.</span> <span>Он делает это, добавляя новый «удаленный» репозиторий heroku с именем heroku, указывающий на репозиторий для вашего источника в облаке Heroku.</span> <span>Во время разработки вы используете <strong>git</strong> для хранения изменений в вашем «master» репозитории.</span> <span>Когда вы хотите развернуть свой сайт, вы синхронизируете свои изменения в репозитории Heroku.</span></span></p> + +<div class="note"> +<p><strong>Примечание:</strong> <span id="result_box" lang="ru"><span>Если вы привыкли следовать хорошей практике разработки программного обеспечения, вы, вероятно, уже используете git или какую-либо другую систему SCM.</span> <span>Если у вас уже есть git-репозиторий, вы можете пропустить этот шаг.</span></span></p> +</div> + +<p><span id="result_box" lang="ru"><span>Существует множество способов работы с git, но одним из самых простых является создание учетной записи в <a href="https://github.com/">Github</a>, создание репозитория там, а затем синхронизация с ним локально:</span></span></p> + +<ol> + <li>Посетите <a href="https://github.com/">https://github.com/</a> и создайте аккаунт.</li> + <li>После входа в систему нажмите ссылку + в верхней панели инструментов и выберите <strong>Новый репозиторий</strong>.</li> + <li>Заполните все поля на этой форме. Хотя они не являются обязательными, они настоятельно рекомендуются. + <ul> + <li>Введите имя нового репозитория (например <em>django_local_library</em>), и комментарий к репозиторию (например "Local Library website written in Django".</li> + <li>Нажмите на кнопку<em> <strong>Add .</strong></em><strong>gitignore </strong>и в появившемся списке выберите <strong>Python</strong>.</li> + <li>Выберите подходящую вам лицензию из списка <em><strong>Add license. </strong></em>Если не знаете для чего это - оставьте как было.</li> + <li> + <p>Установите галочку напротив <em><strong>Initialize this repository with a README</strong>.</em></p> + </li> + </ul> + </li> + <li>Нажмите кнопку <strong>Create repository</strong>, тем самым создав ваш репозиторий.</li> + <li>Перейдите на страницу вашего репозитория. Там нажмите на зелёную кнопку "<strong>Clone or download</strong>". Скопируйте URL из текстового поляиз появившегося диалогового окна (Это будет похоже на: <strong>https://github.com/<em><your_git_user_id></em>/django_local_library.git</strong>). Здесь <strong><your_git_user_id> </strong>- это будет ваш id пользователя git.</li> +</ol> + +<p>Когда ваш репозиторий будет создан - загрузите его себе на компьтер, следуя инструкции, описанной ниже:</p> + +<ol> + <li>Установите git себе на компьютер (Вы можете найти версию для своей платформы <a href="https://git-scm.com/downloads">здесь</a>).</li> + <li>Откройте командную строку (или терминал) и выполните в нём следующую команду, используя ссылку, которую вы получили с github: + <pre class="brush: bash notranslate">git clone https://github.com/<strong><em><your_git_user_id></em></strong>/django_local_library.git +</pre> + Это создаст подпапку (с содержанием вашего репозитория и именем вашего репозитория) внутри папки, в котрой выполнялась команда.</li> + <li>Перейдите в эту папку: + <pre class="brush: bash notranslate">cd django_local_library.git</pre> + </li> +</ol> + +<p>Последний шаг. Нужно скопировать ваше Django-приложение и добавить его файлы в новый репозиторий, используя git:</p> + +<ol> + <li>Скопируйте ваше приложение в папку репозитория (все файлы с таким же уровнем, как у <strong>manage.py,</strong> <u><strong>БЕЗ </strong>папки проекта, в которой эти файлы находятся</u>).</li> + <li>Откройте файл с расширением <strong>.gitignore </strong>в текстовом редакторе, вставьте в самый его конец строки, приведённые ниже, а затем сохраните (этот файл "говорит" о файлах, которые не должны быть загружены в git по умолчанию). + <pre class="notranslate"># Text backup files +*.bak + +#Database +*.sqlite3</pre> + </li> + <li> + <p>Откройте командную строку или терминал и используйте <code>add</code> команду с флагом <code>-A</code>. Эта комманда сохранит изменения в репозиторий:</p> + + <pre class="brush: bash notranslate"><code>git add -A</code></pre> + </li> + <li>Используйте команду <code>status</code>, что бы убедиться, что все файлы, которые вы собираетесь добавить верны (вы хотите включить исходные файлы, а не бинарные файлы, временные файлы и т. д.). В консоль выведется что то вроде этого: + <pre class="notranslate">> git status +On branch master +Your branch is up-to-date with 'origin/master'. +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + modified: .gitignore + new file: catalog/__init__.py + ... + new file: catalog/migrations/0001_initial.py + ... + new file: templates/registration/password_reset_form.html</pre> + </li> + <li>Теперь, зафиксируйте файлы в локальном репозитории: + <pre class="brush: bash notranslate">git commit -m "First version of application moved into github"</pre> + </li> + <li>Синхронизируете свой локальный репозиторий с сайтом Github: + <pre class="notranslate">git push origin master</pre> + </li> +</ol> + +<p>Когда эти операции завершатся, вернитесь на страницу Github где вы создали свой репозиторий, обновите страницу, и убедитесь, что ваше приложение полностью загружено. При надобности обновить файлы на репозитории - повторите цикл ввода команд add/commit/push.</p> + +<div class="note"> +<p><strong>Подсказка:</strong> Это хороший момент для создания резервной копии вашего «ванильного» проекта — в то время как некоторые изменения, которые мы собираемся сделать в следующих разделах, могут быть полезны для развертывания на любой платформе (или разработке), которые другие могут не использовать.</p> + +<p><em>Лучший способ</em> сделать это - использовать <em>git</em> для управления вашими изменениями. С <em>git</em> вы можете не только вернуться к определенной старой версии, но и сохранить ее в отдельной «ветке» ваших производственных изменений, and cherry-pick - выбрать любые изменения для перемещения между ветвями производства и развития. <a href="https://help.github.com/articles/good-resources-for-learning-git-and-github/">Изучение Git</a> будет стоить усилий, но это выходит за рамки данной темы. Самый простой способ сделать это - просто скопировать файлы в другое место. Используйте тот подход, который наилучшим образом соответствует вашим знаниям git!</p> +</div> + +<h3 id="Обновить_приложение_для_Heroku">Обновить приложение для Heroku </h3> + +<p>В этой части говорится об изменениях, которые мы должны сделать на нашем приложении <em>LocalLibrary</em>, что бы оно работало на Heroku. В то время как документация <a dir="ltr" href="https://devcenter.heroku.com/articles/getting-started-with-python" style="color: green;">"начало работы с Heroku с инструкциями Django"</a> предполагает, что вы будете использовать <a href="https://devcenter.heroku.com/articles/getting-started-with-python#set-up">Heroku client</a> для запуска локальной среды разработки, наши изменения здесь совместимы с существующим сервером разработки Django и способами работы, которые мы уже узнали.</p> + +<h4 id="Procfile">Procfile</h4> + +<p> Создайте файл с именем <code>Procfile</code> (без расширения) в корне нашего GitHub репозитории объявить типы процессов и точки входа приложения. Скопируйте в него следующий текст:</p> + +<pre class="notranslate">web: gunicorn locallibrary.wsgi --log-file -</pre> + +<p>«web:» сообщает Heroku, что это веб динамический и может быть отправлен HTTP-трафик. Процесс, который начнется в этом динамически, - это gunicorn, который является популярным сервером веб-приложений, который рекомендует Heroku. Мы запускаем Gunicorn, используя конфигурационную информацию в модуле locallibrary.wsgi (созданный с помощью нашего скелета приложения: /locallibrary/wsgi.py).</p> + +<h4 id="Gunicorn">Gunicorn</h4> + +<p><a href="http://gunicorn.org/">Gunicorn</a> рекомендуемый http сервер с Django на Heroku (Как указанов Procfile выше). Это чистый python http сервер для WSGI приложений которые могут запускать множество параллельных python процессов в пределах одного динамического (посмотрите <a href="https://devcenter.heroku.com/articles/python-gunicorn">Deploying Python applications with Gunicorn</a> для получения большей информации).</p> + +<p>Также нам не понадобится <em>Gunicorn</em> для обслушивания нашей LocalLibrary приложения в течение разработки, мы установим это так, чтобы он стал частью наших требований к Heroku для настройки на удаленном сервере.</p> + +<p>Установка <em>Gunicorn</em> локально в командной строке используя пакетный менеджер <em>pip</em> (которые мы установили когда <a href="/en-US/docs/Learn/Server-side/Django/development_environment">настраивали среду разработки</a>):</p> + +<pre class="brush: bash notranslate">pip3 install gunicorn +</pre> + +<h4 id="Настройка_Базы_Данных">Настройка Базы Данных</h4> + +<p>Мы не можем использовать базу данных SQLite по умолчанию на Heroku, потому что она основана на файлах, и она будет удалена из эфемерной файловой системы каждый раз, когда приложение перезагружается (обычно один раз в день и каждый раз, когда изменяется приложение или его переменные конфигурации ).</p> + +<p>Механизм Heroku для обработки этой ситуации заключается в использовании <a href="https://elements.heroku.com/addons#data-stores">надстройки базы данных</a> и настройке веб-приложения с использованием информации из <a href="https://devcenter.heroku.com/articles/config-vars">переменной конфигурации среды</a>, установленной надстройкой. Существует множество опций базы данных, но мы будем использовать <a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#plan-tiers">hobby уровень</a> в базе данных <em>postgres Heroku</em>, поскольку это бесплатно, поддерживается Django и автоматически добавляется в наши новые приложения Heroku при использовании бесплатного уровня динамического плана для хобби.</p> + +<p>Информация о подключении базы данных предоставляется на web dyno, используя конфигурационную переменную с именем <code>DATABASE_URL</code>. Вместо того, чтобы жестко кодировать эту информацию в Django, Heroku рекомендует разработчикам использовать <a href="https://warehouse.python.org/project/dj-database-url/">dj-database-url</a> пакет для анализа <code>DATABASE_URL</code> переменную окружения и автоматически преобразовать ее в желаемый формат конфигурации Django. В дополнение к установке пакета <em>dj-database-url</em> нам также потребуется установить <a href="http://initd.org/psycopg/">psycopg2</a>, поскольку Django нуждается в этом, чтобы взаимодействовать с базами данных Postgres.</p> + +<h5 id="dj-database-url_Django_конфигурации_базы_данных_из_переменной_окружения">dj-database-url (Django конфигурации базы данных из переменной окружения)</h5> + +<p>Установите dj-database-url локально, чтобы он стал частью наших требований к настройке Heroku на удаленном сервере:</p> + +<pre class="notranslate">$ pip3 install dj-database-url +</pre> + +<h5 id="settings.py">settings.py</h5> + +<p>Откройте /locallibrary/settings.py и скопируйте следующую конфигурацию в нижнюю часть файла:</p> + +<pre class="notranslate"># Heroku: Update database configuration from $DATABASE_URL. +import dj_database_url +db_from_env = dj_database_url.config(conn_max_age=500) +DATABASES['default'].update(db_from_env)</pre> + +<div class="note"> +<p><strong>Заметка:</strong></p> + +<ul> + <li>Мы все еще будем использовать SQLite во время разработки, поскольку <code>DATABASE_URL</code> переменная среды не будет установлена на нашем компьютере разработки.</li> + <li>Значение <code>conn_max_age=500</code> делает соединение постоянным, что намного эффективнее, чем воссоздавать соединение в каждом цикле запросов. Однако это необязательно и при необходимости можно удалить.</li> +</ul> +</div> + +<h5 id="psycopg2_Python_Postgres_database_support">psycopg2 (Python Postgres database support)</h5> + +<p>Django нуждается в psycopg2 для работы с базами данных Postgres, и вам нужно будет добавить это в файл требований.txt для Heroku, чтобы установить это на удаленном сервере (как описано в разделе требований ниже).</p> + +<p>Django будет использовать нашу базу данных SQLite локально по умолчанию, поскольку переменная среды DATABASE_URL не задана в нашей локальной среде. Если вы хотите полностью перейти на Postgres и использовать нашу бесплатную базу данных Heroku для разработки и производства, то вы можете. Например, чтобы установить psycopg2 и его зависимости локально в системе на базе Linux, вы должны использовать следующие команды bash / terminal:</p> + +<pre class="brush: bash notranslate"><code>sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib</code> +pip3 install psycopg2 +</pre> + +<p>Инструкции по установке для других платформ можно найти на веб-сайте psycopg2.</p> + +<p>Однако вам не нужно это делать - вам не нужно, чтобы PostGreSQL был активным на локальном компьютере, если вы передаете его в Heroku в качестве требования в файле требований.txt (см. Ниже).</p> + +<h4 id="Обслуживание_статических_файлов_в_производстве"><strong>Обслуживание статических файлов в производстве</strong></h4> + +<p><br> + Во время разработки мы использовали Django и веб-сервер разработки Django для обслуживания наших статических файлов (CSS, JavaScript и т. Д.). В производственной среде вместо этого мы обычно обслуживаем статические файлы из сети доставки контента (CDN) или веб-сервера.</p> + +<div class="note"> +<p><strong>Примечание. </strong>Обслуживание статических файлов через Django / веб-приложение неэффективно, потому что запросы должны проходить через ненужный дополнительный код (Django), а не обрабатываться непосредственно веб-сервером или полностью отдельным CDN. Хотя это не имеет значения для местного использования во время разработки, это будет иметь значительное влияние на производительность, если мы будем использовать тот же подход в производстве.</p> +</div> + +<p>Чтобы упростить размещение статических файлов отдельно от веб-приложения Django, Django предоставляет средство сбора данных для сбора этих файлов для развертывания (имеется переменная параметров, определяющая, где файлы должны собираться при запуске collectstatic). Шаблоны Django относятся к месту размещения статических файлов относительно переменной параметров (STATIC_URL), так что это можно изменить, если статические файлы перемещаются на другой хост / сервер.</p> + +<p>Соответствующими параметрами настройки являются:</p> + +<p> STATIC_URL: это базовое расположение URL, из которого будут загружены статические файлы, например, на CDN. Это используется для переменной статического шаблона, доступ к которой осуществляется в нашем базовом шаблоне (см. Учебник по Django Part 5: Создание нашей домашней страницы).<br> + STATIC_ROOT: Это абсолютный путь к каталогу, в котором инструмент «collectstatic» Django будет собирать любые статические файлы, упомянутые в наших шаблонах. После их сбора они затем могут быть загружены в группу, где бы файлы не размещались.<br> + STATICFILES_DIRS: В этом списке перечислены дополнительные каталоги, в которых инструмент коллективного поиска Django должен искать статические файлы.</p> + +<h5 id="settings.py_2">settings.py</h5> + +<p>Откройте /locallibrary/settings.py и скопируйте следующую конфигурацию в нижнюю часть файла. BASE_DIR уже должен быть определен в вашем файле (STATIC_URL, возможно, уже был определен в файле, когда он был создан. В то время как это не причинит вреда, вы также можете удалить дублируемую предыдущую ссылку).</p> + +<pre class="notranslate"># Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.10/howto/static-files/ + +# The absolute path to the directory where collectstatic will collect static files for deployment. +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') + +# The URL to use when referring to static files (where they will be served from) +STATIC_URL = '/static/' +</pre> + +<p>Фактически мы будем делать файл, используя библиотеку WhiteNoise, которую мы устанавливаем и настраиваем в следующем разделе.</p> + +<p>Для получения дополнительной информации см. Django и Static Assets (документы Heroku).</p> + +<p><strong>WhiteNoise</strong><br> + Существует множество способов обслуживания статических файлов на производстве (мы видели соответствующие настройки Django в предыдущих разделах). Heroku рекомендует использовать проект WhiteNoise для обслуживания статических активов непосредственно из Gunicorn в производстве.</p> + +<div class="note"> +<p><strong>Заметка: </strong>Heroku автоматически вызывает collectstatic и готовит ваши статические файлы для использования WhiteNoise после того, как он загрузит ваше приложение. Посмотрите <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a> документацию для объяснения того, как она работает, и почему реализация является относительно эффективным методом для обслуживания этих файлов.</p> +</div> + +<p>Шаги по настройке <em>WhiteNoise</em> для использования в проекте:</p> + +<h5 id="WhiteNoise">WhiteNoise</h5> + +<p>Установите <em>WhiteNoise</em> локально, используя следующую команду:</p> + +<pre class="notranslate">$ pip3 install whitenoise +</pre> + +<h5 id="settings.py_3">settings.py</h5> + +<p>Чтобы установить WhiteNoise в приложение Django, откройте /locallibrary/settings.py, найдите параметр MIDDLEWARE и добавьте WhiteNoiseMiddleware в верхней части списка, чуть ниже SecurityMiddleware:</p> + +<pre class="notranslate">MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + <strong>'whitenoise.middleware.WhiteNoiseMiddleware',</strong> + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] +</pre> + +<p>При желании вы можете уменьшить размер статических файлов при их обслуживании (это более эффективно). Просто добавьте следующее в конец /locallibrary/settings.py:</p> + +<pre class="notranslate"># Simplified static file serving. +# https://warehouse.python.org/project/whitenoise/ +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' +</pre> + +<h4 id="Requirements">Requirements</h4> + +<p>Требования Python вашего веб-приложения должны храниться в файле requirements.txt в корневом каталоге вашего репозитория. После этого Heroku автоматически установит их при восстановлении вашей среды. Вы можете создать этот файл с помощью pip в командной строке (запустите в корне repo):</p> + +<pre class="brush: bash notranslate">pip3 freeze > requirements.txt</pre> + +<p>После установки всех разных зависимостей выше, файл requirements.txt должен иметь <em>по меньшей мере</em> эти перечисленные элементы (хотя номера версий могут отличаться). Удалите любые другие зависимости, не перечисленные ниже, если вы явно не добавили их для этого приложения.</p> + +<pre class="notranslate">dj-database-url==0.4.1 +Django==1.10.2 +gunicorn==19.6.0 +<strong>psycopg2==2.6.2</strong> +whitenoise==3.2.2 +</pre> + +<div class="note"> +<p>Убедитесь, что строка <strong>psycopg2</strong>, подобная приведенной выше, присутствует! Даже если вы не установили это локально, вы должны добавить это в <strong>requirements.txt</strong>.</p> +</div> + +<h4 id="Среда_выполнения">Среда выполнения</h4> + +<p>Файл <strong>runtime.txt</strong>, если определён, говорит Heroku, какой язык программирования использовать. Создайте файл в корне репо и добавьте следующий текст:</p> + +<pre class="notranslate">python-3.5.2</pre> + +<div class="note"> +<p><strong>Заметка:</strong> Heroku поддерживает только небольшое количество <a href="https://devcenter.heroku.com/articles/python-support#supported-python-runtimes">Python runtimes</a>. (на момент написания статьи, в том числе и выше). Heroku будет использовать поддерживаемую среду выполнения независимо от значения, указанного в этом файле.</p> +</div> + +<h4 id="Сохраните_изменения_в_Github_и_перепроверьте">Сохраните изменения в Github и перепроверьте</h4> + +<p>Далее мы сохраним все наши изменения в Github. В терминале (whist внутри нашего репозитория) введите следующие команды:</p> + +<pre class="brush: python notranslate">git add -A +git commit -m "Added files and changes required for deployment to heroku" +git push origin master</pre> + +<p>Прежде чем продолжить, дайте возможность проверить сайт снова локально и убедиться, что это не повлияло ни на одно из наших изменений выше. Запустите веб-сервер разработки как обычно, а затем проверьте, работает ли сайт, как вы ожидаете в своем браузере.</p> + +<pre class="brush: bash notranslate">python3 manage.py runserver</pre> + +<p>Теперь мы должны быть готовы начать развертывание LocalLibrary на Heroku.</p> + +<h3 id="Получить_аккаунт_в_heroku">Получить аккаунт в heroku</h3> + +<p>Чтобы начать использовать Heroku, вам сначала нужно создать учетную запись:</p> + +<ul> + <li>Перейдите <a href="https://www.heroku.com/">www.heroku.com</a> и нажмите <strong>SIGN UP FOR FREE</strong> кнопку.</li> + <li>Введите ваши данные, а затем нажмите <strong>CREATE FREE ACCOUNT</strong>. Вам будет предложено проверить свою учетную запись по адресу электронной почты для регистрации.</li> + <li>Нажмите ссылку активации учетной записи в электронной почте для регистрации. Вы вернетесь в свою учетную запись в веб-браузере.</li> + <li>Введите свой пароль и нажмите <strong>SET PASSWORD AND LOGIN</strong>.</li> + <li>Затем вы войдете в систему и попадете в приборную панель Heroku: <a href="https://dashboard.heroku.com/apps">https://dashboard.heroku.com/apps</a>.</li> +</ul> + +<h3 id="Установка_клиента">Установка клиента</h3> + +<p>Загрузите и установите клиент Heroku, следуя <a href="https://devcenter.heroku.com/articles/getting-started-with-python#set-up">инструкциям Heroku </a>здесь.</p> + +<p>После установки клиента вам будут дотупны команды. Например, чтобы получить справку о клиенте:</p> + +<pre class="brush: bash notranslate">heroku help +</pre> + +<h3 id="Создание_и_загрузка_веб-сайта">Создание и загрузка веб-сайта</h3> + +<p>Чтобы создать приложение, мы запускаем команду «create» в корневом каталоге нашего репозитория. Это создает git remote («указатель на удаленный репозиторий»), названный heroku в нашей локальной среде git.</p> + +<pre class="brush: bash notranslate">heroku create</pre> + +<div class="note"> +<p><strong>Заметка:</strong> Вы можете назвать удаленный, если хотите, указав значение после «create». Если вы этого не сделаете, вы получите случайное имя. Имя используется в URL-адресе по умолчанию.</p> +</div> + +<p>Затем мы можем подтолкнуть наше приложение в репозиторий heroku как показано ниже. Это позволит загрузить приложение, упаковать его в dyno, запустить collectstatic, и запустить сам сайт.</p> + +<pre class="brush: bash notranslate">git push heroku master</pre> + +<p>Если нам повезет, приложение «заработает» на сайте, но оно не будет работать должным образом, потому что мы не настроили таблицы базы данных для использования нашим приложением. Для этого нам нужно использовать команду <code>heroku run</code> и запустить "<a href="https://devcenter.heroku.com/articles/deploying-python#one-off-dynos">one off dyno</a>" для выполнения операции переноса. Введите в терминал следующую команду:</p> + +<pre class="brush: bash notranslate">heroku run python manage.py migrate</pre> + +<p>Мы также должны будем иметь возможность добавлять книги и авторов, поэтому давайте также создадим суперпользователя, снова используя одноразовый динамический режим:</p> + +<pre class="brush: bash notranslate">heroku run python manage.py createsuperuser</pre> + +<p>Как только это будет завершено, мы можем посмотреть сайт. Он должен работать, хотя в нем еще нет книг. Чтобы открыть браузер на новом веб-сайте, используйте команду:</p> + +<pre class="brush: bash notranslate">heroku open</pre> + +<p>Создайте несколько книг на сайте администратора и проверьте, работает ли сайт, как вы ожидаете.</p> + +<h3 id="Управление_аддонами">Управление аддонами</h3> + +<p>Вы можете проверить дополнения в своем приложении, используя <code>heroku addons</code> команду. Это будет список всех аддонов, их ценовая категория и состояние.</p> + +<pre class="brush: bash notranslate">>heroku addons + +Add-on Plan Price State +───────────────────────────────────────── ───────── ───── ─────── +heroku-postgresql (postgresql-flat-26536) hobby-dev free created + └─ as DATABASE</pre> + +<p>Здесь мы видим, что у нас есть только одна надстройка, база данных postgres SQL. Это бесплатно и автоматически создается при создании приложения. Вы можете открыть веб-страницу, чтобы более подробно изучить надстройку базы данных (или любое другое дополнение), используя следующую команду:</p> + +<pre class="brush: bash notranslate">heroku addons:open heroku-postgresql +</pre> + +<p>Другие команды позволяют создавать, уничтожать, обновлять и понижать аддоны (используя аналогичный синтаксис для открытия). Для получения дополнительной информации см. <a href="https://devcenter.heroku.com/articles/managing-add-ons">Managing Add-ons</a> (Heroku docs).</p> + +<h3 id="Настройка_переменных_конфигурации">Настройка переменных конфигурации</h3> + +<p>Вы можете проверить конфигурационные переменные для сайта, используя команду <code>heroku config</code>. Ниже вы можете видеть, что у нас есть только одна переменная <code>DATABASE_URL</code> , используемая для настройки нашей базы данных.</p> + +<pre class="brush: bash notranslate">>heroku config + +=== locallibrary Config Vars +DATABASE_URL: postgres://uzfnbcyxidzgrl:j2jkUFDF6OGGqxkgg7Hk3ilbZI@ec2-54-243-201-144.compute-1.amazonaws.com:5432/dbftm4qgh3kda3</pre> + +<p>Если вы вспомните из раздела, посвященного <a href="#Getting_your_website_ready_to_publish">getting the website ready to publish</a>, мы должны установить переменные среды для <code>DJANGO_SECRET_KEY</code> и <code>DJANGO_DEBUG</code>. Давайте сделаем это сейчас.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Секретный ключ должен быть действительно секретным! Один из способов генерации нового ключа - создать новый проект Django (<code>django-admin startproject someprojectname</code>) а затем получить ключ, который генерируется для вас в его <strong>settings.py</strong>.</p> +</div> + +<p>Мы устанавливаем <code>DJANGO_SECRET_KEY</code> используя команду <code>config:set</code> (как показано ниже). Не забудьте использовать свой секретный ключ!</p> + +<pre class="brush: bash notranslate">>heroku config:set DJANGO_SECRET_KEY=eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh&= + +Setting DJANGO_SECRET_KEY and restarting locallibrary... done, v7 +DJANGO_SECRET_KEY: eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh +</pre> + +<p>Аналогично мы устанавливаем <code>DJANGO_DEBUG</code>:</p> + +<pre class="brush: bash notranslate">>heroku config:set <code>DJANGO_DEBUG='' + +Setting DJANGO_DEBUG and restarting locallibrary... done, v8</code></pre> + +<p>Если вы посетите веб-сайт сейчас, вы получите ошибку "Bad request" , потому что в <a href="https://docs.djangoproject.com/en/1.10/ref/settings/#allowed-hosts">ALLOWED_HOSTS</a> надо внести параметры, если у вас <code>DEBUG=False</code> (в качестве меры безопасности). Откройте <strong>/locallibrary/settings.py</strong> и измените <code>ALLOWED_HOSTS</code> для включения вашего базового URL-адреса приложения (например, 'locallibrary1234.herokuapp.com') URL, который вы обычно используете на локальном сервере разработки.</p> + +<pre class="brush: python notranslate">ALLOWED_HOSTS = ['<your app URL without the https:// prefix>.herokuapp.com','127.0.0.1'] +# For example: +# ALLOWED_HOSTS = ['fathomless-scrubland-30645.herokuapp.com','127.0.0.1'] +</pre> + +<p>Затем сохраните настройки и передайте их в репозиторий Github и в Heroku:</p> + +<pre class="brush: bash notranslate">git add -A +git commit -m 'Update ALLOWED_HOSTS with site and development server URL' +git push origin master +git push heroku master</pre> + +<div class="note"> +<p>После завершения обновления сайта на Heroku введите URL-адрес, который не существует (например, <strong>/catalog/doesnotexist/</strong>). Раньше это отображало бы подробную страницу отладки, но теперь вы должны просто увидеть простую страницу «Не найдено».</p> +</div> + +<h3 id="Отладка">Отладка</h3> + +<p>Клиент Heroku предоставляет несколько инструментов для отладки:</p> + +<pre class="brush: bash notranslate">heroku logs # Show current logs +heroku logs --tail # Show current logs and keep updating with any new results +heroku config:set DEBUG_COLLECTSTATIC=1 # Add additional logging for collectstatic (this tool is run automatically during a build) +heroku ps #Display dyno status +</pre> + +<p>Если вам нужно больше информации, предоставленной здесь, вам нужно будет начать изучать <a href="https://docs.djangoproject.com/en/1.10/topics/logging/">Django Logging</a>.</p> + +<ul> +</ul> + +<h2 id="Итоги">Итоги</h2> + +<p>Это конец этого руководства по настройке и развёртывании приложений Django, а также серия руководств по работе с Django. Надеемся, вы нашли их полезными. Вы можете проверить полностью проработанную версию <a href="https://github.com/mdn/django-locallibrary-tutorial">по исходникам на Github</a>.<br> + Следующий шаг - прочитать наши последние несколько статей, а затем завершить оценочную задачу.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/howto/deployment/">Развёртывание Django</a> (Django docs) + + <ul> + <li><a href="https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/">Контрольный список развёртывания</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/howto/static-files/deployment/">Развёртывание статических файлов</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/">Как развернуть с WSGI</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/modwsgi/">Как использовать Django с Apache и mod_wsgi</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/gunicorn/">Как использовать Django с Gunicorn</a> (Django docs)</li> + </ul> + </li> + <li>Heroku + <ul> + <li><a href="https://devcenter.heroku.com/articles/django-app-configuration">Настройка Django приложений для Heroku</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Начало работы в Heroku с Django</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/django-assets">Django and Static Assets</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/python-concurrency-and-database-connections">Параллелизм и подключение к базе данных в Django</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/how-heroku-works">Как Heroku работает</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/dynos">Dynos and the Dyno Manager</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/config-vars">Настройка и Config Vars</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/limits">Ограничения</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/python-gunicorn">Развёртывание Python applications с Gunicorn</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/deploying-python">Развёртывание Python и Django apps в Heroku</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/search?q=django">Ещё о Heroku Django docs</a></li> + </ul> + </li> + <li>Digital Ocean + <ul> + <li><a href="https://www.digitalocean.com/community/tutorials/how-to-serve-django-applications-with-uwsgi-and-nginx-on-ubuntu-16-04">Как обслуживать Django Applications вместе с uWSGI и Nginx в Ubuntu 16.04</a></li> + <li><a href="https://www.digitalocean.com/community/tutorials?q=django">Другие документы Digital Ocean Django</a></li> + </ul> + </li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ru/learn/server-side/django/сессии/index.html b/files/ru/learn/server-side/django/сессии/index.html new file mode 100644 index 0000000000..5f7d492c72 --- /dev/null +++ b/files/ru/learn/server-side/django/сессии/index.html @@ -0,0 +1,181 @@ +--- +title: 'Руководство часть 7: Сессии' +slug: Learn/Server-side/Django/Сессии +tags: + - django + - Джанго + - Для начинающих + - Изучение + - Питон + - Руководство + - Серверная сторона + - Статья + - применение сессий + - сессии +translation_of: Learn/Server-side/Django/Sessions +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django")}}</div> + +<p class="summary">Эта часть раширяет наш сайт <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, добавляя счетчик посещений домашней страницы, реализованного при помощи сессий. Это относительно простой пример, но он демонстрирует то, как при помощи сессий реализовать анализ поведения анонимных пользователей на сайте.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Завершить изучение всех предыдущих разделов, включая <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Руководство Часть 6: Обобщенные отображения списков и детальной информации</a></td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понимать как применять сессии.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>В предыдущих частях мы создали сайт <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, который позволяет пользователям получать из каталога списки книг и авторов. На данный момент каждый посетитель сайта получает доступ к одним и тем же страницам и типам информации динамически сформированными из базы данных.</p> + +<p>В "настоящей" библиотеке вам хотелось бы предоставить пользователю индивидуальные услуги, которые зависят от его предпочтений и предыдущего опыта использования сайта, его настроек и тому подобное. Например, при очередном посещении сайта вы можете скрыть сообщения об ошибках для тех пользователей, которые их уже получали, или сохранить и учитывать пользовательские настройки (например, количество выводимых данных на странице как результат какого-либо поиска). </p> + +<p>Сессии позволяют вам реализовать такой род функциональности, который позволит вам хранить и получать произвольные данные, полученные на основе индивидуального поведения пользователя на сайте.</p> + +<h2 id="Что_такое_сессии">Что такое сессии?</h2> + +<p>Все взаимодействия между браузерами и серверами осуществляются при помощи протокола HTTP, который не сохраняет свое состояние (<em>stateless)</em>. Данный факт означает, что сообщения между клиентом и сервером являются полностью независимыми один от другого — то есть не существует какого-либо представления "последовательности", или поведения в зависимости от предыдущих сообщений. В результате, если вы хотите создать сайт который будет отслеживать взаимодействие с клиентом (браузером), вам нужно реализовать это самостоятельно.</p> + +<p>Сессии являются механизмом, который использует Django (да и весь остальной "Интернет") для отслеживания "состояния" между сайтом и каким-либо браузером. Сессии позволяют вам хранить произвольные данные браузера и получать их в тот момент, когда между данным браузером и сайтом устанавливается соединение. Данные получаются и сохраняются в сессии при помощи соответствующего "ключа".</p> + +<p>Django использует куки (cookie), которые содержат специальный <em>идентификатор сессии,</em> который выделяет среди остальных, каждый браузер и соответствующую сессию. Реальные <em>данные</em> сессии, по умолчанию, хранятся в базе данных сайта (это более безопасно, чем сохранять данные в куки, где они могут быть уязвими для злоумышленников). Однако, у вас есть возможность настроить Django так, чтобы сохранять данные сессий в других местах (кэше, файлах, "безопасных" куки). Но все же хранение по умолчанию является хорошей и безопасной возможностью.</p> + +<h2 id="Подключение_сессий">Подключение сессий</h2> + +<p>Сессии стали доступны автоматически в тот момент, когда мы <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">создали скелет сайта</a> (во второй части руководства).</p> + +<p>Необходимые конфигурации выполняются в разделах <code>INSTALLED_APPS</code> и <code>MIDDLEWARE</code> файла проекта (<strong>locallibrary/locallibrary/settings.py</strong>), как показано ниже:</p> + +<pre class="brush: python">INSTALLED_APPS = [ + ... +<strong> 'django.contrib.sessions',</strong> + .... + +MIDDLEWARE = [ + ... +<strong> 'django.contrib.sessions.middleware.SessionMiddleware',</strong> + ....</pre> + +<h2 id="Применение_сессий">Применение сессий</h2> + +<p>Вы можете получить доступ к переменной <code>session</code>, в соответствующем отображении, через параметр <code>request</code> (<code>HttpRequest</code> передается как первый аргумент в каждое отображение). Переменная сессии является связью с определенным пользователем (или, если быть более точным, связью с определенным <em>браузером</em>, который определяется при помощи идентификатора (id) сессии, получаемого из куки браузера).</p> + +<p>Переменная (или поле) <code>session</code> является объектом-словарем, который служит для чтения и записи неограниченное число раз. С ним вы можете выполнять любые стандартные операции, включая очистку всех данных, проверку наличия ключа, циклы по данным и так далее. Большую часть времени вы будете тратить на обычные "словарные" операции - получения и установки значений.</p> + +<p>Ниже представлены фрагменты кода, которые показывают вам как получать, задавать и удалять некоторые данные при помощи ключа "<code>my_car</code>", связанного с текущей сессией (браузером). </p> + +<div class="note"> +<p><strong>Примечание</strong>: Одной из самых грандиозных вещей в Django является то, что вам не надо думать о механизме, который связывает сессию с текущим запросом в отображении. Во фрагменте ниже, все что вам надо знать, это то, что <code>my_car</code> связана с тем браузером, который отправил текущий запрос.</p> +</div> + +<pre class="brush: python"># Получение значения сессии при помощи ключа(то есть, 'my_car'). +# Если такого ключа нет, то возникнет ошибка KeyError +my_car = request.session['my_car'] + +# Получение значения сессии. Если значения не существует, +# то вернется значение по умолчанию ('mini') +my_car = request.session.get('my_car', 'mini') + +# Передача значения в сессию +request.session['my_car'] = 'mini' + +# Удаление значения из сессии +del request.session['my_car'] +</pre> + +<p>Данное API имеет другие методы, которые большей частью используются для управления куки, связанных с сессией. Например, существуют методы проверки того, что куки поддерживаются клиентским браузером, другие методы служат для установки и проверки предельных дат жизни куки, а также для очистки просроченных сессий из хранилища. Подробное описание API вы можете найти в разделе <a href="https://docs.djangoproject.com/en/1.10/topics/http/sessions/">Как использовать сессии</a> (Django docs).</p> + +<h2 id="Хранение_данных_сессии">Хранение данных сессии</h2> + +<p>По умолчанию Django сохраняет данные сессии в базу данных и отправляет соответствующие куки клиенту только тогда, когда сессия была <em>изменена</em>, или <em>удалена</em>. Если вы обновляете какие-либо данные при помощи ключа сессии, как показано в предыдущем фрагменте, тогда вам не надо беспокоиться о процессе сохранения! Например:</p> + +<pre class="brush: python"># Данное присваивание распознается как обновление сессии +# и данные будут сохранены +request.session['my_car'] = 'mini'</pre> + +<p>Если вы обновлете информацию <em>внутри</em> данных сессии, тогда Django не распознает эти изменения и не выполнит сохранение данных (например, если вы изменили "<code>wheels</code>" внутри переменной "<code>my_car</code>", как показано ниже). В таких случаях вам надо явно указывать, что сессия была изменена.</p> + +<pre class="brush: python"># Объект сессии модифицируется неявно. +# Изменения НЕ БУДУТ сохранены! +request.session['my_car']['wheels'] = 'alloy' + +# Явное указание, что данные изменены. +# Сессия будет сохранена, куки обновлены (если необходимо). +<code>request.session.modified = True</code> +</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете изменить поведение сессий таким образом, чтобы они записывали любое свое изменение в базу данных и отправляли куки, при каждом запросе, путем установки <code>SESSION_SAVE_EVERY_REQUEST = True</code>, в файле настроек проекта (<strong>locallibrary/locallibrary/settings.py</strong>).</p> +</div> + +<h2 id="Простой_пример_—_получение_числа_визитов">Простой пример — получение числа визитов</h2> + +<p>В качестве примера из реального мира мы обновим нашу библиотеку так, чтобы сообщать пользователю количество совершенных им визитов главной страницы сайта <em>LocalLibrary</em>. </p> + +<p>Откройте <strong>/locallibrary/catalog/views.py</strong> и добавьте изменения, выделенных жирным, ниже. </p> + +<pre class="brush: python">def index(request): + ... + + num_authors=Author.objects.count() # The 'all()' is implied by default. + +<strong> # Number of visits to this view, as counted in the session variable. + num_visits=request.session.get('num_visits', 0) + request.session['num_visits'] = num_visits+1</strong> + + # Render the HTML template index.html with the data in the context variable. + return render( + request, + 'index.html', +<strong> context={'num_books':num_books,'num_instances':num_instances,'num_instances_available':num_instances_available,'num_authors':num_authors, + 'num_visits':num_visits}, # num_visits appended</strong> + )</pre> + +<p>В первую очередь мы получаем значение <code>'num_visits'</code> из сессии, возвращая 0, если оно не было установлено ранее. Каждый раз при получении запроса, мы увеличиваем данное значение на единицу и сохраняем его обратно в сессии (до следующего посещения данной страницы пользователем). Затем переменная <code>num_visits</code> передается в шаблон через переменную контекста <code>context</code>. </p> + +<div class="note"> +<p><strong>Примечание</strong>: Можно проверить наличие поддержки куки в браузере (для примера, смотрите <a href="https://docs.djangoproject.com/en/1.10/topics/http/sessions/">Как использовать сессии</a>), или разработать наш UI таким образом, чтобы это не имело значения.</p> +</div> + +<p>Для показа значения переменной, из следующего фрагмента добавьте нижнюю строчку кода в ваш шаблон главной страницы сайта (<strong>/locallibrary/catalog/templates/index.html</strong>), в его нижний раздел "Dynamic content":</p> + +<pre class="brush: html"><h2>Dynamic content</h2> + +<p>The library has the following record counts:</p> +<ul> +<li><strong>Books:</strong> \{{ num_books }}</li> +<li><strong>Copies:</strong> \{{ num_instances }}</li> +<li><strong>Copies available:</strong> \{{ num_instances_available }}</li> +<li><strong>Authors:</strong> \{{ num_authors }}</li> +</ul> + +<strong><p>You have visited this page \{{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.</p></strong> +</pre> + +<p>Сохраните ваши изменения и перезапустите сервер. Данное значение должно изменяться всякий раз, когда вы обновляете страницу.</p> + +<ul> +</ul> + +<h2 id="Итоги">Итоги</h2> + +<p>Вы узнали как применять сессии для улучшения взаимодейстсвие с <em>анонимными</em> пользователями. </p> + +<p>В наших следующих статьях мы рассмотрим фреймворк аутентификации и авторизации (разрешение доступа, permission), и покажем вам как поддерживать пользовательские аккаунты.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/1.10/topics/http/sessions/">Как использовать сессии</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/Authentication", "Learn/Server-side/Django")}}</p> diff --git a/files/ru/learn/server-side/express_nodejs/development_environment/index.html b/files/ru/learn/server-side/express_nodejs/development_environment/index.html new file mode 100644 index 0000000000..30000c6470 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/development_environment/index.html @@ -0,0 +1,391 @@ +--- +title: Setting up a Node development environment +slug: Learn/Server-side/Express_Nodejs/development_environment +translation_of: Learn/Server-side/Express_Nodejs/development_environment +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">Теперь, когда вы знаете, что такое Express, мы покажем вам, как настроить и протестировать среду разработки Express для Windows, Linux (Ubuntu) и Mac OS X - какую бы операционную систему вы не использовали, эта статья должна дать вам все, что необходимо для возможности начать разрабатывать приложения Express.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Знание как открыть терминал / командную строку, как устанавливать программные пакеты в операционной системе вашего компьютера.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Создать среду разработки для Express на вашем компьютере.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор_среды_разработки_Express">Обзор среды разработки Express</h2> + +<p><em>Node</em> и <em>Express</em> упрощают настройку вашего компьютера, чтобы вы могли начать разработку веб-приложений. В этом разделе объясняется, какие инструменты нужны, приводятся некоторые из самых простых способов установки Node (и Express) на Ubuntu, macOS, and Windows, и показывается как вы можете протестировать свою установку.</p> + +<h3 id="Что_такое_среда_разработки_Express">Что такое среда разработки Express?</h3> + +<p><span class="tlid-translation translation" lang="ru">Среда разработки Express включает в себя установку Nodejs, менеджера пакетов NPM и (необязательно) Express Application Generator на локальном компьютере.<br> + <br> + Узел и менеджер пакетов NPM устанавливаются вместе из подготовленных двоичных пакетов, установщиков, менеджеров пакетов операционной системы или из исходного кода (как показано в следующих разделах). Затем Express устанавливается NPM как зависимость от ваших отдельных веб-приложений Express (наряду с другими библиотеками, такими как механизмы шаблонов, драйверы баз данных, промежуточное программное обеспечение для аутентификации, промежуточное программное обеспечение для обслуживания статических файлов и т. Д.)<br> + <br> + NPM также можно использовать для (глобальной) установки Express Application Generator, удобного инструмента для создания каркасных веб-приложений Express, которые следуют шаблону MVC. Генератор приложений является необязательным, поскольку вам не нужно использовать этот инструмент для создания приложений, использующих Express, или для приложений для создан Express, имеющих одинаковую архитектурную разметку или зависимости. Мы будем использовать его, потому что это значительно облегчает начало работы и продвигает модульную структуру приложения.</span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание: в отличие от некоторых других веб-сред, среда разработки не включает отдельный веб-сервер разработки.</span> <span title="">В Node / Express веб-приложение создает и запускает собственный веб-сервер!</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Существуют и другие периферийные инструменты, которые являются частью типичной среды разработки, в том числе текстовые редакторы или IDE для редактирования кода и инструменты управления исходным кодом, такие как Git, для безопасного управления различными версиями вашего кода.</span> <span title="">Мы предполагаем, что вы уже установили подобные инструменты (в частности, текстовый редактор).</span></span></p> + +<h3 id="Какие_операционные_системы_поддерживаются"><span class="tlid-translation translation" lang="ru"><span title="">Какие операционные системы поддерживаются?</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Узел может быть запущен в Windows, macOS, во многих «разновидностях» Linux, Docker и т. Д. (Полный список на странице загрузок nodejs).</span> <span title="">Практически любой персональный компьютер должен иметь необходимую производительность для запуска Node во время разработки.</span> <span title="">Express работает в среде Node и, следовательно, может работать на любой платформе, на которой работает Node.</span><br> + <br> + <span title="">В этой статье мы предоставляем инструкции по установке для Windows, macOS и Ubuntu Linux.</span></span></p> + +<h3 id="Какую_версию_Node_Express_следует_использовать"><span class="tlid-translation translation" lang="ru"><span title="">Какую версию Node / Express следует использовать?</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Существует множество выпусков Node - более новые выпуски содержат исправления ошибок, поддержку более свежих версий стандартов ECMAScript (JavaScript) и улучшения API-интерфейсов Node.</span><br> + <br> + <span title="">Как правило, вы должны использовать самый последний выпуск LTS (с долгосрочной поддержкой), поскольку он будет более стабильным, чем «текущий» выпуск, при этом все еще имея относительно недавние функции (и все еще активно поддерживается).</span> <span title="">Вы должны использовать Текущий выпуск, если вам нужна функция, которой нет в версии LTS.</span><br> + <br> + <span title="">Для Express вы всегда должны использовать последнюю версию.</span></span></p> + +<h3 id="Как_насчет_баз_данных_и_других_зависимостей"><span class="tlid-translation translation" lang="ru"><span title="">Как насчет баз данных и других зависимостей?</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Другие зависимости, такие как драйверы баз данных, механизмы шаблонов, механизмы аутентификации и т. д., Являются частью приложения и импортируются в среду приложения с помощью диспетчера пакетов NPM.</span> <span title="">Мы обсудим их в следующих статьях для конкретных приложений.</span></span></p> + +<h2 id="Установка_Node">Установка Node</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Чтобы использовать Express, сначала необходимо установить Nodejs и Node Package Manager (NPM) в вашей операционной системе.</span> <span title="">В следующих разделах описывается самый простой способ установки версии Nodejs с долгосрочной поддержкой (LTS) в Ubuntu Linux 16.04, macOS и Windows 10.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Совет: В следующих разделах показан самый простой способ установки Node и NPM на наши целевые платформы ОС.</span> <span title="">Если вы используете другую ОС или просто хотите увидеть некоторые другие подходы для текущих платформ, см. Установка Node.js через менеджер пакетов (nodejs.org).</span></span></p> +</div> + +<h3 id="Windows_и_macOS">Windows и macOS</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Установка Node и NPM в Windows и macOS проста, потому что вы можете просто использовать предоставленный инсталлятор:</span></span></p> + +<ol> + <li><span class="tlid-translation translation" lang="ru"><span title="">Загрузите необходимый установщик:</span></span> + + <ol> + <li>Перейдите по ссылке <a href="https://nodejs.org/en/">https://nodejs.org/en/</a></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Нажмите кнопку, чтобы загрузить сборку LTS, которая «Рекомендуется для большинства пользователей».</span></span></li> + </ol> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Установите Node, дважды щелкнув по загруженному файлу и следуя инструкциям по установке.</span></span></li> +</ol> + +<h3 id="Ubuntu_16.04">Ubuntu 16.04</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Самый простой способ установить последнюю версию LTS Node 6.x - это использовать</span></span> <a href="https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions">package manager</a> <span class="tlid-translation translation" lang="ru"><span title="">чтобы получить его из репозитория бинарных дистрибутивов Ubuntu.</span> <span title="">Это можно сделать очень просто, выполнив следующие две команды на вашем терминале:</span></span></p> + +<pre class="brush: bash notranslate"><code>curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - +sudo apt-get install -y nodejs</code> +</pre> + +<div class="warning"> +<p><strong>Внимание:</strong> <span class="tlid-translation translation" lang="ru"><span title="">Не устанавливайте напрямую из обычных репозиториев Ubuntu, поскольку они содержат очень старые версии узла.</span></span></p> +</div> + +<ol> +</ol> + +<h3 id="Проверка_вашей_установки_Nodejs_и_NPM">Проверка вашей установки Nodejs и NPM</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Самый простой способ проверить, установлен ли этот узел, - это запустить команду «версия» в своем терминале / командной строке и проверить, что возвращается строка версии:</span></span></p> + +<pre class="brush: bash notranslate">>node -v +v8.11.3</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Менеджер пакетов Nodejs NPM также должен быть установлен и может быть протестирован таким же образом:</span></span></p> + +<pre class="brush: bash notranslate">>npm -v +5.8.0</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В качестве немного более захватывающего теста давайте создадим очень простой сервер «чистого узла», который просто печатает «Hello World» в браузере, когда вы посещаете правильный URL в вашем браузере:</span></span></p> + +<ol> + <li><span class="tlid-translation translation" lang="ru"><span title="">Скопируйте следующий текст в файл с именем hellonode.js.</span> <span title="">Здесь используются чистые функции Node (ничего из Express) и некоторый синтаксис ES6:</span></span> + + <pre class="brush: js notranslate">//Загрузка моделя HTTP +const http = require("http"); +<code>const hostname = '127.0.0.1'; +const port = 3000; + +//Создание HTTP-сервера +const server = http.createServer((req, res) => { + + //Установка HTTP-заголовков ответа с HTTP-статусом и Content type + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('Hello World\n'); +}); + +//Слушание запросов на порту 3000, и в качестве каллбака функция, которая пишет в лог +server.listen(port, hostname, () => { + console.log('Server running at http://${hostname}:${port}/'); +});</code> + +</pre> + + <p><span class="tlid-translation translation" lang="ru"><span title="">Код импортирует модуль «http» и использует его для создания сервера (createServer ()), который прослушивает HTTP-запросы на порту 3000. Затем сценарий выводит на консоль сообщение о том, какой URL-адрес браузера можно использовать для тестирования сервера.</span> <span title="">Функция createServer () принимает в качестве аргумента функцию обратного вызова, которая будет вызываться при получении HTTP-запроса - она просто возвращает ответ с кодом состояния HTTP 200 («ОК») и простым текстом «Hello World».</span></span></p> + + <div class="note"> + <p><span class="tlid-translation translation" lang="ru"><span title="">Замечание: не беспокойтесь, если вы еще не совсем понимаете, что делает этот код!</span> <span title="">Мы объясним наш код более подробно, как только мы начнем использовать Express!</span></span></p> + </div> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Запустите сервер, перейдя в тот же каталог, что и ваш файл hellonode.js в командной строке, и вызвав узел вместе с именем скрипта, например так:</span></span> + <pre class="brush: bash notranslate">>node hellonode.js +Server running at http://127.0.0.1:3000/ +</pre> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Перейдите к URL-адресу http://127.0.0.1:3000.</span> <span title="">Если все работает, браузер должен просто отобразить строку «Hello World».</span></span></li> +</ol> + +<h2 id="Использование_NPM">Использование NPM</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Помимо самого Node, NPM является наиболее важным инструментом для работы с приложениями Node.</span> <span title="">NPM используется для получения любых пакетов (библиотек JavaScript), которые необходимы приложению для разработки, тестирования и / или производства, а также может использоваться для запуска тестов и инструментов, используемых в процессе разработки.</span></span></p> + +<div class="note"> +<p><strong>Замечание:</strong> <span class="tlid-translation translation" lang="ru"><span title="">С точки зрения Node, Express - это просто еще один пакет, который вам нужно установить с помощью NPM, а затем установить его в своем собственном коде.</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете вручную использовать NPM для получения каждого необходимого пакета отдельно.</span> <span title="">Обычно мы вместо этого управляем зависимостями, используя простой текстовый файл с именем package.json.</span> <span title="">В этом файле перечислены все зависимости для конкретного «пакета» JavaScript, включая имя пакета, версию, описание, исходный файл для выполнения, производственные зависимости, зависимости разработки, версии Node, с которыми он может работать, и т. Д. Файл package.json должен</span> <span title="">содержать все, что нужно NPM для загрузки и запуска вашего приложения (если вы пишете библиотеку многократного использования, вы можете использовать это определение для загрузки пакета в репозиторий npm и сделать его доступным для других пользователей).</span></span></p> + +<h3 id="Добавление_зависимостей">Добавление зависимостей</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Следующие шаги показывают, как вы можете использовать NPM для загрузки пакета, сохранить его в зависимостях проекта, а затем потребовать его в приложении Node.</span></span></p> + +<div class="note"> +<p><strong>Замечание:</strong> <span class="tlid-translation translation" lang="ru"><span title="">Здесь мы показываем инструкции для получения и установки пакета Express.</span> <span title="">Позже мы покажем, как этот пакет и другие уже указаны для нас с помощью Express Application Generator.</span> <span title="">Этот раздел предоставлен, потому что полезно понять, как работает NPM и что создается генератором приложений.</span></span></p> +</div> + +<ol> + <li><span class="tlid-translation translation" lang="ru"><span title="">Сначала создайте каталог для вашего нового приложения и перейдите в него:</span></span> + + <pre class="brush: bash notranslate">mkdir myapp +cd myapp</pre> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Используйте команду npm init для создания файла package.json для вашего приложения.</span> <span title="">Эта команда запрашивает у вас несколько вещей, включая имя и версию вашего приложения, а также имя исходного файла точки входа (по умолчанию это index.js).</span> <span title="">Сейчас просто примите значения по умолчанию:</span></span> + <pre class="brush: bash notranslate">npm init</pre> + + <p><span class="tlid-translation translation" lang="ru"><span title="">Если вы отобразите файл package.json (cat package.json), вы увидите принятые по умолчанию значения, заканчивающиеся лицензией.</span></span></p> + + <pre class="brush: json notranslate">{ + "name": "myapp", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} +</pre> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Теперь установите Express в каталог myapp и сохраните его в списке зависимостей вашего файла package.json</span></span></li> + <li> + <pre class="brush: bash notranslate">npm install express --save</pre> + + <p><span class="tlid-translation translation" lang="ru"><span title="">Раздел зависимостей вашего package.json теперь появится в конце файла package.json и будет содержать Express.</span></span></p> + + <pre class="brush: json notranslate">{ + "name": "myapp", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", +<strong> "dependencies": { + "express": "^4.16.3" + }</strong> +} +</pre> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Для использования библиотеки вы вызываете функцию require (), как показано ниже в вашем файле index.js.</span></span> + <pre class="notranslate"><code><strong>const express = require('express')</strong> +const app = express(); + +app.get('/', (req, res) => { + res.send('Hello World!') +}); + +app.listen(</code>8000<code>, () => { + console.log('Example app listening on port </code>8000<code>!') +});</code> +</pre> + + <p><span class="tlid-translation translation" lang="ru"><span title="">Этот код показывает минимальное веб-приложение Express «HelloWorld».</span> <span title="">Это импортирует модуль «экспресс» и использует его для создания сервера (приложения), который прослушивает HTTP-запросы на порту 8000 и выводит на консоль сообщение, объясняющее, какой URL-адрес браузера можно использовать для тестирования сервера.</span> <span title="">Функция app.get () отвечает только на запросы HTTP GET с указанным URL-путем ('/'), в этом случае вызывая функцию для отправки нашего Hello World!</span> <span title="">сообщение.</span></span><br> + <br> + <span class="tlid-translation translation" lang="ru"><span title="">Создайте файл с именем index.js в корне каталога приложения «myapp» и передайте ему содержимое, показанное выше.</span></span></p> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Вы можете запустить сервер, вызвав узел с помощью скрипта в командной строке:</span></span> + <pre class="brush: bash notranslate">>node index.js +Example app listening on port 8000 +</pre> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Перейдите к URL </span></span> (<a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>) <span class="tlid-translation translation" lang="ru"><span title="">.</span> <span title="">Если все работает, браузер должен просто отобразить строку «Hello World!».</span></span></li> +</ol> + +<h3 id="Зависимости_разработки">Зависимости разработки</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Если зависимость используется только во время разработки, вы должны вместо этого сохранить ее как «зависимость разработки» (чтобы пользователям вашего пакета не приходилось устанавливать ее в производстве).</span> <span title="">Например, чтобы использовать популярный инструмент JavaScript Linting eslint, вы должны вызвать NPM, как показано ниже:</span></span></p> + +<pre class="brush: bash notranslate"><code>npm install eslint --save-dev</code></pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Следующая запись будет добавлена в package.json вашего приложения:</span></span></p> + +<pre class="brush: js notranslate"> "devDependencies": { + "eslint": "^4.12.1" + } +</pre> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание: «Линтеры» - это инструменты, которые выполняют статический анализ программного обеспечения, чтобы распознавать и сообщать о приверженности / несоблюдении некоторого набора лучших практик кодирования.</span></span></p> +</div> + +<h3 id="Запуск_задач"><span class="tlid-translation translation" lang="ru"><span title="">Запуск задач</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В дополнение к определению и извлечению зависимостей вы также можете определить именованные скрипты в ваших файлах package.json и вызвать NPM, чтобы выполнить их с помощью команды run-script.</span> <span title="">Этот подход обычно используется для автоматизации выполнения тестов и частей набора инструментов разработки или сборки (например, запуска инструментов для минимизации JavaScript, сжатия изображений, LINT / анализа вашего кода и т. Д.).</span></span></p> + +<div class="note"> +<p><strong>Замечание:</strong> <span class="tlid-translation translation" lang="ru"><span title="">Для запуска тестов и других внешних инструментов могут также использоваться такие исполнители, как Gulp и Grunt.</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Например, чтобы определить скрипт для запуска зависимости разработки eslint, которую мы указали в предыдущем разделе, мы могли бы добавить следующий блок скрипта в наш файл package.json (при условии, что наш источник приложения находится в папке / src / js):</span></span></p> + +<pre class="brush: js notranslate">"scripts": { + ... + "lint": "eslint src/js" + ... +} +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Чтобы пояснить немного подробнее, eslint src / js - это команда, которую мы могли бы ввести в нашем терминале / командной строке, чтобы запустить eslint для файлов JavaScript, содержащихся в каталоге src / js внутри каталога нашего приложения.</span> <span title="">Включение вышеупомянутого в файл package.json нашего приложения обеспечивает ярлык для этой команды - lint.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Затем мы сможем запустить eslint с помощью NPM, вызвав:</span></span></p> + +<pre class="brush: bash notranslate"><code>npm run-script lint +# OR (using the alias) +npm run lint</code> +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Этот пример может выглядеть не короче, чем исходная команда, но вы можете включить в свои сценарии npm гораздо более крупные команды, включая цепочки из нескольких команд.</span> <span title="">Вы можете определить один скрипт npm, который запускает все ваши тесты одновременно.</span></span></p> + +<h2 id="Установка_Express_Application_Generator">Установка Express Application Generator</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Инструмент Express Application Generator создает «скелет» приложения Express.</span> <span title="">Установите генератор, используя NPM, как показано (флаг -g устанавливает инструмент глобально, чтобы вы могли вызывать его из любого места):</span></span></p> + +<pre class="notranslate"><code>npm install express-generator -g</code></pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Чтобы создать приложение Express с именем «helloworld» с настройками по умолчанию, перейдите туда, где вы хотите его создать, и запустите приложение, как показано ниже:</span></span></p> + +<pre class="brush: bash notranslate">express helloworld</pre> + +<div class="note"> +<p><strong>Замечание:</strong> <span class="tlid-translation translation" lang="ru"><span title="">Вы также можете указать библиотеку шаблонов для использования и ряд других настроек.</span> <span title="">Используйте команду help, чтобы увидеть все параметры:</span></span></p> + +<pre class="brush: bash notranslate">express --help +</pre> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">NPM создаст новое приложение Express в подпапке вашего текущего местоположения, отображая процесс сборки на консоли.</span> <span title="">По завершении инструмент отобразит команды, которые необходимо ввести, чтобы установить зависимости Node и запустить приложение.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Новое приложение будет иметь файл package.json в своем корневом каталоге.</span> <span title="">Вы можете открыть это, чтобы увидеть, какие зависимости установлены, включая Express и библиотеку шаблонов Jade:</span></span></p> + +<pre class="brush: js notranslate">{ + "name": "helloworld", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www" + }, + "dependencies": { + "body-parser": "~1.18.2", + "cookie-parser": "~1.4.3", + "debug": "~2.6.9", + "express": "~4.15.5", + "jade": "~1.11.0", + "morgan": "~1.9.0", + "serve-favicon": "~2.4.5" + } +}</pre> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Установите все зависимости для приложения helloworld, используя NPM, как показано ниже:</span></span></p> + +<pre class="brush: bash notranslate">cd helloworld +npm install +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Затем запустите приложение (команды немного отличаются для Windows и Linux / macOS), как показано ниже:</span></span></p> + +<pre class="brush: bash notranslate"># Run the helloworld on Windows with Command Prompt +SET DEBUG=helloworld:* & npm start + +# Run the helloworld on Windows with PowerShell +SET DEBUG=helloworld:* | npm start + +# Run helloworld on Linux/macOS +DEBUG=helloworld:* npm start +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Команда DEBUG создает полезное ведение журнала, что приводит к выводу, подобному показанному ниже.</span></span></p> + +<pre class="brush: bash notranslate">>SET DEBUG=helloworld:* & npm start + +> helloworld@0.0.0 start D:\Github\expresstests\helloworld +> node ./bin/www + + helloworld:server Listening on port 3000 +0ms</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Откройте браузер и перейдите по адресу http://127.0.0.1:3000/, чтобы увидеть страницу приветствия Express по умолчанию.</span></span></p> + +<p><img alt="Express - Generated App Default Screen" src="https://mdn.mozillademos.org/files/14331/express_default_screen.png" style="border-style: solid; border-width: 1px; display: block; height: 301px; margin: 0px auto; width: 675px;"></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Мы поговорим больше о сгенерированном приложении, когда перейдем к статье о создании каркасного приложения.</span></span></p> + +<ul> +</ul> + +<h2 id="Резюме">Резюме</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Теперь на вашем компьютере установлена и запущена среда разработки Node, которую можно использовать для создания веб-приложений Express.</span> <span title="">Вы также увидели, как NPM можно использовать для импорта Express в приложение, а также как вы можете создавать приложения с помощью инструмента Express Application Generator и затем запускать их.</span><br> + <br> + <span title="">В следующей статье мы начнем работу с учебным пособием по созданию полноценного веб-приложения с использованием этой среды и связанных инструментов.</span></span></p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://nodejs.org/en/download/">Downloads</a> page (nodejs.org)</li> + <li><a href="https://nodejs.org/en/download/package-manager/">Installing Node.js via package manager</a> (nodejs.org)</li> + <li><a href="http://expressjs.com/en/starter/installing.html">Installing Express</a> (expressjs.com)</li> + <li><a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a> (expressjs.com)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html new file mode 100644 index 0000000000..2e1edbc625 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html @@ -0,0 +1,85 @@ +--- +title: Список авторов. Тест - список жанров +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page +--- +<p>Страница списка авторов должна показывать список всех авторов, хранимых в БД, причем каждое имя автора должно быть связано со страницей подробностей для этого автора. Дата рождения автора и дата смерти должны выводиться в одной строке после имени автора.</p> + +<h2 class="highlight-spanned" id="Контроллер"><span class="highlight-span">Контроллер</span></h2> + +<p>Функция контроллера списка авторов должна получить список всех элементов в <code>Author</code> , и передать этот список в шаблон для отображения.</p> + +<p>Откройте файл <strong>/controllers/authorController.js</strong>. Найдите экспортируемый метод <code>author_list()</code> в начале файла и замените его следующим ниже кодом:</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display list of all Authors.</span> +exports<span class="punctuation token">.</span>author_list <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span> + + Author<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">)</span> + <span class="punctuation token">.</span><span class="function token">sort</span><span class="punctuation token">(</span><span class="punctuation token">[</span><span class="punctuation token">[</span><span class="string token">'family_name'</span><span class="punctuation token">,</span> <span class="string token">'ascending'</span><span class="punctuation token">]</span><span class="punctuation token">]</span><span class="punctuation token">)</span> + <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> list_authors<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span> + <span class="comment token">//Successful, so render</span> + res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'author_list'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Author List'</span><span class="punctuation token">,</span> author_list<span class="punctuation token">:</span> list_authors <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + +<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre> + +<p>Метод использует такие функции модели как <code>find()</code>, <code>sort()</code> и <code>exec()</code> для того, чтобы вернуть все объекты <code>Author</code> отсортированными по <code>family_name</code> в алфавитном порядке. В вызове <code>exec()</code> callback-функция имеет первый параметр- объект ошибок (или <code>null</code>) и второй параметр - список всех авторов, если ошибок не было. При ошибках вызывается следующая функция промежуточного слоя с полученным значением объекта ошибок, а если ошибок не было, отображается шаблон <strong>author_list</strong>(.pug), передавая странице <code>title</code> и список авторов (<code>author_list</code>).</p> + +<h2 class="highlight-spanned" id="Представление"><span class="highlight-span">Представление</span></h2> + +<p>Создайте файл <strong>/views/author_list.pug</strong> и поместите в него следующий текст:</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">extends</span> <span class="class-name token">layout</span> + +block content + h1<span class="operator token">=</span> title + + ul + each author <span class="keyword token">in</span> author_list + li + <span class="function token">a</span><span class="punctuation token">(</span>href<span class="operator token">=</span>author<span class="punctuation token">.</span>url<span class="punctuation token">)</span> #<span class="punctuation token">{</span>author<span class="punctuation token">.</span>name<span class="punctuation token">}</span> + <span class="operator token">|</span> <span class="punctuation token">(</span>#<span class="punctuation token">{</span>author<span class="punctuation token">.</span>date_of_birth<span class="punctuation token">}</span> <span class="operator token">-</span> #<span class="punctuation token">{</span>author<span class="punctuation token">.</span>date_of_death<span class="punctuation token">}</span><span class="punctuation token">)</span> + + <span class="keyword token">else</span> + li There are no authors<span class="punctuation token">.</span></code></pre> + +<p>Представление создано по тому же образцу, что и другие шаблоны.</p> + +<h2 class="highlight-spanned" id="Как_это_выглядит"><span class="highlight-span">Как это выглядит?</span></h2> + +<p>Запустите приложение и откройте браузер с адресом <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>. Выберите ссылку <em>All authors</em>. Если все было сделано правильно, страница должна выглядеть примерно нак, как на следующем скриншоте.</p> + +<p><img alt="Author List Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14468/LocalLibary_Express_Author_List.png" style="display: block; height: 453px; margin: 0px auto; width: 1200px;"></p> + +<div class="note"> +<p><strong>Заметка:</strong> Представление дат продолжительности жизни автора выгядит безобразно! Это можно исправить, если использовать <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data#date_formatting">тот же подход</a> , который применялся для списка <code>BookInstance</code> (добавить в модель <code>Author</code> виртуальное свойство продолжительности жизни). Но в этот раз, однако, некоторые даты могут отсутствовать, и ссылки на несуществующие свойства игнорируются, если не задан строгий режим. Метод <code>moment()</code> возврашает текущее время, и нежелательно, чтобы отсутствующие даты форматировались как "сегодня". Один из способов состоит в том, чтобы форматирующая функция возвращала пустую строку, если дата не существует. Например:</p> + +<p><code>return this.date_of_birth ? moment(this.date_of_birth).format('YYYY-MM-DD') : '';</code></p> +</div> + +<h2 id="Тест_-_страница_списка_жанров!Edit">Тест - страница списка жанров!<a class="button section-edit only-icon" href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data$edit#Genre_list_page—challenge!" rel="nofollow, noindex"><span>Edit</span></a></h2> + +<p>В этой части требуется создать собственную страницу списка жанров. Страница должна показывать жанры, имеющиеся в БД, а для каждого жанра должна быть создана ссылка на страницу с детальной информацией. Скриншот ожидаемого результата приводится ниже.</p> + +<p><img alt="Genre List - Express Local Library site" src="https://mdn.mozillademos.org/files/14460/LocalLibary_Express_Genre_List.png" style="border-style: solid; border-width: 1px; display: block; height: 346px; margin: 0px auto; width: 600px;"></p> + +<p>Функция контроллера списка жанров должна получить список всех экземпляров <code>Genre</code>, и передать его в шаблон для отображения.</p> + +<ol> + <li>Следует отредактировать <code>genre_list()</code> в файле <strong>/controllers/genreController.js</strong>. </li> + <li>Реализация почти такая же, как и для контроллера <code>author_list()</code> . + <ul> + <li>Sort the results by name, in ascending order.</li> + </ul> + </li> + <li>Отображающий шаблон должен быть назван <strong>genre_list.pug</strong>.</li> + <li>Шаблону для отображения должны быть переданы переменные <code>title</code> (строка 'Genre List') и <code>genre_list</code> (the list of список жанров, который вернет callback-функция <code>Genre.find()</code>.</li> + <li>Представление должно соответствовать скриншоту, приведенному ранее (оно должно иметь структуру и формат, похожие на таковые в представлении списка авторов, за исключением, конечно, продолжительности жизни, так как для жанров даты не заданы).</li> +</ol> + +<h2 id="Далее">Далее</h2> + +<p>Вернуться к части 5 - <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</p> + +<p>Перейти к следующему подразделу в части 5: подробная информация о жанрах (<a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page">Genre detail page</a>).</p> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html new file mode 100644 index 0000000000..b5a4400d90 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html @@ -0,0 +1,68 @@ +--- +title: Страница списка книг +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page +--- +<p>Далее мы реализуем нашу страницу списка книг. На этой странице должен отображаться список всех книг и их авторов в базе данных, причем каждое название книги является гиперссылкой на соответствующую страницу сведений о книге.</p> + +<h2 class="highlight-spanned" id="Контроллер"><span class="highlight-span">Контроллер</span></h2> + +<p>Функция контроллера списка книг должна получить список всех объектов <code>Book</code> в базе данных, а затем передать их для отрисовки шаблона.</p> + +<p>Откройте файл <strong>/controllers/bookController.js</strong>. Найдите экспортируемый метод контроллера <code>book_list()</code> и замените его следующим кодом.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display list of all Books.</span> +exports<span class="punctuation token">.</span>book_list <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span> + + Book<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">{</span><span class="punctuation token">}</span><span class="punctuation token">,</span> <span class="string token">'title author'</span><span class="punctuation token">)</span> + <span class="punctuation token">.</span><span class="function token">populate</span><span class="punctuation token">(</span><span class="string token">'author'</span><span class="punctuation token">)</span> + <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> list_books<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span> + <span class="comment token">//Successful, so render</span> + res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'book_list'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Book List'</span><span class="punctuation token">,</span> book_list<span class="punctuation token">:</span> list_books <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + +<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre> + +<p>Метод использует функцию модели<code>find()</code> для возврата всех объектов <code>Book</code>, выбрав для возврата только заголовок и автора, поскольку нам не нужны другие поля (он также вернет <code>_id</code> и виртуальные поля). Здесь мы также вызываем <code>populate()</code> on <code>Book</code>, указывая поле <code>author</code> —это заменит сохраненный идентификатор автора книги полными сведениями об авторе.</p> + +<p>При успешном выполнении, обратный вызов передаст запрос на отрисовку шаблона <strong>book_list</strong>(.pug), передаст <code>title</code> и<code>book_list</code> (список книг с автором) в качестве переменных.</p> + +<h2 class="highlight-spanned" id="Представление"><span class="highlight-span">Представление</span></h2> + +<p>Создайте файл <strong>/views/book_list.pug</strong> и скопируйте в него текст ниже.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">extends</span> <span class="class-name token">layout</span> + +block content + h1<span class="operator token">=</span> title + + ul + each book <span class="keyword token">in</span> book_list + li + <span class="function token">a</span><span class="punctuation token">(</span>href<span class="operator token">=</span>book<span class="punctuation token">.</span>url<span class="punctuation token">)</span> #<span class="punctuation token">{</span>book<span class="punctuation token">.</span>title<span class="punctuation token">}</span> + <span class="operator token">|</span> <span class="punctuation token">(</span>#<span class="punctuation token">{</span>book<span class="punctuation token">.</span>author<span class="punctuation token">.</span>name<span class="punctuation token">}</span><span class="punctuation token">)</span> + + <span class="keyword token">else</span> + li There are no books<span class="punctuation token">.</span></code></pre> + +<p>View расширит базовый шаблон <strong>layout.pug</strong> и переопределит <code>block</code> с именем '<strong>content</strong>'. Он отображает <code>title</code> который мы передали из контроллера (с помощью метода <code>render()</code> ), а затем перебирает переменную <code>book_list</code> используя синтаксис <code>each</code>-<code>in</code>-<code>else</code> . Для каждой книги создается элемент списка, отображающий название книги в виде ссылки на страницу сведений о книге, за которой следует имя автора. Если в <code>book_list</code> нет книг, то выполняется <code>else</code>, и отображается текст "нет книг".'</p> + +<div class="note"> +<p><strong>Заметка: </strong>Мы используем <code>book.url</code> для предоставления ссылки на подробную запись для каждой книги (мы реализовали этот маршрут, но не страницу). Это виртуальное свойство модели <code>Book</code> , которая использует поле <code>_id</code> для создания уникального URL.</p> +</div> + +<p>Здесь интересно, что каждая книга определена в двух строках, использование конвейера для второй строки (выделено выше) необходимо, чтобы имя автора не стало частью гиперссылки из первой строки.</p> + +<h2 class="highlight-spanned" id="На_что_это_похоже">На что это похоже?</h2> + +<p>Запустите приложение (смотрите <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes#Testing_the_routes">тестирование маршрутов</a> для соответствующей команды) и откройте ваш браузер по адресу: <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>. Затем выберите ссылку: <em>All books</em>. Если все сделано корректно, то вы должны увидеть нечто подобное скриншоту ниже.</p> + +<p><img alt="Book List Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14464/LocalLibary_Express_Book_List.png" style="border-style: solid; border-width: 1px; display: block; height: 387px; margin: 0px auto; width: 918px;"></p> + +<h2 id="Next_steps">Next steps</h2> + +<ul> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li> + <li>Proceed to the next subarticle of part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page">BookInstance list page</a>.</li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html new file mode 100644 index 0000000000..512e78d040 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html @@ -0,0 +1,69 @@ +--- +title: Список экземпляров книг +slug: Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page +--- +<p>Далее мы реализуем список всех имеющихся в библиотеке копий книги (<code>BookInstance</code>) . Эта страница должна включать название книги из <code>Book</code>, с которой связаны экземпляры <code>BookInstance</code> (linked to its detail page), а такжде дополнительнцю информацию, имеющуюся в модели <code>BookInstance</code>, включая статус, издание, и уникальный идентификатор каждой копии. Уникальное значение идентификатора копии должно быть связано со страницей детальной информации <code>BookInstance</code>.</p> + +<h2 class="highlight-spanned" id="Контроллер"><span class="highlight-span">Контроллер</span></h2> + +<p>Функция контроллера списка <code>BookInstance</code> требуется для получения списка всех экземпляров некоторой книги, для получения информации, связанной с книгой, и для передачиполученного списка в шаблог для отображения.</p> + +<p>Откройте файл <strong>/controllers/bookinstanceController.js</strong>. Найдите экспортируемый метод <code>bookinstance_list()</code> контроллера и замените его следующим кодом (измененный код выделен жирным).</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display list of all BookInstances.</span> +exports<span class="punctuation token">.</span>bookinstance_list <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span> + + <strong>BookInstance<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">)</span> + <span class="punctuation token">.</span><span class="function token">populate</span><span class="punctuation token">(</span><span class="string token">'book'</span><span class="punctuation token">)</span> + <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> list_bookinstances<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span> + <span class="comment token">// Successful, so render</span> + res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'bookinstance_list'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Book Instance List'</span><span class="punctuation token">,</span> bookinstance_list<span class="punctuation token">:</span> list_bookinstances <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span></strong> + +<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre> + +<p>Чтобы вернуть все объекты <code>BookInstance,</code> метод использует функцию <code>find()</code> модели. Далее в цепочке вызывается метод <code>populate()</code> с аргументом - полем <code>book,</code> что приводит к замене идентификатора id, хранящегося для каждого экземпляра <code>BookInstance</code> полным документом <code>Book</code>.</p> + +<p>При удаче, callback-функция, переданная запросу, заполняет шаблон <strong>bookinstance_list</strong>(.pug), передав переменные <code>title</code> и <code>bookinstance_list</code>.</p> + +<h2 class="highlight-spanned" id="Представление">Представление</h2> + +<p>Создайте файл <strong>/views/bookinstance_list.pug</strong> и скопируйте в него текст, приведенный ниже.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">extends</span> <span class="class-name token">layout</span> + +block content + h1<span class="operator token">=</span> title + + ul + each val <span class="keyword token">in</span> bookinstance_list + li + <span class="function token">a</span><span class="punctuation token">(</span>href<span class="operator token">=</span>val<span class="punctuation token">.</span>url<span class="punctuation token">)</span> #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>book<span class="punctuation token">.</span>title<span class="punctuation token">}</span> <span class="punctuation token">:</span> #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>imprint<span class="punctuation token">}</span> <span class="operator token">-</span> + <span class="keyword token">if</span> val<span class="punctuation token">.</span>status<span class="operator token">==</span><span class="string token">'Available'</span> + span<span class="punctuation token">.</span>text<span class="operator token">-</span>success #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>status<span class="punctuation token">}</span> + <span class="keyword token">else</span> <span class="keyword token">if</span> val<span class="punctuation token">.</span>status<span class="operator token">==</span><span class="string token">'Maintenance'</span> + span<span class="punctuation token">.</span>text<span class="operator token">-</span>danger #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>status<span class="punctuation token">}</span> + <span class="keyword token">else</span> + span<span class="punctuation token">.</span>text<span class="operator token">-</span>warning #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>status<span class="punctuation token">}</span> + <span class="keyword token">if</span> val<span class="punctuation token">.</span>status<span class="operator token">!=</span><span class="string token">'Available'</span> + span <span class="function token"> </span><span class="punctuation token">(</span>Due<span class="punctuation token">:</span> #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>due_back<span class="punctuation token">}</span> <span class="punctuation token">)</span> + + <span class="keyword token">else</span> + li There are no book copies <span class="keyword token">in</span> <span class="keyword token">this</span> library<span class="punctuation token">.</span></code></pre> + +<p>This view is much the same as all the others. It extends the layout, replacing the <em>content</em> block, displays the <code>title</code> passed in from the controller, and iterates through all the book copies in <code>bookinstance_list</code>. For each copy we display its status (colour coded) and if the book is not available, its expected return date. One new feature is introduced—we can use dot notation after a tag to assign a class. So <code>span.text-success</code> will be compiled to <code><span class="text-success"></code> (and might also be written in Pug as <code>span(class="text-success")</code>.</p> + +<h2 class="highlight-spanned" id="What_does_it_look_like"><span class="highlight-span">What does it look like?</span></h2> + +<p>Run the application, open your browser to <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>, then select the <em>All book-instances </em>link. If everything is set up correctly, your site should look something like the following screenshot.</p> + +<p><img alt="BookInstance List Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14474/LocalLibary_Express_BookInstance_List.png" style="border-style: solid; border-width: 1px; display: block; height: 322px; margin: 0px auto; width: 1200px;"></p> + +<h2 id="Next_steps">Next steps</h2> + +<ul> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li> + <li>Proceed to the next subarticle of part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment">Date formatting using moment</a>.</li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html new file mode 100644 index 0000000000..58f297ce95 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html @@ -0,0 +1,60 @@ +--- +title: Форматирование даты при помощи moment +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment +--- +<p>По умолчанию отображение дат наших моделей некрасиво: <em>Tue Dec 06 2016 15:49:58 GMT+1100 (AUS Eastern Daylight Time)</em>. В этом разделе мы покажем, как можно обновить страницу списка <em>BookInstance List </em>из предыдущего раздела, чтобы представитьполе <code>due_date</code> в более удобном формате: December 6th, 2016. </p> + +<p>Подход, который будет использован, состоит в создании виртуального свойства в модели <code>BookInstance</code>, которое будет возращать отформатированную дату. Форматирование будет производиться с использованием <a class="external external-icon" href="https://www.npmjs.com/package/moment" rel="noopener">moment</a>, легковесной библиотеки JavaScript для разбора, проверки, изменения и форматирования дат.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Можно применять <em>moment</em> для форматирования непосредственно в шаблонах Pug, а можно отформатировать строку в других местах. Использование виртуального свойства позволяет получить дату, отформатированную точно так же, как при помощи <code>due_date</code>. </p> +</div> + +<h2 class="highlight-spanned" id="Установка_moment"><span class="highlight-span">Установка moment</span></h2> + +<p>Ведите следующую команду в корне проекта:</p> + +<pre class="brush: bash line-numbers language-bash"><code class="language-bash">npm install moment</code></pre> + +<h2 class="highlight-spanned" id="Создание_виртуального_свойства"><span class="highlight-span">Создание виртуального свойства</span></h2> + +<ol> + <li>Откройте файл <strong>./models/bookinstance.js</strong>.</li> + <li>В начало файла введите строку для импортирования <em>moment</em>. + <pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">var</span> moment <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'moment'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + </li> +</ol> + +<p>Добавьте виртуальное свойство <code>due_back_formatted</code> сразу после свойства url.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js">BookInstanceSchema +<span class="punctuation token">.</span><span class="function token">virtual</span><span class="punctuation token">(</span><span class="string token">'due_back_formatted'</span><span class="punctuation token">)</span> +<span class="punctuation token">.</span><span class="keyword token">get</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">return</span> <span class="function token">moment</span><span class="punctuation token">(</span><span class="keyword token">this</span><span class="punctuation token">.</span>due_back<span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">format</span><span class="punctuation token">(</span><span class="string token">'MMMM Do, YYYY'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<div class="note"> +<p><strong>Заметка:</strong> Метод format method может вывести дату почти по любому образцу. Синтаксис для представления различных составляющих даты можно найти в документации ( <a class="external external-icon" href="http://momentjs.com/docs/#/displaying/" rel="noopener">moment documentation</a>).</p> +</div> + +<h2 class="highlight-spanned" id="Обновляем_представление"><span class="highlight-span">Обновляем представление</span></h2> + +<p>Откройте файл <strong>/views/bookinstance_list.pug</strong> и замените <code>due_back</code> на <code>due_back_formatted</code>.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"> <span class="keyword token">if</span> val<span class="punctuation token">.</span>status<span class="operator token">!=</span><span class="string token">'Available'</span> + <span class="comment token">//span (Due: #{val.due_back} )</span> + span <span class="function token"> </span><span class="punctuation token">(</span>Due<span class="punctuation token">:</span> #<span class="punctuation token">{</span>val<span class="punctuation token">.</span>due_back_formatted<span class="punctuation token">}</span> <span class="punctuation token">)</span> </code></pre> + +<p>Вот и все. Если вы перейдете к <em>All book-instances</em> в боковом меню, вы должны увидеть все даты в привлекательном формате!</p> + +<p> </p> + +<h2 id="Далее">Далее</h2> + +<ul> + <li>Вернуться к <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li> + <li>Перейти к следующему подразделу части 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page">Author list page and Genre list page challenge</a> (страница списка авторов и тест- страница списка жанров).</li> +</ul> + +<p> </p> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html new file mode 100644 index 0000000000..32100db740 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html @@ -0,0 +1,138 @@ +--- +title: Асинхронное управление потоками при помощи async +slug: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async +tags: + - Node + - Часть 5 +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async +--- +<p>Код контроллера для некоторых страниц библиотеки будет зависеть от результатов многих асинхронных запросов, которые должны выполняться в определенном порядке или параллельно. Для того, чтобы управлять потоком выполнения, и выводить страницы, когда получена вся необходимая информация, будет использован <a class="external external-icon" href="https://www.npmjs.com/package/async" rel="noopener">async</a> - известный модуль node.</p> + +<div class="note"> +<p><strong>Note:</strong> В JavaScript существует много других способов управления аснхронным поведением и потоком выполнения, включая такой относительно новый элемент языка JacaScript как <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Techniques/Promises">Promises</a> (обещания, промисы).</p> +</div> + +<p>Модуль Async имеет массу полезных методов (см. документациюt <a class="external external-icon" href="http://caolan.github.io/async/docs.html" rel="noopener">the documentation</a>). Вот некоторые наиболее важные функции:</p> + +<ul> + <li><code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#parallel" rel="noopener">async.parallel()</a></code> для осуществеления любых операций, которые должны выполняться параллельно.</li> + <li><code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#series" rel="noopener">async.series()</a></code> если нужно иметь уверенность, что асинхронные операции выполняются последовательно.</li> + <li><code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#waterfall" rel="noopener">async.waterfall()</a></code> для операций, которые должны выполняться последовательно, причем каждая операция зависит от результатов предыдущих операций.</li> +</ul> + +<h2 class="highlight-spanned" id="Почему_это_необходимо"><span class="highlight-span">Почему это необходимо?</span></h2> + +<p>Большинство методов, которые используются в <em>Express</em> - <span class="highlight-span">асинхронные - вы определяете выполняемую операцию, передавая </span> callback-функцию. Метод завершается немедленно, а callback-функция вызывается тогда, когда завершилась запрошенная операция. По соглашению, принятому в <em>Express</em>, callback-функция передает значение ошибки <em>error</em> как первый параметр (или <code>null</code> при успехе) и результат функции (если есть) как второй параметр.</p> + +<p>Если контроллер должен выполнить только одну асинхронную операцию, чтобы получить информацию для представления страницы, то реализация проста - мы просто представляем шаблон в колбэке. Фрагмент кода (ниже) демонстрирует это для функции, которая подсчитывает количество элементов модкли <code>SomeModel</code> (применяя метод Mongoose <code><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#model_Model.count" rel="noopener">count()</a></code> ):</p> + +<pre class="brush: js"><code>exports.some_model_count = function(req, res, next) { + +</code> SomeModel.count({ a_model_field: 'match_value' }, function (err, count) { + // ... сделать что-то, если ошибка + + // При успехе представить результат, передав count в render-функцию (здесь - как переменную 'data'). + res.render('the_template', { data: count } ); + }); +<code>}</code> +</pre> + +<p>Однако что, если требуется сделать <strong>множественные</strong> асинхронные запросы, и результат нельзя представить, пока не завершились все операции? Наивная реализация могла бы использовать "венок" запросов, запуская последующие запросы в колбэках предыдущих, и представляя ответ в последнем колбэке. Проблема такого подхода состоит в том, что запросы должны вапольняться последовательно, хотя, вероятно, было бы более эффективно выполнять их параллельно. Это также может привести к усложненному вложенному коду, что обычно называют адом обратных вызовов ( <a class="external external-icon" href="http://callbackhell.com/" rel="noopener">callback hell</a> ).</p> + +<p>Намного лучше было бы выполнять все запросы параллельно, и иметь единственную callback-функцию, которая будет вызвана после того как все запросы выполнены. Именно такое выполнение операций модуль <em>Async</em> делает легким и простым!</p> + +<h2 class="highlight-spanned" id="Параллельные_асинхронные_операции"><span class="highlight-span">Параллельные асинхронные операции</span></h2> + +<p>Метод <code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#parallel" rel="noopener">async.parallel()</a></code> используется для параллельного выполнения нескольких асинхронных операций.</p> + +<p>Первый аргумент в <code>async.parallel()</code> - это коллекция асинхронных функций, которые требуется выполнить (массив, объект или другой итерируемый элемент). Каждая функция получает callback-функцию <code>callback(err, result)</code> , которую она должна вызвать при завершении, с ошибкой <code>err</code> (может быть <code>null</code>) и, возможно, со значением результата <code>results</code>.</p> + +<p>Возможный второй аргумент для <code>async.parallel()</code> - это callback -функция, которая должна быть вызвана после завершения всех функций, указанных в первом аргументе. Эта функция вызывается с аргументом ошибки и результатом - коллекцией результатов отдельных асинхронных операций. Тип коллекции - такой же, как и тип первого аргумента async.parallel (т.е. если передается <em>массив</em> асинхронных функций, итоговая callback-функция будет вызвана с <em>массивом</em> результатов). Если любая из параллельных функций сообщила об ошибке, сразу вызывается итоговая callback-функция, которая возвращает ошибку.</p> + +<p>Пример ниже показывает, как это работает в случае, когда первый аргумент является объектом. Как видно, результаты возвращаются в объекте с такими же именами свойств, как у переданных функций.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">parallel</span><span class="punctuation token">(</span><span class="punctuation token">{</span> + one<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span> + two<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> + something_else<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="comment token">// optional callback</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// 'results' равны: {one: 1, two: 2, ..., something_else: some_value}</span> + <span class="punctuation token">}</span> +<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<p>Если вместо объекта передать <em>массив </em>функций как первый аргумент, результатом будет массив (порядок результатов в массиве такой же, как и порядок функций в массиве, а не порядок выполнения функций).</p> + +<h2 class="highlight-spanned" id="Последовательные_асинхронные_операции"><span class="highlight-span">Последовательные асинхронные операции</span></h2> + +<p>Для выполнения нескольких асинхронных операций последовательно используется метод <code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#series" rel="noopener">async.series()</a></code> , при этом <span class="highlight-span">последующие функции не зависят от результатов предыдущих функций</span>. Метод определяется и ведет себя так же, как и <code>async.parallel()</code>.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">series</span><span class="punctuation token">(</span><span class="punctuation token">{</span> + one<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span> + two<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> + something_else<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">.</span><span class="punctuation token">.</span><span class="punctuation token">.</span> <span class="punctuation token">}</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="comment token">// optional callback after the last asynchronous function completes.</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// 'results' is now equals to: {one: 1, two: 2, ..., something_else: some_value} </span> + <span class="punctuation token">}</span> +<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<div class="note"> +<p><strong>Заметка:</strong> Спецификация языка ECMAScript (JavaScript) устанавливает, что порядок в перечислении объектов не определен, поэтому возможно, что функции не будут вызываться в том порядке, в котором вы их задали на всех платформах. Если порядок вызова действительно важен, вместо объекта следует передавать массив, как показано ниже.</p> +</div> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">series</span><span class="punctuation token">(</span><span class="punctuation token">[</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// do some stuff ...</span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'one'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// do some more stuff ... </span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'two'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="punctuation token">]</span><span class="punctuation token">,</span> + <span class="comment token">// optional callback</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// results is now equal to ['one', 'two'] </span> + <span class="punctuation token">}</span> +<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<h2 class="highlight-spanned" id="Последовательные_зависимые_асинхронные_операции"><span class="highlight-span">Последовательные зависимые асинхронные операции</span></h2> + +<p>Выполнение нескольких асинхронных операций последовательно, когда каждая операция зависит от результатов предыдущих операций, осуществляется методом <code><a class="external external-icon" href="http://caolan.github.io/async/docs.html#waterfall" rel="noopener">async.waterfall()</a></code>.</p> + +<p>Функции-callback, которая вызываются асинхронными функциями , содержит <code>null</code> как первый аргумент, и результаты в следующих аргументах. Каждая функция в последовательности (кроме первой) как аргументы использует результаты предыдущих функция, а callback-функция является последним аргументом. Когда операции завершаются, вызывается финальная callback-функция, аргументы которой - объект err и результат последней операции. Как это работает, станет более ясным после рассмотрения примера - фрагмента кода, приведенного ниже ( пример взят из документации <em>async</em>):</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">waterfall</span><span class="punctuation token">(</span><span class="punctuation token">[</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{//первая функция в цепочке</span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'one'</span><span class="punctuation token">,</span> <span class="string token">'two'</span><span class="punctuation token">)</span><span class="punctuation token">;//результаты 'one' и 'two'</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>arg1<span class="punctuation token">,</span> arg2<span class="punctuation token">,</span> callback<span class="punctuation token">)</span> <span class="punctuation token">{//вторая функция в цепочке</span> + <span class="comment token">// arg1 равен 'one' , arg2 равен 'two' </span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'three'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> //результат 'three' + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="keyword token">function</span><span class="punctuation token">(</span>arg1<span class="punctuation token">,</span> callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// arg1 равен 'three'</span> + <span class="function token">callback</span><span class="punctuation token">(</span><span class="keyword token">null</span><span class="punctuation token">,</span> <span class="string token">'done'</span><span class="punctuation token">)</span><span class="punctuation token">; //результат 'done'</span> + <span class="punctuation token">}</span> +<span class="punctuation token">]</span><span class="punctuation token">,</span> <span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> result<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// result равен 'done'</span> +<span class="punctuation token">}</span> +<span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<h2 class="highlight-spanned" id="Установка_async"><span class="highlight-span">Установка async</span></h2> + +<p>Установим модуль async при помощи менеджера пакетов NPM, чтобы использовать его в своем коде. Это делается обычным способом - откроем окно команд в корне проекта <em>LocalLibrary</em> и введем команду:</p> + +<pre class="brush: bash line-numbers language-bash"><code class="language-bash">npm install async</code></pre> + +<h2 id="Дальнейшие_шаги">Дальнейшие шаги</h2> + +<ul> + <li>Вернуться учебнику <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express, Part 5: Вывести данные библиотеки</a>.</li> + <li>Перейти к следующему разделу части 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer">Основы шаблонов</a>.</li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html new file mode 100644 index 0000000000..be5bd57962 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html @@ -0,0 +1,121 @@ +--- +title: Страница с подробностями жанров +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page +--- +<p>Страница "подробности" (<em>detail)</em> для жанров должна показывать информацию для отдельного жанра по его автоматически генерируему идентификатору <code>_id</code>. Должно быть показано название жанра и список книг этого жанра, со ссылками на страницу с детальной информацией для каждой книги.</p> + +<h2 id="Controller">Controller</h2> + +<p>Откройте файл<em> </em><strong>/controllers/genreController.js</strong> и импортируйте модули <em>async</em> и <em>Book</em> в первых строках файла.</p> + +<pre class="brush: js">var Book = require('../models/book'); +var async = require('async'); +</pre> + +<p>Найдите экспортируемый метод контроллера <code>genre_detail</code><code>()</code> и замените его следующим кодом:</p> + +<pre class="brush: js">// Display detail page for a specific Genre. +exports.genre_detail = function(req, res, next) { + +<strong> async.parallel({ + genre: function(callback) { + Genre.findById(req.params.id) + .exec(callback); + }, + + genre_books: function(callback) { + Book.find({ 'genre': req.params.id }) + .exec(callback); + }, + + }, function(err, results) { + if (err) { return next(err); } + if (results.genre==null) { // No results. + var err = new Error('Genre not found'); + err.status = 404; + return next(err); + } + // Successful, so render + res.render('genre_detail', { title: 'Genre Detail', genre: results.genre, genre_books: results.genre_books } ); + });</strong> + +}; +</pre> + +<p>Метод использует <code>async.parallel()</code> для параллельного запроса названия жанра и связанных с ним книг, причем callback-функция возвращает страницу, когда (если) оба запроса завершились успешно.</p> + +<p>The ID of the required genre record is encoded at the end of the URL and extracted automatically based on the route definition (<strong>/genre/:id</strong>). The ID is accessed within the controller via the request parameters: <code style="font-style: normal; font-weight: normal;">req.params.id</code>. It is used in <code style="font-style: normal; font-weight: normal;">Genre.findById()</code> to get the current genre. It is also used to get all <code>Book</code> objects that have the genre ID in their <code>genre</code> field: <code>Book.find({ 'genre': req.params.id })</code>.</p> + +<div class="note"> +<p><strong>Note:</strong> If the genre does not exist in the database (i.e. it may have been deleted) then <code>findById()</code> will return successfully with no results. In this case we want to display a "not found" page, so we create an <code>Error</code> object and pass it to the <code>next</code> middleware function in the chain. </p> + +<pre class="brush: js"><strong>if (results.genre==null) { // No results. + var err = new Error('Genre not found'); + err.status = 404; + return next(err); +}</strong> +</pre> + +<p>The message will then propagate through to our error handling code (this was set up when we <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website#error_handling">generated the app skeleton</a> - for more information see <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction#Handling_errors">Handling Errors</a>).</p> +</div> + +<p>The rendered view is <strong>genre_detail</strong> and it is passed variables for the <code>title</code>, <code>genre</code> and the list of books in this genre (<code>genre_books</code>).</p> + +<h2 id="View">View</h2> + +<p>Create <strong>/views/genre_detail.pug</strong> and fill it with the text below:</p> + +<pre class="brush: js">extends layout + +block content + + <strong>h1 Genre: #{genre.name}</strong> + + div(style='margin-left:20px;margin-top:20px') + + h4 Books + + dl + each book in genre_books + dt + a(href=book.url) #{book.title} + dd #{book.summary} + + else + p This genre has no books +</pre> + +<p>The view is very similar to all our other templates. The main difference is that we don't use the <code>title</code> passed in for the first heading (though it is used in the underlying <strong>layout.pug</strong> template to set the page title).</p> + +<h2 id="What_does_it_look_like">What does it look like?</h2> + +<p>Run the application and open your browser to <a href="http://localhost:3000/">http://localhost:3000/</a>. Select the <em>All genres</em> link, then select one of the genres (e.g. "Fantasy"). If everything is set up correctly, your page should look something like the following screenshot.</p> + +<p><img alt="Genre Detail Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14462/LocalLibary_Express_Genre_Detail.png" style="border-style: solid; border-width: 1px; display: block; height: 523px; margin: 0px auto; width: 1000px;"></p> + +<div class="note"> +<p>You might get an error similar to this:</p> + +<pre class="brush: bash">Cast to ObjectId failed for value " 59347139895ea23f9430ecbb" at path "_id" for model "Genre" +</pre> + +<p>This is a mongoose error coming from the <strong>req.params.id</strong>. To solve this problem, first you need to require mongoose on the <strong>genreController.js</strong> page like this:</p> + +<pre class="brush: js"> var mongoose = require('mongoose'); +</pre> + +<p>Then use <strong>mongoose.Types.ObjectId() </strong>to convert the id to a that can be used. For example:</p> + +<pre class="brush: js">exports.genre_detail = function(req, res, next) { + var id = mongoose.Types.ObjectId(req.params.id); + ... +</pre> +</div> + +<h2 id="Next_steps">Next steps</h2> + +<ul> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li> + <li>Proceed to the next subarticle of part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page">Book detail page</a>.</li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.html new file mode 100644 index 0000000000..248187f1a5 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.html @@ -0,0 +1,134 @@ +--- +title: Home page +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Home_page +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Home_page +--- +<p>Первой создаваемой страницей будет домашняя страница веб-сайта, доступная из корня сайта (<code>'/'</code>) или из каталога (<code>catalog/</code>). На странице будет виден статический текст, описывающий сайт, и динамически вычисляемые "количества" записей разных типов имеющихся в БД.</p> + +<p>Маршрут для домашней страницы уже создан. Для завершения страницы обновить функции контроллера, чтобы он извлекал количество записей из БД, и создавал представление (шаблон), который можно использовать для презентации страницы.</p> + +<h2 id="Маршрут">Маршрут</h2> + +<p>Маршруты индексной страницы созданы ранее в предыдущем разделе (<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes">previous tutorial).</a> Напомним, все функции маршрутов определены в файле <strong>/routes/catalog.js</strong>:</p> + +<pre class="brush: js ">// GET catalog home page. +router.get('/', book_controller.index); //This actually maps to /catalog/ because we import the route with a /catalog prefix</pre> + +<p>Параметр callback-функции определен в <strong>/controllers/bookController.js</strong>:</p> + +<pre class="brush: js">exports.index = function(req, res, next) { + res.send('NOT IMPLEMENTED: Site Home Page'); +}</pre> + +<p>Именно эту функцию контроллера мы расширим, чтобы получать информацию из моделей и затем отображать ее, используя шаблоны (представления).</p> + +<h2 id="Контроллер">Контроллер</h2> + +<p>Функция контроллера индекса должна получать информацию о том, сколько книг (<code>Book)</code>, экземпляров книг (<code>BookInstance)</code>, сколько из них доступно, сколько авторов (<code>Author)</code>, жанров (<code>Genre)</code> имеется в БД, должна поместить эту информацию в шаблон, чтобы создать HTML-страницу, после чего вернуть ее в HTTP-ответе.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Количество экземпляров в каждой модели вычисляется при помощи метода <code><a class="external external-icon" href="http://mongoosejs.com/docs/api.html#model_Model.countDocuments" rel="noopener">countDocuments()</a></code> . Он вызывается для модели с возможным набором условий, необходимых для проверки соответствия первому аргументу и callback-функции второго аргумента (обсуждалось ранее в "Использование базы данных с Mongoose" <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Using a Database (with Mongoose)</a>), причем можно вернуть также запрос <code>Query,</code> а затем выполнить его позже при помощи callback. Эта callback-функция будет выполняться, когда БД вернет количество записей. Значение ошибки (or <code>null</code>) будет первым параметром, а количество записей (или null, если была ошибка) - вторым параметром.</p> + +<pre class="brush: js ">SomeModel.countDocuments({ a_model_field: 'match_value' }, function (err, count) { + // ... do something if there is an err + // ... do something with the count if there was no error + });</pre> +</div> + +<p>Откройте файл <strong>/controllers/bookController.js</strong>. Почти в самом начале вы должны увидеть экспортируемую функцию <code>index()</code> .</p> + +<pre class="brush: python ">var Book = require('../models/book') + +exports.index = function(req, res, next) { + res.send('NOT IMPLEMENTED: Site Home Page'); +}</pre> + +<p>Замените весь код, показанный выше, на следующий фрагмент кода. Первое, что он делает - импортирует (<code>require()</code>) все модели (выделено жирным). Это требуется, поскольку они нужны для подсчета числа записей. Затем импортируется модуль <em>async</em> .</p> + +<pre class="brush: js "><strong>var Book = require('../models/book'); +var Author = require('../models/author'); +var Genre = require('../models/genre'); +var BookInstance = require('../models/bookinstance');</strong> + +var async = require('async'); + +exports.index = function(req, res) { + + async.parallel({ + book_count: function(callback) { + Book.count<s>Documents</s>({}, callback); // Pass an empty object as match condition to find all documents of this collection +// count<s>Documents</s> не работает, работает только просто count + }, + book_instance_count: function(callback) { + BookInstance.count<s>Documents</s>({}, callback); + }, + book_instance_available_count: function(callback) { + BookInstance.count<s>Documents</s>({status:'Available'}, callback); + }, + author_count: function(callback) { + Author.count<s>Documents</s>({}, callback); + }, + genre_count: function(callback) { + Genre.count<s>Documents</s>({}, callback); + } + }, function(err, results) { + res.render('index', { title: 'Local Library Home', error: err, data: results }); + }); +};</pre> + +<p>Метод <code>async.parallel()</code> передает объект с функциями для получения количества элементов каждой модели. Все эти функции стартуют одновременно. Когда все они завершатся, будет вызвана финальная callback-функция, в итоговом параметре которой содержится нужный нам результат (или ошибка).</p> + +<p>При успешном завершении callback-функции она вызывает <code><a class="external external-icon" href="http://expressjs.com/en/4x/api.html#res.render" rel="noopener">res.render()</a></code>, у которой в качестве параметров - представление (шаблон) '<strong>index</strong>' и объект, содержащий данные, которые следует поместить в шаблон (среди них - количества элементов в моделях). Данные представлены как пары ключ-значение, и могут быть получены в шаблоне по ключу.</p> + +<div class="note"> +<p><strong>Заметка:</strong> В данном случае callback-функция, которую вызывает <code>async.parallel()</code> , несколько необычная - страница отображается всегда, независимо от того, была ошибка или нет (обычно используют отдельный путь выполнения для обработки выводимых ошибок).</p> +</div> + +<h2 id="Представление">Представление</h2> + +<p>Откройте файл <strong>/views/index.pug</strong> и замените его содержимое текстом, приведенным ниже</p> + +<pre class="brush: js ">extends layout + +block content + h1= title + p Welcome to #[em LocalLibrary], a very basic Express website developed as a tutorial example on the Mozilla Developer Network. + + h1 Dynamic content + + if error + p Error getting dynamic content. + else + p The library has the following record counts: + + ul + li #[strong Books:] !{data.book_count} + li #[strong Copies:] !{data.book_instance_count} + li #[strong Copies available:] !{data.book_instance_available_count} + li #[strong Authors:] !{data.author_count} + li #[strong Genres:] !{data.genre_count}</pre> + +<p>Представление несложное. Мы расширили базовый шаблон <strong>layout.pug</strong>, переопределив блок (<code>block)</code> с именем '<strong>content</strong>'. Первый заголовок <code>h1</code> будет экранированным текстом - значением переменной <code>title</code> ,variable that которая передается в функцию <code>render()</code> —заметьте, что применение '<code>h1=</code>' говорит, что следующий текст рассматривается как выражение JavaScript. Затем расположен параграф, знакомящий с LocalLibrary.</p> + +<p>Под заголовком <em>Dynamic content</em> мы проверяем, определена ли переданная из функции <code>render()</code> переменная error. Если да, отмечаем ошибку. Если нет, выводим ( как список) количества копий каждой модели, которые хранятся в переменной <code>data</code>.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Мы не экранируем количества элементов (т.е. используется синтаксис <code>!{}</code> ) потому что эти значения вычисляются. Если бы информация предоставлялась конечным пользователем, следовало бы экранировать переменную перед выводом.</p> +</div> + +<h2 id="Как_это_выглядит">Как это выглядит?</h2> + +<p>Сейчас у нас есть все для того, чтобы показать страницу index. Запустите приложение и откройте браузер с адресом <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>. Если все задано правильно, ваш сайт должен иметь примерно такой вид, как на приведенном снимке экрана.</p> + +<p><img alt="Home page - Express Local Library site" src="https://mdn.mozillademos.org/files/14458/LocalLibary_Express_Home.png" style="display: block; height: 440px; margin: 0px auto; width: 1000px;"></p> + +<div class="note"> +<p><strong>Заметка:</strong> Элементы бокового меню использовать еще нельзя, так как адреса, представления и шаблоны для этих страниц еще не определены. Если вы попытаетесь их использовать, будет выведено сообщение об ошибке, например, вида "NOT IMPLEMENTED: Book list" (НЕ РЕАЛИЗОВАНО: список книг), в зависимости от выбранного элемента меню. Эти строковые литералы (которые будут замещены действительными данными) были заданы в различных файлах контроллеров в каталоге "controllers".</p> +</div> + +<h2 id="Next_steps">Next steps</h2> + +<ul> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li> + <li>Proceed to the next subarticle of part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page">Book list page</a>.</li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/index.html new file mode 100644 index 0000000000..bb2e804d2e --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/index.html @@ -0,0 +1,83 @@ +--- +title: 'Учебник Express часть 5: Отображение данных библиотеки' +slug: Learn/Server-side/Express_Nodejs/Displaying_data +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">Теперь мы готовы добавить страницы, на которых будут отображаться книги веб-сайта <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a> и другие данные. Страницы будут включать главную страницу, которая показывает сколько записей определенного типа мы имеем и отдельные страницы для детального просмотра записей. Попутно мы приобретем практический опыт в получении записей из баз данных и использовании шаблонов.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные знания:</th> + <td>Завершите изучение предыдущих тем учебника (включая <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Учебник Express часть 4: Маршруты и контроллеры</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять, как использовать асинхронный модуль и язык шаблона Pug, и как получить данные из URL в наших функциях контроллера.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>В предыдущих статьях учебника мы определили <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Mongoose модели</a>, которые можно использовать для взаимодействия с базой данных и создания некоторых исходных записей библиотеки. Затем мы <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">создали все маршруты</a>, необходимые для веб-сайта LocalLibrary, но с "фиктивными" функциями контроллеров (это скелетные функции, которые просто возвращают сообщение "не реализовано " при доступе к странице).</p> + +<p>Следующим шагом является обеспечение правильных реализаций для страниц, которые отображают информацию из библиотеки (мы рассмотрим реализацию страниц с формами для создания, обновления или удаления информации в последующих статьях). Это включает в себя обновление функций контроллера для извлечения записей с помощью наших моделей и определение шаблонов для отображения этой информации пользователям.</p> + +<p>Мы начнем с обзорных / основных тем, объясняющих, как управлять асинхронными операциями в функциях контроллера и как писать шаблоны с помощью Pug. Затем мы предоставим реализации для каждой из наших основных страниц" только для чтения " с кратким объяснением любых специальных или новых функций, которые они используют.</p> + +<p>В конце этой статьи вы должны иметь хорошее сквозное понимание того, как маршруты, асинхронные функции, представления и модели работают на практике.</p> + +<h2 id="Отображение_данных_библиотеки_—_подразделы">Отображение данных библиотеки — подразделы</h2> + +<p>Следующие подразделы проходят процесс добавления различных функций, необходимых для отображения необходимых страниц веб-сайта. Вы должны прочитать и проработать каждый из них по очереди, прежде чем перейти к следующему.</p> + +<ol> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async">Aсинхронное управление потоками с помощью async</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer">Пример шаблона</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template">Базовые шаблоны LocalLibrary</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Home_page">Домашняя страница</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page">Страница списка книг</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_list_page">Страница списка экземпляров книг</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_moment">Форматирование даты с момента использования</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page">Страница списка авторов и страница списка жанров</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Genre_detail_page">Страница сведений о жанре</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_detail_page">Страница сведений о книге</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Author_detail_page">Страница информации об авторе</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_detail_page_and_challenge">Страница сведений об экземпляре книги и вызове</a></li> +</ol> + +<h2 id="Итог">Итог</h2> + +<p>Теперь мы создали все страницы "только для чтения " для нашего сайта: домашнюю страницу, которая отображает количество экземпляров каждой из наших моделей, а также список и подробные страницы для наших книг, экземпляров книг, авторов и жанров. По пути мы получили много фундаментальных знаний о контроллерах, управлении потоком при использовании асинхронных операций, создании представлений с помощью Pug, запросе базы данных с помощью наших моделей, как передавать информацию в шаблон из вашего представления, а также как создавать и расширять шаблоны. Те, кто выполнил вызов также узнали немного о дате обработки с помощью момента.</p> + +<p>В нашей следующей статье мы будем опираться на наши знания, создавая HTML-формы и код обработки форм, чтобы начать изменять данные, хранящиеся на сайте.</p> + +<h2 id="Смотрите_так_же">Смотрите так же</h2> + +<ul> + <li><a href="http://caolan.github.io/async/docs.html">Aссинхроный модуль</a> (Асинхронные документация)</li> + <li><a href="https://expressjs.com/en/guide/using-template-engines.html">Использование механизмов шаблонов с Express</a> (Express документация)</li> + <li><a href="https://pugjs.org/api/getting-started.html">Pug</a> (Pug документация)</li> + <li><a href="http://momentjs.com/docs/">Moment</a> (Moment документация)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html new file mode 100644 index 0000000000..13c61ea6cb --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html @@ -0,0 +1,69 @@ +--- +title: Базовый шаблон LocalLibrary +slug: Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template +--- +<p>Теперь, чтобы мы понимали как расширить шаблон с помощью Pug, давайте создадим базовый шаблон для проекта. У него будет боковая панель (sidebar)) со ссылками на страницы, которые мы надеемся создать на протяжении учебника (например, для отображения и создания книг, жанров, автор иов т. д.) и основная область контента, которую мы переопределим на каждой из отдельных страниц.</p> + +<p>Откройте файл <strong>/views/layout.pug </strong>и замените его содержимое следующим.</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">doctype html +html(lang='en') + head + title= title + meta(charset='utf-8') + meta(name='viewport', content='width=device-width, initial-scale=1') + link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css') + script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js') + script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js') + link(rel='stylesheet', href='/stylesheets/style.css') + body + div(class='container-fluid') + div(class='row') + div(class='col-sm-2') + block sidebar + ul(class='sidebar-nav') + li + a(href='/catalog') Home + li + a(href='/catalog/books') All books + li + a(href='/catalog/authors') All authors + li + a(href='/catalog/genres') All genres + li + a(href='/catalog/bookinstances') All book-instances + li + hr + li + a(href='/catalog/author/create') Create new author + li + a(href='/catalog/genre/create') Create new genre + li + a(href='/catalog/book/create') Create new book + li + a(href='/catalog/bookinstance/create') Create new book instance (copy) + + div(class='col-sm-10') + block content</code></pre> + +<p>Шаблон использует (и включает) JavaScript и CSS из <a class="external external-icon" href="http://getbootstrap.com/" rel="noopener">Bootstrap</a> , что позволяет улучшить макет и представление HTML-страницы. Применение Bootstrap или другого клиентского фреймворка - быстрый способ создать привлекательную, хорошо масштабируемую страницу. Кроме того, это позволяет получить представление страницы, не вдаваясь в детали - мы можем уделить все внимание коду на стороне сервера!</p> + +<p>Макет представляется достаточно очевидным, если Вы уже прочли статью Основы шаблонов (<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data#Template_primer">Template primer</a>) выше. Обратите внимание на использование <code>block content</code> в качестве места для размещения контента отдельных страниц.</p> + +<p>Базовый шаблон также ссылается на локальный файл стилей (<strong>style.css</strong>), что обеспечивает дополнительное управление внешним видом. Откройте <strong>/public/stylesheets/style.css</strong> и замените его содержимое таким текстом:</p> + +<pre class="brush: css line-numbers language-css"><code class="language-css"><span class="selector token"><span class="class token">.sidebar-nav</span> </span><span class="punctuation token">{</span> + <span class="property token">margin-top</span><span class="punctuation token">:</span> <span class="number token">20</span>px<span class="punctuation token">;</span> + <span class="property token">padding</span><span class="punctuation token">:</span> <span class="number token">0</span><span class="punctuation token">;</span> + <span class="property token">list-style</span><span class="punctuation token">:</span> none<span class="punctuation token">;</span> +<span class="punctuation token">}</span></code></pre> + +<p>При запуске нашего сайта мы должны увидеть боковую панель! В следующих разделах мы будем использовать вышеуказанный макет для определения отдельных страниц.</p> + +<h2 id="Следующие_шаги">Следующие шаги</h2> + +<ul> + <li>Вернуться к <a href="https://developer.mozilla.org/ru/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Учебник Express часть 5: Отображение данных библиотеки</a>.</li> + <li>Перейти к следующему подразделу <a href="https://developer.mozilla.org/ru/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Home_page">Домашняя страница</a>.</li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.html new file mode 100644 index 0000000000..3f537db354 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.html @@ -0,0 +1,149 @@ +--- +title: Основы шаблонов +slug: Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer +translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer +--- +<p>Шаблон - это текстовый файл, определяющий <em>структуру</em>, или внешний вид выходного файла, с предусмотренными позициями, в которые будут помещаться данные при отображении по шаблону (в <em>Express</em> шаблоны также называют <em>представлениями</em>).</p> + +<h2 id="Выбор_шаблонов_Express">Выбор шаблонов Express</h2> + +<p>В Express можно использовать много движков отображающих шаблонов ( <a class="external external-icon" href="https://expressjs.com/en/guide/using-template-engines.html" rel="noopener">template rendering engines</a>). В этом руководстве для шаблонов будет использован <a class="external external-icon" href="https://pugjs.org/api/getting-started.html" rel="noopener">Pug</a> (ранее известный как Jade) . Это наиболее популярный в Node язык шаблонов, который о себе заявляет так: чистый, чувствительный к пробелам синтаксис для написания HTML, на который сильно повлиял <a class="external external-icon" href="http://haml.info/" rel="noopener">Haml</a>.</p> + +<p>Разные языки шаблонов используют различные подходы для определения внешнего вида и разметки позиций для данных—некоторые используют HTML для определения внешнего вида, тогда как другие применяют различные форматы разметки, которые затем должы компилироваться в HTML. Pug - второго типа; он использует <em>представление</em> (<em>representation) </em> HTML, в котором первое слово в каждой строке обычно представляет элемент HTML, а отступы в следующих строках применяются, чтобы представить вложенные элементы. Результатом является определение страницы, которое транслируется непосредственно в HTML, и которое, вероятно, более краткое и легче читается.</p> + +<div class="note"> +<p><strong>Заметка:</strong> недостаток применения <em>Pug</em> - это чувствительность к отступам и пробелам (если добавить лишний пробел в "плохом" месте, можно получить невразумительный код ошибки). Однако, если ваши шаблоны уже действуют, их очень легко читать и поддерживать.</p> +</div> + +<h2 class="highlight-spanned" id="Конфигурация_шаблона"><span class="highlight-span">Конфигурация шаблона</span></h2> + +<p>Когда создавался каркас (<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">the skeleton website</a>) веб-сайта <em>LocalLibrary, </em>он был настроен на использование <a class="external external-icon" href="https://pugjs.org/api/getting-started.html" rel="noopener">Pug</a> . Можно было заметить, что модуль pug включен в зависимости в файле <strong>package.json</strong>, и установлен (app.set(...)) как движок представлений в файле <strong>app.js</strong>. Эта установка показывает,, что движок представлений - pug, и что <em>Express</em> должен искать шаблоны в подкаталоге <strong>/views</strong>.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// View engine setup.</span> +app<span class="punctuation token">.</span><span class="keyword token">set</span><span class="punctuation token">(</span><span class="string token">'views'</span><span class="punctuation token">,</span> path<span class="punctuation token">.</span><span class="function token">join</span><span class="punctuation token">(</span>__dirname<span class="punctuation token">,</span> <span class="string token">'views'</span><span class="punctuation token">)</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +app<span class="punctuation token">.</span><span class="keyword token">set</span><span class="punctuation token">(</span><span class="string token">'view engine'</span><span class="punctuation token">,</span> <span class="string token">'pug'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<p>Если посмотреть содержимое каталога <strong>views</strong>, можно увидеть файлы с расширением .pug, в которых шаблоны представлений по умолчанию. Это представление для домашней страницы (<strong>index.pug</strong>) и базовый шаблон (<strong>layout.pug</strong>), который следует заменить нашим содержимым.</p> + +<pre><code>/express-locallibrary-tutorial //the project root + /views + error.pug + <strong>index.pug</strong> + layout.pug</code> +</pre> + +<h2 class="highlight-spanned" id="Синтаксис_шаблонов"><span class="highlight-span">Синтаксис шаблонов</span></h2> + +<p>Пример файла шаблона (ниже) демонстрирует многие наиболее полезные черты Pug.</p> + +<p>Сначала отметим, что файл отражает структуру типового HTML-файла, причем первое слов в (почти) каждой строке является элементом HTML, а отступы используются, чтобы показать вложенные элементы. Так, например, элемент <code>body</code> находится внутри элемента <code>html</code>, а элементы <code>p</code> (параграфы) - внутри элемента <code>body,</code> и так далее. Невложенные элементы (т.е. индивидуальные параграфы) располагаются в отдельных строках.</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">doctype html +html(lang="en") + head + title= title + script(type='text/javascript'). + body + h1= title + + p This is a line with #[em some emphasis] and #[strong strong text] markup. + p This line has un-escaped data: !{'<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>em</span><span class="punctuation token">></span></span> is emphasised<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>em</span><span class="punctuation token">></span></span>'} and escaped data: #{'<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>em</span><span class="punctuation token">></span></span> is not emphasised<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>em</span><span class="punctuation token">></span></span>'}. + | This line follows on. + p= 'Evaluated and <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>em</span><span class="punctuation token">></span></span>escaped expression<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>em</span><span class="punctuation token">></span></span>:' + title + + <span class="comment token"><!-- You can add HTML comments directly --></span> + // You can add single line JavaScript comments and they are generated to HTML comments + //- Introducing a single line JavaScript comment with "//-" ensures the comment isn't rendered to HTML + + p A line with a link + a(href='/catalog/authors') Some link text + | and some extra text. + + #container.col + if title + p A variable named "title" exists. + else + p A variable named "title" does not exist. + p. + Pug is a terse and simple template language with a + strong focus on performance and powerful features. + + h2 Generate a list + + ul + each val in [1, 2, 3, 4, 5] + li= val</code></pre> + +<p>Атрибуты элементов определены в скобках после соответствующих элементов. В скобках располагается список пар <em>имя атрибута=значение,</em>причем элементы списка разделяются запятой или пробелом. Например:</p> + +<ul> + <li><code>script(type='text/javascript')</code>, <code>link(rel='stylesheet', href='/stylesheets/style.css')</code></li> + <li><code>meta(name='viewport' content='width=device-width initial-scale=1')</code></li> +</ul> + +<p>Значения всех атрибутов <em>экранируются</em> (т.е. такие символы как "<code>></code>" заменяются эквивалентными кодами HTML как "<code>&gt;"</code>) , чтобы предотвратить JavaScript инъекции и межсайтовые атаки.</p> + +<p>Если после тэга стоит знак = , следующий текст рассматривается как <em>выражение</em> JavaScript. Например, шиже в первой строке, содержимое тэга <code>h1</code> будет <em>переменной </em> <code>title</code> (которая определена в файле или передана в шаблон из Express). Во второй строке содержимое параграфа - это текстовая строка, соединенная с переменной <code>title</code> . В каждом из случаев поведение по умолчанию - экранировать строки.</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">h1= title +p= 'Evaluated and <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>em</span><span class="punctuation token">></span></span>escaped expression<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>em</span><span class="punctuation token">></span></span>:' + title</code></pre> + +<p>Если после тэга знак = отсутствует, тогда содержимое рассматривается как обычный текст. Внутри текста можно вставить экранированные или неэкранированные данные, применяя синтаксис <code>#{}</code> и<code> !{}</code>, как показано ниже. В простой текст можно также вставлять "сырой" HTML.</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">p This is a line with #[em some emphasis] and #[strong strong text] markup. +p This line has an un-escaped string: !{'<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>em</span><span class="punctuation token">></span></span> is emphasised<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>em</span><span class="punctuation token">></span></span>'}, an escaped string: #{'<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>em</span><span class="punctuation token">></span></span> is not emphasised<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>em</span><span class="punctuation token">></span></span>'}, and escaped variables: #{title}.</code></pre> + +<div class="note"> +<p><strong>Совет:</strong> Почти всегда желательно экранировать данные, полученные от пользователей (при помощи синтаксиса <strong><code>#{}</code></strong> ). Данные, которым можно верить (т.е. подсчитанное количество записей, могут быть выведены без экранирования значений.</p> +</div> + +<p>Можно использовать символ конвейера ('<strong>|</strong>') в начале строки, чтобы отметить простой текст ("<a class="external external-icon" href="https://pugjs.org/language/plain-text.html" rel="noopener">plain text</a>"). Например, дополнительный текст, приведенный ниже, будет показан в той же строке, что и предыдущий, но не будет относиться к ссылке.</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">a(href='http://someurl/') Link text +| Plain text</code></pre> + +<p>Pug позволяет выполнять условные операции <code>if</code>, <code>else</code> , <code>else if</code> и <code>unless</code>— пример приведен ниже:</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">if title + p Переменная с именем "title" существует +else + p Переменной с именем "title" не существует</code></pre> + +<p>Можно также выполнять циклы (итерации), применяя ситаксис <code>each-in</code> или <code>while</code> . Фрагмент кода (ниже) содержит цикл по элементам массива, чтобы показать список элементов (отметим применение 'li=' для оценки "val" как переменной). Значение итератора val может быть также передано в шаблон как переменная!</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">ul + each val in [1, 2, 3, 4, 5] + li= val</code></pre> + +<p>Синтаксис разрешает также комментарии (которые попадут в результат или нет, по вашему желанию), смеси для создания повторно используемых блоков кода, операторы выбора case, и много другого. Более подробная информация - в документации <a class="external external-icon" href="https://pugjs.org/api/getting-started.html" rel="noopener">The Pug docs</a>.</p> + +<h2 class="highlight-spanned" id="Расширение_шаблонов"><span class="highlight-span">Расширение шаблонов</span></h2> + +<p>Принято иметь общую структуру для всех страниц сайта, <span class="highlight-span">включая стандартную HTML-разметку для </span>заголовка, футера, навигации и т.д. Вместо того, чтобы засталять разработчиков дублировать эти образцы на каждой странице, <em>Pug</em> позволяет объявить базовай шаблон, а затем модифицировать его, заменяя только те небольшие части, которые различны на каждой конкретной странице.</p> + +<p>Например, базовый шаблон <strong>layout.pug,</strong> созданный в каркасе проекта, имеет такой вид:</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">doctype html +html + head + title= title + link(rel='stylesheet', href='/stylesheets/style.css') + body + block content</code></pre> + +<p>Тэг <code>block</code> применен для отметки разделов контента, которые могут быть заменены в производных шаблона (если блок не переопределяется, будет использованиа его реализация в базовом классе).</p> + +<p>Умолчание для <strong>index.pug</strong> (созданный для каркаса проекта) показывает, как можно заменить базовый шаблон. Тэг <code>extends</code> идентифицирует базовый шаблон, который следует использовать, а затем мы используем <code>block <em>section_name,</em></code> чтобы отметить новый контент раздела, который мы заменяем.</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">extends layout + +block content + h1= title + p Welcome to #{title}</code></pre> + +<h2 id="Next_steps">Next steps</h2> + +<ul> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a>.</li> + <li>Proceed to the next subarticle of part 5: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/LocalLibrary_base_template">The LocalLibrary base template</a>.</li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html b/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html new file mode 100644 index 0000000000..13f409ea3c --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html @@ -0,0 +1,151 @@ +--- +title: "Форма для создания\_BookInstance" +slug: Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form +translation_of: Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form +--- +<p><a class="button section-edit only-icon" href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/forms$edit#Create_BookInstance_form" rel="nofollow, noindex"><span>Edi</span></a>В этой статье показано, как определить страницу / форму для создания объектов <code>BookInstance</code>. Это очень похоже на форму, которую мы использовали для создания объектов <code>Book</code>.</p> + +<h2 class="highlight-spanned" id="Импорт_методов_проверки_и_очистки"><span class="highlight-span">Импорт методов проверки и очистки</span></h2> + +<p>Откройте <strong>/controllers/bookinstanceController.js</strong> и добавьте следующие строки вверху файла:</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">const</span> <span class="punctuation token">{</span> body<span class="punctuation token">,</span>validationResult <span class="punctuation token">}</span> <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'express-validator/check'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="keyword token">const</span> <span class="punctuation token">{</span> sanitizeBody <span class="punctuation token">}</span> <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'express-validator/filter'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<h2 class="highlight-spanned" id="Controller—get_route"><span class="highlight-span">Controller—get route</span></h2> + +<p>At the top of the file, require the <em>Book</em> module (needed because each <code>BookInstance</code> is associated with a particular <code>Book</code>).</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">var</span> Book <span class="operator token">=</span> <span class="function token">require</span><span class="punctuation token">(</span><span class="string token">'../models/book'</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<p>Find the exported <code>bookinstance_create_get()</code> controller method and replace it with the following code.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display BookInstance create form on GET.</span> +exports<span class="punctuation token">.</span>bookinstance_create_get <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span> + + Book<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">{</span><span class="punctuation token">}</span><span class="punctuation token">,</span><span class="string token">'title'</span><span class="punctuation token">)</span> + <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> books<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span> + <span class="comment token">// Successful, so render.</span> + res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'bookinstance_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span>title<span class="punctuation token">:</span> <span class="string token">'Create BookInstance'</span><span class="punctuation token">,</span> book_list<span class="punctuation token">: </span>books<span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + +<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre> + +<p>The controller gets a list of all books (<code>book_list</code>) and passes it to the view <code><strong>bookinstance_form.pug</strong></code> (along with the <code>title</code>)</p> + +<h2 class="highlight-spanned" id="Controller—post_route"><span class="highlight-span">Controller—post route</span></h2> + +<p>Find the exported <code>bookinstance_create_post()</code> controller method and replace it with the following code.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Handle BookInstance create on POST.</span> +exports<span class="punctuation token">.</span>bookinstance_create_post <span class="operator token">=</span> <span class="punctuation token">[</span> + + <span class="comment token">// Validate fields.</span> + <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'book'</span><span class="punctuation token">,</span> <span class="string token">'Book must be specified'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'imprint'</span><span class="punctuation token">,</span> <span class="string token">'Imprint must be specified'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'due_back'</span><span class="punctuation token">,</span> <span class="string token">'Invalid date'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">optional</span><span class="punctuation token">(</span><span class="punctuation token">{</span> checkFalsy<span class="punctuation token">:</span> <span class="keyword token">true</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isISO8601</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + + <span class="comment token">// Sanitize fields.</span> + <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'book'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'imprint'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'status'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'due_back'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">toDate</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + + <span class="comment token">// Process request after validation and sanitization.</span> + <span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="operator token">=</span><span class="operator token">></span> <span class="punctuation token">{</span> + + <span class="comment token">// Extract the validation errors from a request.</span> + <span class="keyword token">const</span> errors <span class="operator token">=</span> <span class="function token">validationResult</span><span class="punctuation token">(</span>req<span class="punctuation token">)</span><span class="punctuation token">;</span> + + <span class="comment token">// Create a BookInstance object with escaped and trimmed data.</span> + <span class="keyword token">var</span> bookinstance <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">BookInstance</span><span class="punctuation token">(</span> + <span class="punctuation token">{</span> book<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>book<span class="punctuation token">,</span> + imprint<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>imprint<span class="punctuation token">,</span> + status<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>status<span class="punctuation token">,</span> + due_back<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>due_back + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + + <span class="keyword token">if</span> <span class="punctuation token">(</span><span class="operator token">!</span>errors<span class="punctuation token">.</span><span class="function token">isEmpty</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// There are errors. Render form again with sanitized values and error messages.</span> + Book<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span><span class="punctuation token">{</span><span class="punctuation token">}</span><span class="punctuation token">,</span><span class="string token">'title'</span><span class="punctuation token">)</span> + <span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span> books<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span> + <span class="comment token">// Successful, so render.</span> + res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'bookinstance_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Create BookInstance'</span><span class="punctuation token">,</span> book_list<span class="punctuation token">:</span> books<span class="punctuation token">,</span> selected_book<span class="punctuation token">:</span> bookinstance<span class="punctuation token">.</span>book<span class="punctuation token">.</span>_id <span class="punctuation token">,</span> errors<span class="punctuation token">:</span> errors<span class="punctuation token">.</span><span class="function token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> bookinstance<span class="punctuation token">: </span>bookinstance <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="keyword token">return</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="keyword token">else</span> <span class="punctuation token">{</span> + <span class="comment token">// Data from form is valid.</span> + bookinstance<span class="punctuation token">.</span><span class="function token">save</span><span class="punctuation token">(</span><span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span> + <span class="comment token">// Successful - redirect to new record.</span> + res<span class="punctuation token">.</span><span class="function token">redirect</span><span class="punctuation token">(</span>bookinstance<span class="punctuation token">.</span>url<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="punctuation token">}</span> +<span class="punctuation token">]</span><span class="punctuation token">;</span></code></pre> + +<p>The structure and behaviour of this code is the same as for creating our other objects. First we validate and sanitize the data. If the data is invalid, we then re-display the form along with the data that was originally entered by the user and a list of error messages. If the data is valid, we save the new <code>BookInstance</code> record and redirect the user to the detail page.</p> + +<h2 class="highlight-spanned" id="View"><span class="highlight-span">View</span></h2> + +<p>Create <strong>/views/bookinstance_form.pug</strong> and copy in the text below.</p> + +<pre class="line-numbers language-html"><code class="language-html">extends layout + +block content + h1=title + + form(method='POST' action='') + div.form-group + label(for='book') Book: + select#book.form-control(type='select' placeholder='Select book' name='book' required='true') + - book_list.sort(function(a, b) {let textA = a.title.toUpperCase(); let textB = b.title.toUpperCase(); return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;}); + for book in book_list + if bookinstance + option(value=book._id selected=(bookinstance.book.toString()==book._id.toString() ? 'selected' : false)) #{book.title} + else + option(value=book._id) #{book.title} + + div.form-group + label(for='imprint') Imprint: + input#imprint.form-control(type='text' placeholder='Publisher and date information' name='imprint' required='true' value=(undefined===bookinstance ? '' : bookinstance.imprint)) + div.form-group + label(for='due_back') Date when book available: + input#due_back.form-control(type='date' name='due_back' value=(undefined===bookinstance ? '' : bookinstance.due_back)) + + div.form-group + label(for='status') Status: + select#status.form-control(type='select' placeholder='Select status' name='status' required='true') + option(value='Maintenance') Maintenance + option(value='Available') Available + option(value='Loaned') Loaned + option(value='Reserved') Reserved + + button.btn.btn-primary(type='submit') Submit + + if errors + ul + for error in errors + li!= error.msg</code></pre> + +<p>The view structure and behaviour is almost the same as for the <strong>book_form.pug</strong> template, so we won't go over it again.</p> + +<div class="note"> +<p><strong>Note:</strong> The above template hard-codes the <em>Status</em> values (Maintenance, Available, etc.) and does not "remember" the user's entered values. Should you so wish, consider reimplementing the list, passing in option data from the controller and setting the selected value when the form is re-displayed.</p> +</div> + +<h2 class="highlight-spanned" id="Как_это_выглядит"><span class="highlight-span">Как это выглядит?</span></h2> + +<p>Запустите приложение и откройте в браузере <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>. Затем выберите ссылку <em>Create new book instance (copy)</em>. Если все настроено правильно, ваш сайт должен выглядеть примерно так, как показано на скриншоте. После того, как вы отправите валидный <code>BookInstance</code>, он должен быть сохранен, и вы попадете на страницу сведений.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14490/LocalLibary_Express_BookInstance_Create_Empty.png" style="display: block; height: 554px; margin: 0px auto; width: 1000px;"></p> + +<h2 id="Next_steps">Next steps</h2> + +<ul> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a>.</li> + <li>Proceed to the next subarticle of part 6: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Delete_author_form">Delete Author form</a>.</li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/forms/create_genre_form/index.html b/files/ru/learn/server-side/express_nodejs/forms/create_genre_form/index.html new file mode 100644 index 0000000000..c9407372c4 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/forms/create_genre_form/index.html @@ -0,0 +1,199 @@ +--- +title: Create genre form +slug: Learn/Server-side/Express_Nodejs/forms/Create_genre_form +translation_of: Learn/Server-side/Express_Nodejs/forms/Create_genre_form +--- +<p>В этом подразделе рассказано, как сделать страницу для создания жанра (<code>Genre</code>). Хорошая точка для старта, у жанра всего одно поле - <code>name</code>. Как и для любой другой страницы, здесь потребуется внести изменения в соответствующие маршрут, контроллер и шаблон (route, controller, view).</p> + +<h2 id="Import_validation_and_sanitisation_methods">Import validation and sanitisation methods</h2> + +<p>To use the <em>express-validator </em>in our controllers we have to <em>require</em> the functions we want to use from the <strong>'express-validator/check</strong>' and <strong>'express-validator/filter</strong>' modules.</p> + +<p>Open <strong>/controllers/genreController.js</strong>, and add the following line at the top of the file:</p> + +<pre class="brush: js">const validator = require('express-validator'); +</pre> + +<h2 id="Controller—get_route">Controller—get route</h2> + +<p>Find the exported <code>genre_create_get()</code> controller method and replace it with the following code. This simply renders the <strong>genre_form.pug</strong> view, passing a title variable.</p> + +<pre class="brush: js">// Display Genre create form on GET. +exports.genre_create_get = function(req, res, next) { + res.render('genre_form', { title: 'Create Genre' }); +};</pre> + +<h2 id="Controller—post_route">Controller—post route</h2> + +<p>Find the exported <code>genre_create_post()</code> controller method and replace it with the following code.</p> + +<pre class="brush: js">// Handle Genre create on POST. +exports.genre_create_post = [ + + // Validate that the name field is not empty. + validator.body('name', 'Genre name required').trim().isLength({ min: 1 }), + + // Sanitize (escape) the name field. + validator.sanitizeBody('name').escape(), + + // Process request after validation and sanitization. + (req, res, next) => { + + // Extract the validation errors from a request. + const errors = validator.validationResult(req); + + // Create a genre object with escaped and trimmed data. + var genre = new Genre( + { name: req.body.name } + ); + + + if (!errors.isEmpty()) { + // There are errors. Render the form again with sanitized values/error messages. + res.render('genre_form', { title: 'Create Genre', genre: genre, errors: errors.array()}); + return; + } + else { + // Data from form is valid. + // Check if Genre with same name already exists. + Genre.findOne({ 'name': req.body.name }) + .exec( function(err, found_genre) { + if (err) { return next(err); } + + if (found_genre) { + // Genre exists, redirect to its detail page. + res.redirect(found_genre.url); + } + else { + + genre.save(function (err) { + if (err) { return next(err); } + // Genre saved. Redirect to genre detail page. + res.redirect(genre.url); + }); + + } + + }); + } + } +];</pre> + +<p>The first thing to note is that instead of being a single middleware function (with arguments <code>(req, res, next)</code>) the controller specifies an <em>array</em> of middleware functions. The array is passed to the router function and each method is called in order.</p> + +<div class="note"> +<p><strong>Note:</strong> This approach is needed, because the sanitisers/validators are middleware functions.</p> +</div> + +<p>The first method in the array defines a validator (<code>validator.body()</code>) from the <code>validator</code> module to check that the <em>name</em> field is not empty (calling <code>trim()</code> to remove any trailing/leading whitespace before performing the validation). The second method in the array (<code>validator.sanitizeBody()</code>) creates a sanitizer to <code>escape()</code> any dangerous HTML characters in the <em>name</em> field.</p> + +<pre class="brush: js">// Validate that the name field is not empty. +validator<code>.</code>body('name', 'Genre name required').isLength({ min: 1 }).trim(), + +// Sanitize (escape) the name field. +validator.sanitizeBody('name').escape()</pre> + +<p>After specifying the validators and sanitizers we create a middleware function to extract any validation errors. We use <code>isEmpty()</code> to check whether there are any errors in the validation result. If there are then we render the form again, passing in our sanitised genre object and the array of error messages (<code>errors.array()</code>).</p> + +<pre class="brush: js">// Process request after validation and sanitization. +(req, res, next) => { + + // Extract the validation errors from a request. + const errors = validator.validationResult(req); + + // Create a genre object with escaped and trimmed data. + var genre = new Genre( + { name: req.body.name } + ); + + if (!errors.isEmpty()) { + // There are errors. Render the form again with sanitized values/error messages. + res.render('genre_form', { title: 'Create Genre', genre: genre, errors: errors.array()}); + return; + } + else { + // Data from form is valid. + ... <save the result/> ... + } +};</pre> + +<p>If the genre name data is valid then we check if a <code>Genre</code> with the same name already exists (as we don't want to create duplicates). If it does, we redirect to the existing genre's detail page. If not, we save the new <code>Genre</code> and redirect to its detail page.</p> + +<pre class="brush: js">// Check if Genre with same name already exists. +Genre.findOne({ 'name': req.body.name }) + .exec( function(err, found_genre) { + if (err) { return next(err); } + if (found_genre) { + // Genre exists, redirect to its detail page. + res.redirect(found_genre.url); + } + else { + genre.save(function (err) { + if (err) { return next(err); } + // Genre saved. Redirect to genre detail page. + res.redirect(genre.url); + }); + } +});</pre> + +<p>This same pattern is used in all our post controllers: we run validators, then sanitisers, then check for errors and either re-render the form with error information or save the data. </p> + +<h2 id="View">View</h2> + +<p>The same view is rendered in both the <code>GET</code> and <code>POST</code> controllers/routes when we create a new <code>Genre</code> (and later on it is also used when we <em>update</em> a <code>Genre</code>). In the <code>GET</code> case the form is empty, and we just pass a title variable. In the <code>POST</code> case the user has previously entered invalid data—in the <code>genre</code> variable we pass back a sanitized version of the entered data and in the <code>errors</code> variable we pass back an array of error messages.</p> + +<pre class="brush: js">res.render('genre_form', { title: 'Create Genre'}); +res.render('genre_form', { title: 'Create Genre', genre: genre, errors: errors.array()});</pre> + +<p>Create <strong>/views/genre_form.pug</strong> and copy in the text below.</p> + +<pre class="brush: html">extends layout + +block content + h1 #{title} + + form(method='POST' action='') + div.form-group + label(for='name') Genre: + input#name.form-control(type='text', placeholder='Fantasy, Poetry etc.' name='name' value=(undefined===genre ? '' : genre.name)) + button.btn.btn-primary(type='submit') Submit + + if errors + ul + for error in errors + li!= error.msg</pre> + +<p>Much of this template will be familiar from our previous tutorials. First, we extend the <strong>layout.pug</strong> base template and override the <code>block</code> named '<strong>content</strong>'. We then have a heading with the <code>title</code> we passed in from the controller (via the <code>render()</code> method).</p> + +<p>Next, we have the pug code for our HTML form that uses the <code>POST</code> <code>method</code> to send the data to the server, and because the <code>action</code> is an empty string, will send the data to the same URL as the page.</p> + +<p>The form defines a single required field of type "text" called "name". The default <em>value</em> of the field depends on whether the <code>genre</code> variable is defined. If called from the <code>GET</code> route it will be empty as this is a new form. If called from a <code>POST</code> route it will contain the (invalid) value originally entered by the user.</p> + +<p>The last part of the page is the error code. This simply prints a list of errors, if the error variable has been defined (in other words, this section will not appear when the template is rendered on the <code>GET</code> route).</p> + +<div class="note"> +<p><strong>Note:</strong> This is just one way to render the errors. You can also get the names of the affected fields from the error variable, and use these to control where the error messages are rendered, whether to apply custom CSS, etc.</p> +</div> + +<h2 id="What_does_it_look_like">What does it look like?</h2> + +<p>Run the application, open your browser to <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>, then select the <em>Create new genre </em>link. If everything is set up correctly, your site should look something like the following screenshot. After you enter a value, it should be saved and you'll be taken to the genre detail page.</p> + +<p><img alt="Genre Create Page - Express Local Library site" src="https://mdn.mozillademos.org/files/14476/LocalLibary_Express_Genre_Create_Empty.png" style="border-style: solid; border-width: 1px; display: block; height: 301px; margin: 0px auto; width: 800px;"></p> + +<p>The only error we validate against server-side is that the genre field must not be empty. The screenshot below shows what the error list would look like if you didn't supply a genre (highlighted in red).</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14480/LocalLibary_Express_Genre_Create_Error.png" style="border-style: solid; border-width: 1px; display: block; height: 249px; margin: 0px auto; width: 400px;"></p> + +<div class="note"> +<p><strong>Note:</strong> Our validation uses <code>trim()</code> to ensure that whitespace is not accepted as a genre name. We can also validate that the field is not empty on the client side by adding the value <code>required='true'</code> to the field definition in the form:</p> + +<pre class="brush: js">input#name.form-control(type='text', placeholder='Fantasy, Poetry etc.' name='name' value=(undefined===genre ? '' : genre.name), <strong>required='true'</strong> )</pre> +</div> + +<h2 id="Next_steps">Next steps</h2> + +<ol> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms.</a></li> + <li>Proceed to the next sub article of part 6: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_author_form">Create Author form</a>.</li> +</ol> diff --git a/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.html b/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.html new file mode 100644 index 0000000000..0e0fa6cdf3 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.html @@ -0,0 +1,165 @@ +--- +title: Delete Author form +slug: Learn/Server-side/Express_Nodejs/forms/Delete_author_form +translation_of: Learn/Server-side/Express_Nodejs/forms/Delete_author_form +--- +<p>В этой статье показано, как определить страницу для удаления объектов <code>Author</code>.</p> + +<p>Как описано в разделе <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/forms#form_design">form design</a>, наша стратегия будет заключаться в том, чтобы разрешить удаление только объектов, на которые не ссылаются другие объекты(в этом случае это означает, что мы не позволим <code>Author</code> быть удаленным, если на него ссылается <code>Book</code>). С точки зрения реализации это означает, что форма должна подтвердить, что нет никаких связанных книг, прежде чем автор будет удален. Если есть связанные книги, то они должны отображаться и быть удалены до того, как будеет удален объект <code>Author</code>.</p> + +<h2 class="highlight-spanned" id="Controller—get_route">Controller—get route</h2> + +<p>Откройте <strong>/controllers/authorController.js</strong>. Найдите экспротируемый метод контроллера <code>author_delete_get()</code> и замените его на слдеующий код.</p> + +<pre><code class="language-js">// Отображать форму для удаления автора GET +exports.author_delete_get = function(req, res, next) { + + async.parallel({ + author: function(callback) { + Author.findById(req.params.id).exec(callback) + }, + authors_books: function(callback) { + Book.find({ 'author': req.params.id }).exec(callback) + }, + }, function(err, results) { + if (err) { return next(err); } + if (results.author==null) { // No results. + res.redirect('/catalog/authors'); + } + // </code>Удачно, значит рендерим.<code class="language-js"> + res.render('author_delete', { title: 'Delete Author', author: results.author, author_books: results.authors_books } ); + }); + +};</code></pre> + +<p>TКонтроллер получает id экземпляра <code>Author</code> для удаления из параметра URL (<code>req.params.id</code>). Он использует метод <code>async.parallel()</code> , чтобы получить запись автра и паралельнно вс связанные книги. WКогда оба пораметра авершины, он рендерит страницу <code><strong>author_delete</strong></code><strong>.pug</strong>, передает значения для <code>title</code>, <code>author</code>, и <code>author_books</code>.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Если <code>findById()</code><strong> </strong>не возвращает результатов, то автор отсутствует в базе данных. В этом случае удалять нечего, поэтому сразу выводим список всех авторов.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js">}, function(err, results) { + if (err) { return next(err); } + if (results.author==null) { // No results. + res.redirect('/catalog/authors') + }</code></pre> +</div> + +<h2 class="highlight-spanned" id="Controller—post_route">Controller—post route</h2> + +<p>Найдите экспортируемый метод контроллера <code>author_delete_post()</code> и замените его на следующий код.</p> + +<pre><code class="language-js">// Обработчик удаления автора POST. +exports.author_delete_post = function(req, res, next) { + + async.parallel({ + author: function(callback) { + Author.findById(req.body.authorid).exec(callback) + }, + authors_books: function(callback) { + Book.find({ 'author': req.body.authorid }).exec(callback) + }, + }, function(err, results) { + if (err) { return next(err); } + // Success + if (results.authors_books.length > 0) { + // </code>Автор книги. Визуализация выполняется так же, как и для GET route.<code class="language-js"> + res.render('author_delete', { title: 'Delete Author', author: results.author, author_books: results.authors_books } ); + return; + } + else { + </code>//У автора нет никаких книг. Удалить объект и перенаправить в список авторов.<code class="language-js"> + Author.findByIdAndRemove(req.body.authorid, function deleteAuthor(err) { + if (err) { return next(err); } + // </code>Успех-перейти к списку авторов<code class="language-js"> + res.redirect('/catalog/authors') + }) + } + }); +};</code></pre> + +<p>Сначала мы проверяем, что был предоставлен id (он отправляется через параметры тела формы, а не через версию в URL). Затем мы получаем автора и связанные с ним книги так же, как и для маршрута <code>GET</code>. Если книг нет, то удаляем объект автора и перенаправляем в список всех авторов. Если есть еще книги, то мы просто перерисовываем форму, передавая автора и список книг, которые нужно удалить.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Мы можем проверить, возвращает ли вызов <code>findbyid ()</code> какой-либо результат, и если нет, немедленно отобразить список всех авторов.Для краткости мы оставили код как есть выше (он все равно вернет список авторов, если id не будет найден, но это произойдет после <code>findByIdAndRemove()</code>).</p> +</div> + +<h2 class="highlight-spanned" id="View">View</h2> + +<p>Создайте <strong>/views/author_delete.pug</strong> и скопируйет текст ниже.</p> + +<pre class="line-numbers language-html"><code class="language-html">extends layout + +block content + h1 #{title}: #{author.name} + p= author.lifespan + + if author_books.length + + p #[strong Delete the following books before attempting to delete this author.] + + div(style='margin-left:20px;margin-top:20px') + + h4 Books + + dl + each book in author_books + dt + a(href=book.url) #{book.title} + dd #{book.summary} + + else + p Do you really want to delete this Author? + + form(method='POST' action='') + div.form-group + input#authorid.form-control(type='hidden',name='authorid', required='true', value=author._id ) + + button.btn.btn-primary(type='submit') Delete</code></pre> + +<p>Представление расширяет шаблон макета, переопределяя блок с именем <code>content</code>. Вверху отображаются сведения об авторе. Затем он включает условный оператор, основанный на количестве <code><strong>author_books</strong></code> (пункты <code>if</code> и <code>else</code> ).</p> + +<ul> + <li>Если есть книги, связанные с автором, то на странице перечислены книги и говорится, что они должны быть удалены, прежде чем этот <code>Author</code> может быть удален.</li> + <li>Если книг нет, на странице отображается запрос на подтверждение. Если нажать кнопку <strong>Delete</strong>, то id автора будет отправлен на сервер в <code>POST</code>-запросе, и запись этого автора будет удалена.</li> +</ul> + +<h2 class="highlight-spanned" id="Добавление_элемента_управления_delete">Добавление элемента управления delete</h2> + +<p>Затем мы добавим элемент управления <code>Delete</code> в представление сведений об авторе (страница сведений-хорошее место для удаления записи).</p> + +<div class="note"> +<p><strong>Note:</strong> В полном объеме контроль будет доступен только авторизованным пользователям. Однако на данный момент у нас нет системы авторизации!</p> +</div> + +<p>Откройте <strong>author_detail.pug</strong> и добавьте следующие строки внизу.</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html">hr +p + a(href=author.url+'/delete') Delete author</code></pre> + +<p>Теперь элемент управления должен отображаться в виде ссылки, как показано ниже на странице сведений об авторе.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14492/LocalLibary_Express_Author_Detail_Delete.png" style="border-style: solid; border-width: 1px; display: block; height: 202px; margin: 0px auto; width: 500px;"></p> + +<h2 class="highlight-spanned" id="Как_это_выглядит">Как это выглядит?</h2> + +<p>Запустите приложение и откройте в вашем браузере <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>. Затем раздел <em>All authors </em>, а затем укажите конктретного пользователя. Наконец, выберите ссылку <em>Delete author</em>.</p> + +<p>Если у автора нет книг, вам будет представлена такая страница. После нажатия клавиши delete сервер удалит автора и перенаправит в список авторов</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14494/LocalLibary_Express_Author_Delete_NoBooks.png" style="border-style: solid; border-width: 1px; display: block; height: 342px; margin: 0px auto; width: 600px;"></p> + +<p>Если у автора есть книги, то вам будет представлен следующий вид. Затем вы можете удалить книги из их подробных страниц (как только этот код будет реализован!).</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14496/LocalLibary_Express_Author_Delete_WithBooks.png" style="border-style: solid; border-width: 1px; display: block; height: 327px; margin: 0px auto; width: 500px;"></p> + +<div class="note"> +<p><strong>Note:</strong> Другие страницы для удаления объектов могут быть реализованы примерно таким же образом. Мы оставили это как задачи.</p> +</div> + +<h2 id="Next_steps">Next steps</h2> + +<ul> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a>.</li> + <li>Proceed to the final subarticle of part 6: <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Update_Book_form">Update Book form</a>.</li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/forms/index.html b/files/ru/learn/server-side/express_nodejs/forms/index.html new file mode 100644 index 0000000000..f877a6015c --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/forms/index.html @@ -0,0 +1,269 @@ +--- +title: 'Учебник Express часть 6: Работа с формами' +slug: Learn/Server-side/Express_Nodejs/forms +tags: + - Начинающим + - Сервер + - Формы +translation_of: Learn/Server-side/Express_Nodejs/forms +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs/deployment", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">В этой главе мы покажем Вам как работать с HTML формами в Express, используя Pug, и в частности как написать формы для создания, обновления и удаления документов из базы данных.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные знания:</th> + <td>Завершите изучение предыдущих тем учебника, включая <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Учебник Express Часть 5: Отображение данных библиотеки</a></td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять, как писать формы для получения данных от пользователей и обновлять базу данных с этими данными.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p><a href="/en-US/docs/Web/Guide/HTML/Forms">HTML форма</a> - это группа из одного или нескольких полей / виджетов на веб-странице, которая может использоваться для сбора информации от пользователей для отправки на сервер. Формы представляют собой гибкий механизм для сбора данных, вводимых пользователем, поскольку существуют подходящие входные данные форм, доступные для ввода различных типов данных-текстовые поля, флажки, переключатели, средства выбора даты и т. д. Формы также являются относительно безопасным способом обмена данными с сервером, поскольку они позволяют отправлять данные в запросах <code>POST</code> с защитой от подделки межсайтовых запросов.</p> + +<p>Работа с формами может быть сложной! Разработчику нужно написать HTML код для форм, валидацию и правильно анализировать введенные данные на сервере (и, возможно, также в браузере), отобразить форму с сообщениями об ошибках, чтобы сообщить пользователям о любых недопустимых полях, обработать данные, когда они были успешно отправлены, и, наконец, каким-то образом ответить пользователю о том, что результат успешен.</p> + +<p>В этом уроке мы покажем вам, как вышеуказанные операции могут быть выполнены в <em>Express</em>. По пути мы расширим веб-сайт <em>LocalLibrary</em>, чтобы пользователи могли создавать, редактировать и удалять элементы из библиотеки.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Мы не рассматривали, как ограничить определенные маршруты аутентифицированными или авторизованными пользователями, поэтому на данный момент любой пользователь сможет вносить изменения в базу данных.</p> +</div> + +<h3 id="HTML_Forms">HTML Forms</h3> + +<p>Первый краткий обзор <a href="/en-US/docs/Web/Guide/HTML/Forms">HTML Forms</a>. Рассмотрим простую HTML-форму с одним текстовым полем для ввода имени некоторой "команды" и связанной с ней меткой:</p> + +<p><img alt="Simple name field example in HTML form" src="https://mdn.mozillademos.org/files/14117/form_example_name_field.png" style="border-style: solid; border-width: 1px; display: block; height: 44px; margin: 0px auto; width: 399px;"></p> + +<p>Определенные в HTML формы собираются внутри тэга <code><form>...</form></code>, содержащего хтя ы один элемент <code>input</code> с <code>type="submit"</code>.</p> + +<pre class="brush: html notranslate"><form action="/team_name_url/" method="post"> + <label for="team_name">Enter name: </label> + <input id="team_name" type="text" name="name_field" value="Default name for team."> + <input type="submit" value="OK"> +</form></pre> + +<p>Хотя здесь мы включили только одно (текстовое) поле для ввода имени команды, форма может содержать любое количество других элементов ввода и связанных с ними меток. Атрибут <code>type</code> определяет какой из <a href="/ru/docs/Learn/HTML/Forms/Стандартные_виджеты_форм">виджетов</a> будет выбран для отображения поля. Атрибуты <code>name</code> и <code>id</code> идентифицируют поле в JavaScript/CSS/HTML, а <code>value</code> определяет его первоначальное значение. Связанная с полем метка, задается с помощью тега <code style="font-style: normal; font-weight: normal;">label</code> (располгается строкой выше и содержит в себе подпись "Enter name"). Связь метки и поля ввода устанавливается при помощи атрибута <code>for</code>, в котором указывается значение идентификатора поля (<code>input</code> <code>id</code>).</p> + +<p>Input <code>submit </code>будет отображаться в виде кнопки (по умолчанию) - он может быть нажат пользователем, чтобы загрузить данные, содержащиеся в других входных элементов на сервер (в данном случае, только team_name). Атрибуты формы определяют метод HTTP, используемый для отправки данных, и назначение данных на сервере (action):</p> + +<ul> + <li><code>action</code>: ресурс/URL-адрес, по которому данные должны отправляться на обработку при отправке формы. Если это не установлено (или установлено в пустую строку), то форма будет отправлена назад к URL текущей страницы.</li> + <li><code>method</code>: Метод HTTP, используемый для отправки данных: <code>POST</code> or <code>GET</code>. + <ul> + <li>Метод <code>POST</code> должен всегда использоваться, если данные собираются привести к изменению базы данных сервера, потому что это может быть сделано более устойчивым к атакам запроса подделки межсайтового.</li> + <li>Метод <code>GET</code> следует использовать только для форм, которые не изменяют пользовательские данные (например, форма поиска). Рекомендуется, когда вы хотите, чтобы иметь возможность делать закладки или поделиться URL.</li> + </ul> + </li> +</ul> + +<h3 id="Процесс_обработки_формы">Процесс обработки формы</h3> + +<p>Обработка форм использует все те же методы, которые мы изучили для отображения информации о наших моделях: маршрут отправляет запрос в функцию контроллера, которая выполняет все необходимые действия с базой данных, включая чтение данных из моделей, а затем генерирует и возвращает HTML-страницу. Что усложняет ситуацию, так это то, что сервер также должен иметь возможность обрабатывать данные, предоставленные пользователем, и повторно отображать форму с информацией об ошибках, если есть какие-либо проблемы.</p> + +<p>Блок-схема процесса обработки запросов формы показана ниже, начиная с запроса страницы, содержащей форму (показана зеленым цветом):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14478/Web%20server%20form%20handling.png" style="height: 649px; width: 800px;"></p> + +<p>Как показано на диаграмме выше, основные действия, которые необходимо выполнить коду обработки форм:</p> + +<ol> + <li>Отображение формы по умолчанию при первом запросе пользователем. + <ul> + <li>Форма может содержать пустые поля (например, если вы создаете новую запись), или она может быть предварительно заполнена начальными значениями (например, если вы изменяете запись или имеете полезные начальные значения по умолчанию).</li> + </ul> + </li> + <li>Получение данных, отправленных пользователем, обычно в запросе HTTP <code>POST</code>.</li> + <li>Валидация и очистка данных.</li> + <li>Если какие-либо данные недопустимы, повторно отобразите форму—на этот раз с заполненными пользователем значениями и сообщениями об ошибках для проблемных полей</li> + <li>Если все данные верны, выполнить требуемые действия (например, сохранить данные в базе данных, отправьте уведомление по электронной почте, возвращающие результат поиска, загрузить файл и т. д.)</li> + <li>После завершения всех действий перенаправьте пользователя на другую страницу.</li> +</ol> + +<p>Часто код обработки формы реализуется с помощью <code>GET </code>route для начального отображения формы и <code>POST </code>route к тому же пути для обработки проверки и обработки данных формы. Это подход, который будет использоваться в этом уроке!</p> + +<p>Сам Express не предоставляет какой-либо конкретной поддержки для операций обработки форм, но он может использовать промежуточное программное обеспечение для обработки <code>POST</code> и <code>GET</code> параметров из формы, а также для проверки/очистки их значений.</p> + +<h3 id="Валидация_и_обработка">Валидация и обработка</h3> + +<p>Перед сохранением данных формы их необходимо проверить и очистить:</p> + +<ul> + <li>Проверка проверяет, что введенные значения являются подходящими для каждого поля (расположены в правильном диапазоне, формат и т. д.) и что значения были предоставлены для всех обязательных полей.</li> + <li>Очистка удаляет / заменяет символы в данных, которые потенциально могут использоваться для отправки вредоносного содержимого на сервер.</li> +</ul> + +<p>В этом уроке мы будем использовать популярный модуль <a href="https://www.npmjs.com/package/express-validator">express-validator</a> для проверки и очистки данных формы.</p> + +<h4 id="Установка">Установка</h4> + +<p>Установите модуль, выполнив следующую команду в корне проекта</p> + +<pre class="brush: bash notranslate">npm install express-validator +</pre> + +<h4 id="Использование_express-validator">Использование express-validator</h4> + +<div class="note"> +<p><strong>Note:</strong> <a href="https://github.com/ctavan/express-validator#express-validator">express-validator</a> руководство на Github предоставляет хороший обзор API. Мы рекомендуем вам прочитать это, чтобы получить представление о всех его возможностях (включая создание пользовательских валидаторов). Ниже мы рассмотрим только подмножество, которое полезно для <em>LocalLibrary</em>.</p> +</div> + +<p>Для того, чтобы использовать валидатор в наших контроллерах, мы должны требовать функции, которые мы хотим использовать из модулей <strong>'express-validator/check</strong>' и <strong>'express-validator/filter</strong>', как показано ниже:</p> + +<pre class="brush: js notranslate">const { body,validationResult } = require('express-validator/check'); +const { sanitizeBody } = require('express-validator/filter'); +</pre> + +<p>Есть много доступных функций, позволяющих проверять и очищать данные из параметров запроса, тела, заголовков, файлов cookie и т. д., или все сразу. Для этого урока мы будем использовать <code>body</code>, <code>sanitizeBody</code>, and <code>validationResult</code> (как "требуется" выше).</p> + +<p>Функции определяются следующим образом:</p> + +<ul> + <li><code><a href="https://github.com/ctavan/express-validator#bodyfields-message">body(fields[, message])</a></code>: Задает набор полей в теле запроса (параметр <code>POST</code>) для проверки, а также необязательное сообщение об ошибке, которое может отображаться в случае сбоя тестов. Критерии проверки последовательно связаны с методом <code>body()</code>. Например, первая проверка ниже проверяет, что поле" имя "не пустое и задает сообщение об ошибке" пустое имя", если оно не пустое. Второй тест проверяет, что поле age является допустимой датой, и с помощью optional() указывает, что пустые и пустые строки не пройдут проверку. + + <pre class="brush: js notranslate">body('name', 'Empty name').isLength({ min: 1 }), +body('age', 'Invalid age').optional({ checkFalsy: true }).isISO8601(), +</pre> + Можно также последовательно подключить различные валидаторы и добавить сообщения, отображаемые при выполнении предыдущих валидаторов.</li> + <li> + <pre class="brush: js notranslate">body('name').isLength({ min: 1 }).trim().withMessage('Name empty.') + .isAlpha().withMessage('Name must be alphabet letters.'), +</pre> + + <div class="note"> + <p><strong>Note:</strong> Вы также можете добавить встроенные средства очистки, такие как <code>trim()</code>, как показано выше. Однако средства очитски, применяемые здесь, применяются только к шагу проверки. Если требуется очистить конечный результат, необходимо использовать отдельный метод очистки, как показано ниже.</p> + </div> + </li> + <li><code><a href="https://github.com/ctavan/express-validator#sanitizebodyfields">sanitizeBody(fields)</a></code>: Задает поле тела для очистки. затем операции очистки последовательно соединяются с этим методом. Например, операция очистки <code>escape()</code>, описанная ниже, удаляет символы HTML из переменной name, которые могут использоваться в атаках сценариев между сайтами JavaScript. + <pre class="brush: js notranslate">sanitizeBody('name').trim().escape(), +sanitizeBody('date').toDate(),</pre> + </li> + <li><code><a href="https://github.com/ctavan/express-validator#validationresultreq">validationResult(req)</a></code>: Запускает проверку, делая ошибки доступными в виде объекта результата проверки. Это вызывается в отдельном обратном вызове, как показано ниже: + <pre class="brush: js notranslate">(req, res, next) => { + // Extract the validation errors from a request. + const errors = validationResult(req); + + if (!errors.isEmpty()) { + // There are errors. Render form again with sanitized values/errors messages. + // Error messages can be returned in an array using `errors.array()`. + } + else { + // Data from form is valid. + } +}</pre> + Мы используем метод <code>isEmpty()</code> результата проверки, чтобы проверить, были ли ошибки, и его метод array (), чтобы получить набор сообщений об ошибках. Дополнительные сведения см. в разделе API результатов проверки.</li> +</ul> + +<p>Цепочки проверки и очистки являются промежуточными запросами, которые должны быть переданы обработчику Express -маршрута (мы делаем это косвенно, через контроллер). При запуске промежуточного по каждый валидатор / средства очистки выполняется в указанном порядке..</p> + +<p>Мы рассмотрим некоторые реальные примеры, когда мы реализуем <em>LocalLibrary </em>формы ниже.</p> + +<h3 id="Дизайн_формы">Дизайн формы</h3> + +<p>Многие модели в библиотеке связаны / зависимы—например, книга требует автора, а также может иметь один или несколько жанров. Это поднимает вопрос о том, как мы должны обрабатывать случай, когда пользователь хочет:</p> + +<ul> + <li>Создайте объект, если связанные с ним объекты еще не существуют (например, книга, в которой не определен объект автора).</li> + <li>Удаление объекта, который все еще используется другим объектом (например, удаление жанра, который все еще используется книгой).</li> +</ul> + +<p>Для этого проекта мы упростили реализацию, объявив, что форма может быть только:</p> + +<ul> + <li>Создайте объект, используя объекты, которые уже существуют (таким образом, пользователи должны будут создать все необходимые экземпляры автора и жанра, прежде чем пытаться создать любые объекты книги).</li> + <li>Удалите объект, если на него не ссылаются другие объекты (например, Вы не сможете удалить книгу, пока не будут удалены все связанные объекты BookInstance).</li> +</ul> + +<div class="note"> +<p><strong>Note:</strong> Более" надежная " реализация может позволить создавать зависимые объекты при создании нового объекта и удалять любой объект в любое время (например, путем удаления зависимых объектов или путем удаления ссылок на удаленный объект из базы данных).</p> +</div> + +<h3 id="Маршруты">Маршруты</h3> + +<p>Чтобы реализовать наш код обработки форм, нам понадобятся два маршрута с одинаковым шаблоном URL. Первый (<code>GET</code>) маршрут используется для отображения новой пустой формы создания объекта. Второй маршрут (<code>POST</code>) используется для проверки введенных пользователем данных, а затем сохранения информации и перенаправления на страницу сведений (если данные верны) или повторного отображения формы с ошибками (если данные неверны).</p> + +<p>Мы уже создали маршруты для всех страниц создания нашей модели в <strong>/routes/catalog.js</strong> (in a <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes">previous tutorial</a>). Например, жанровые маршруты показаны ниже:</p> + +<pre class="brush: js notranslate">// GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id). +router.get('/genre/create', genre_controller.genre_create_get); + +// POST request for creating Genre. +router.post('/genre/create', genre_controller.genre_create_post); +</pre> + +<h2 id="Express_формы_—_подразделы">Express формы — подразделы</h2> + +<p>В следующих подразделах мы добавим необходимые формы для нашего веб-сайта. Вы должны прочитать и проработать каждый из них по очереди, прежде чем перейти к следующему.</p> + +<ol> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_genre_form">Форма для создания Genre</a> — Определение нашей страницы для создания объектов <code>Genre</code>.</li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_author_form">Форма для cоздания Author</a> — Определение страницы для создания объектов <code>Author</code>.</li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_book_form">Форма для создания Book</a> — Определение страницы/формы для создания объектов <code>Book</code>.</li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Create_BookInstance_form">Форма для создания BookInstance</a> — Определение страницы/формы для создания объектов <code>BookInstance</code>.</li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Delete_author_form">Форма для удаления Author</a> — Определение страницы для удаления объектов <code>Author</code>.</li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms/Update_Book_form">Форма для обновления Book</a> — Определение страницы для обновления объектов <code>Book</code>.</li> +</ol> + +<h2 id="Challenge_yourself">Challenge yourself</h2> + +<p>Implement the delete pages for the <code>Book</code>, <code>BookInstance</code>, and <code>Genre</code> models, linking them from the associated detail pages in the same way as our <em>Author delete </em>page. The pages should follow the same design approach:</p> + +<ul> + <li>If there are references to the object from other objects, then these other objects should be displayed along with a note that this record can't be deleted until the listed objects have been deleted.</li> + <li>If there are no other references to the object then the view should prompt to delete it. If the user presses the <strong>Delete</strong> button, the record should then be deleted.</li> +</ul> + +<p>A few tips:</p> + +<ul> + <li>Deleting a <code>Genre</code> is just like deleting an <code>Author</code> as both objects are dependencies of <code>Book</code> (so in both cases you can delete the object only when the associated books are deleted).</li> + <li>Deleting a <code>Book</code> is also similar, but you need to check that there are no associated <code>BookInstances</code>.</li> + <li>Deleting a <code>BookInstance</code> is the easiest of all, because there are no dependent objects. In this case you can just find the associated record and delete it.</li> +</ul> + +<p>Implement the update pages for the <code>BookInstance</code>, <code>Author</code>, and <code>Genre</code> models, linking them from the associated detail pages in the same way as our <em>Book update </em>page.</p> + +<p>A few tips:</p> + +<ul> + <li>The <em>Book update page</em> we just implemented is the hardest! The same patterns can be used for the update pages for the other objects.</li> + <li>The <code>Author</code> date of death and date of birth fields, and the <code>BookInstance</code> due_date field are the wrong format to input into the date input field on the form (it requires data in form "YYYY-MM-DD"). The easiest way to get around this is to define a new virtual property for the dates that formats the dates appropriately, and then use this field in the associated view templates.</li> + <li>If you get stuck, there are examples of the update pages in <a href="https://github.com/mdn/express-locallibrary-tutorial">the example here</a>.</li> +</ul> + +<h2 id="Summary">Summary</h2> + +<p><em>Express</em>, node, and third party packages on NPM provide everything you need to add forms to your website. In this article you've learned how to create forms using <em>Pug</em>, validate and sanitize input using <em>express-validator</em>, and add, delete, and modify records in the database.</p> + +<p>You should now understand how to add basic forms and form-handling code to your own node websites!</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://www.npmjs.com/package/express-validator">express-validator</a> (npm docs).</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs/deployment", "Learn/Server-side/Express_Nodejs")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.html b/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.html new file mode 100644 index 0000000000..16172605d1 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.html @@ -0,0 +1,189 @@ +--- +title: Update Book form +slug: Learn/Server-side/Express_Nodejs/forms/Update_Book_form +translation_of: Learn/Server-side/Express_Nodejs/forms/Update_Book_form +--- +<p><a class="button section-edit only-icon" href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/forms$edit#Update_Book_form" rel="nofollow, noindex"><span>Edit</span></a>Наконец, в разделе показано, как определить страницу для обновления объектов <code>Book</code>. Обработка форм при обновлении книги аналогична обработке форм при создании книги, за исключением того, что необходимо заполнить форму в маршруте <code>GET</code> значениями из базы данных.</p> + +<h2 class="highlight-spanned" id="Controller—get_route"><span class="highlight-span">Controller—get route</span></h2> + +<p>Откройте <strong>/controllers/bookController.js</strong>. Найдите экспортируемый метод контроллера <code>book_update_get()</code> и замените его на следующий код.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Display book update form on GET.</span> +exports<span class="punctuation token">.</span>book_update_get <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="punctuation token">{</span> + + <span class="comment token">// Get book, authors and genres for form.</span> + <span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">parallel</span><span class="punctuation token">(</span><span class="punctuation token">{</span> + book<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + Book<span class="punctuation token">.</span><span class="function token">findById</span><span class="punctuation token">(</span>req<span class="punctuation token">.</span>params<span class="punctuation token">.</span>id<span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">populate</span><span class="punctuation token">(</span><span class="string token">'author'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">populate</span><span class="punctuation token">(</span><span class="string token">'genre'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">exec</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + authors<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + Author<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + genres<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + Genre<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>results<span class="punctuation token">.</span>book<span class="operator token">==</span><span class="keyword token">null</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="comment token">// No results.</span> + <span class="keyword token">var</span> err <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Error</span><span class="punctuation token">(</span><span class="string token">'Book not found'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + err<span class="punctuation token">.</span>status <span class="operator token">=</span> <span class="number token">404</span><span class="punctuation token">;</span> + <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="comment token">// Success.</span> + <span class="comment token">// Mark our selected genres as checked.</span> + <span class="keyword token">for</span> <span class="punctuation token">(</span><span class="keyword token">var</span> all_g_iter <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span> all_g_iter <span class="operator token"><</span> results<span class="punctuation token">.</span>genres<span class="punctuation token">.</span>length<span class="punctuation token">;</span> all_g_iter<span class="operator token">++</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">for</span> <span class="punctuation token">(</span><span class="keyword token">var</span> book_g_iter <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span> book_g_iter <span class="operator token"><</span> results<span class="punctuation token">.</span>book<span class="punctuation token">.</span>genre<span class="punctuation token">.</span>length<span class="punctuation token">;</span> book_g_iter<span class="operator token">++</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>results<span class="punctuation token">.</span>genres<span class="punctuation token">[</span>all_g_iter<span class="punctuation token">]</span><span class="punctuation token">.</span>_id<span class="punctuation token">.</span><span class="function token">toString</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="operator token">==</span>results<span class="punctuation token">.</span>book<span class="punctuation token">.</span>genre<span class="punctuation token">[</span>book_g_iter<span class="punctuation token">]</span><span class="punctuation token">.</span>_id<span class="punctuation token">.</span><span class="function token">toString</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + results<span class="punctuation token">.</span>genres<span class="punctuation token">[</span>all_g_iter<span class="punctuation token">]</span><span class="punctuation token">.</span>checked<span class="operator token">=</span><span class="string token">'true'</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="punctuation token">}</span> + <span class="punctuation token">}</span> + res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'book_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Update Book'</span><span class="punctuation token">,</span> authors<span class="punctuation token">:</span>results<span class="punctuation token">.</span>authors<span class="punctuation token">,</span> genres<span class="punctuation token">:</span>results<span class="punctuation token">.</span>genres<span class="punctuation token">,</span> book<span class="punctuation token">:</span> results<span class="punctuation token">.</span>book <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + +<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre> + +<p>Контроллер получит id <code>Book</code> книги для обновления из параметра URL (<code>req.params.id</code>). Он использует метод <code>async.parallel()</code>чтобы получить указанную запись <code>Book</code> (pаполнение полей жанра и автора) и список всех объектов <code>Author</code> и <code>Genre</code>. Когда все операции завершены, он помечает выбранные жанры как отмеченные, а затем отображает их в <strong>book_form.pug</strong>, передает переменные <code>itle</code>, book, всех <code>authors</code>, и все<code>genres</code>.</p> + +<h2 class="highlight-spanned" id="Controller—post_route"><span class="highlight-span">Controller—post route</span></h2> + +<p>Найдите экспортируемый метод контроллера <code>book_update_post()</code> и замените его следующим кодом.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="comment token">// Handle book update on POST.</span> +exports<span class="punctuation token">.</span>book_update_post <span class="operator token">=</span> <span class="punctuation token">[</span> + + <span class="comment token">// Convert the genre to an array</span> + <span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="operator token">=</span><span class="operator token">></span> <span class="punctuation token">{</span> + <span class="keyword token">if</span><span class="punctuation token">(</span><span class="operator token">!</span><span class="punctuation token">(</span>req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>genre <span class="keyword token">instanceof</span> <span class="class-name token">Array</span><span class="punctuation token">)</span><span class="punctuation token">)</span><span class="punctuation token">{</span> + <span class="keyword token">if</span><span class="punctuation token">(</span><span class="keyword token">typeof</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>genre<span class="operator token">===</span><span class="string token">'undefined'</span><span class="punctuation token">)</span> + req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>genre<span class="operator token">=</span><span class="punctuation token">[</span><span class="punctuation token">]</span><span class="punctuation token">;</span> + <span class="keyword token">else</span> + req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>genre<span class="operator token">=</span><span class="keyword token">new</span> <span class="class-name token">Array</span><span class="punctuation token">(</span>req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>genre<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="function token">next</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + + <span class="comment token">// Validate fields.</span> + <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'title'</span><span class="punctuation token">,</span> <span class="string token">'Title must not be empty.'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'author'</span><span class="punctuation token">,</span> <span class="string token">'Author must not be empty.'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'summary'</span><span class="punctuation token">,</span> <span class="string token">'Summary must not be empty.'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">body</span><span class="punctuation token">(</span><span class="string token">'isbn'</span><span class="punctuation token">,</span> <span class="string token">'ISBN must not be empty'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">isLength</span><span class="punctuation token">(</span><span class="punctuation token">{</span> min<span class="punctuation token">:</span> <span class="number token">1</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + + <span class="comment token">// Sanitize fields.</span> + <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'title'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'author'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'summary'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'isbn'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + <span class="function token">sanitizeBody</span><span class="punctuation token">(</span><span class="string token">'genre.*'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">trim</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">escape</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">,</span> + + <span class="comment token">// Process request after validation and sanitization.</span> + <span class="punctuation token">(</span>req<span class="punctuation token">,</span> res<span class="punctuation token">,</span> next<span class="punctuation token">)</span> <span class="operator token">=</span><span class="operator token">></span> <span class="punctuation token">{</span> + + <span class="comment token">// Extract the validation errors from a request.</span> + <span class="keyword token">const</span> errors <span class="operator token">=</span> <span class="function token">validationResult</span><span class="punctuation token">(</span>req<span class="punctuation token">)</span><span class="punctuation token">;</span> + + <span class="comment token">// Create a Book object with escaped/trimmed data and old id.</span> + <span class="keyword token">var</span> book <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Book</span><span class="punctuation token">(</span> + <span class="punctuation token">{</span> title<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>title<span class="punctuation token">,</span> + author<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>author<span class="punctuation token">,</span> + summary<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>summary<span class="punctuation token">,</span> + isbn<span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>isbn<span class="punctuation token">,</span> + genre<span class="punctuation token">:</span> <span class="punctuation token">(</span><span class="keyword token">typeof</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>genre<span class="operator token">===</span><span class="string token">'undefined'</span><span class="punctuation token">)</span> <span class="operator token">?</span> <span class="punctuation token">[</span><span class="punctuation token">]</span> <span class="punctuation token">:</span> req<span class="punctuation token">.</span>body<span class="punctuation token">.</span>genre<span class="punctuation token">,</span> + _id<span class="punctuation token">:</span>req<span class="punctuation token">.</span>params<span class="punctuation token">.</span>id <span class="comment token">//This is required, or a new ID will be assigned!</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + + <span class="keyword token">if</span> <span class="punctuation token">(</span><span class="operator token">!</span>errors<span class="punctuation token">.</span><span class="function token">isEmpty</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="comment token">// There are errors. Render form again with sanitized values/error messages.</span> + + <span class="comment token">// Get all authors and genres for form.</span> + <span class="keyword token">async</span><span class="punctuation token">.</span><span class="function token">parallel</span><span class="punctuation token">(</span><span class="punctuation token">{</span> + authors<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + Author<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + genres<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span> <span class="punctuation token">{</span> + Genre<span class="punctuation token">.</span><span class="function token">find</span><span class="punctuation token">(</span>callback<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> + <span class="punctuation token">}</span><span class="punctuation token">,</span> <span class="keyword token">function</span><span class="punctuation token">(</span>err<span class="punctuation token">,</span> results<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span> + + <span class="comment token">// Mark our selected genres as checked.</span> + <span class="keyword token">for</span> <span class="punctuation token">(</span><span class="keyword token">let</span> i <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span> i <span class="operator token"><</span> results<span class="punctuation token">.</span>genres<span class="punctuation token">.</span>length<span class="punctuation token">;</span> i<span class="operator token">++</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>book<span class="punctuation token">.</span>genre<span class="punctuation token">.</span><span class="function token">indexOf</span><span class="punctuation token">(</span>results<span class="punctuation token">.</span>genres<span class="punctuation token">[</span>i<span class="punctuation token">]</span><span class="punctuation token">.</span>_id<span class="punctuation token">)</span> <span class="operator token">></span> <span class="operator token">-</span><span class="number token">1</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + results<span class="punctuation token">.</span>genres<span class="punctuation token">[</span>i<span class="punctuation token">]</span><span class="punctuation token">.</span>checked<span class="operator token">=</span><span class="string token">'true'</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="punctuation token">}</span> + res<span class="punctuation token">.</span><span class="function token">render</span><span class="punctuation token">(</span><span class="string token">'book_form'</span><span class="punctuation token">,</span> <span class="punctuation token">{</span> title<span class="punctuation token">:</span> <span class="string token">'Update Book'</span><span class="punctuation token">,</span>authors<span class="punctuation token">:</span>results<span class="punctuation token">.</span>authors<span class="punctuation token">,</span> genres<span class="punctuation token">:</span>results<span class="punctuation token">.</span>genres<span class="punctuation token">,</span> book<span class="punctuation token">:</span> book<span class="punctuation token">,</span> errors<span class="punctuation token">:</span> errors<span class="punctuation token">.</span><span class="function token">array</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="keyword token">return</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="keyword token">else</span> <span class="punctuation token">{</span> + <span class="comment token">// Data from form is valid. Update the record.</span> + Book<span class="punctuation token">.</span><span class="function token">findByIdAndUpdate</span><span class="punctuation token">(</span>req<span class="punctuation token">.</span>params<span class="punctuation token">.</span>id<span class="punctuation token">,</span> book<span class="punctuation token">,</span> <span class="punctuation token">{</span><span class="punctuation token">}</span><span class="punctuation token">,</span> <span class="keyword token">function</span> <span class="punctuation token">(</span>err<span class="punctuation token">,</span>thebook<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>err<span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> <span class="function token">next</span><span class="punctuation token">(</span>err<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span> + <span class="comment token">// Successful - redirect to book detail page.</span> + res<span class="punctuation token">.</span><span class="function token">redirect</span><span class="punctuation token">(</span>thebook<span class="punctuation token">.</span>url<span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="punctuation token">}</span> +<span class="punctuation token">]</span><span class="punctuation token">;</span></code></pre> + +<p>Это очень похоже на маршрут записи, используемый при создании Book. Сперва мы проверяем и очищаем данные книги и используем их для создание нового объекта <code>Book</code>(устанавливая его значение <code>_id</code> в идентификатор объекта для обновления). Если есть ошибки, когда мы проверяем данные, то мы повторно представляем форму, дополнительно отображая данные, введенные пользователем, ошибки, а также списки жанров и авторов. Если ошибок нет, то мы вызываем <code>Book.findByIdAndUpdate()</code> для обновления документа <code>Book</code>, а затем перенаправить на страницу сведений.</p> + +<h2 class="highlight-spanned" id="View"><span class="highlight-span">View</span></h2> + +<p>Откройте <strong>/views/book_form.pug</strong> и обновите раздел, в котором элемент управления "форма автора" имеет условный код, показанный ниже.</p> + +<pre class="line-numbers language-html"><code class="language-html"> div.form-group + label(for='author') Author: + select#author.form-control(type='select' placeholder='Select author' name='author' required='true' ) + for author in authors + if book + //- Handle GET form, where book.author is an object, and POST form, where it is a string. + option( + value=author._id + selected=( + author._id.toString()==book.author._id + || author._id.toString()==book.author + ) ? 'selected' : false + ) #{author.name} + else + option(value=author._id) #{author.name}</code></pre> + +<div class="note"> +<p><strong>Note</strong>: Это изменение кода необходимо для того, чтобы форму book_form можно было использовать как для создания, так и для обновления объектов book (без этого при создании формы на маршруте <code>GET</code> возникает ошибка).</p> +</div> + +<h2 class="highlight-spanned" id="Добавить_кнопку_обновления">Добавить кнопку обновления</h2> + +<p>Откройте <strong>book_detail.pug</strong> и убедитесь, что есть ссылки для удаления и обновления книг в нижней части страницы, как показано ниже.</p> + +<pre class="brush: html line-numbers language-html"><code class="language-html"> hr + p + a(href=book.url+'/delete') Delete Book + p + a(href=book.url+'/update') Update Book</code></pre> + +<p>Теперь вы можете обновлять книги со страницы сведений о книге.</p> + +<h2 class="highlight-spanned" id="Как_это_выглядит"><span class="highlight-span">Как это выглядит?</span></h2> + +<p>Запустите приложение, откройте ваш браузер на <a class="external external-icon" href="http://localhost:3000/" rel="noopener">http://localhost:3000/</a>, выберите ссылку <em>All books</em>, затем выберите конкретную книгу. Наконец, выберите ссылку <em>Update Book</em>.</p> + +<p>Форма должна выглядеть так же, как страница <em>Create book</em>, только с заголовком 'Update book' и предварительно заполнены значениями записей.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14498/LocalLibary_Express_Book_Update_NoErrors.png" style="border-style: solid; border-width: 1px; display: block; height: 443px; margin: 0px auto; width: 1000px;"></p> + +<div class="note"> +<p><strong>Note:</strong> Другие страницы для обновления объектов могут быть реализованы примерно таким же образом. Мы оставили это как задание.</p> +</div> + +<p> </p> + +<h2 id="Next_steps">Next steps</h2> + +<ul> + <li>Return to <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a>.</li> +</ul> + +<p> </p> diff --git a/files/ru/learn/server-side/express_nodejs/index.html b/files/ru/learn/server-side/express_nodejs/index.html new file mode 100644 index 0000000000..9c1f44a50f --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/index.html @@ -0,0 +1,77 @@ +--- +title: Веб-фреймворк Express (Node.js/JavaScript) +slug: Learn/Server-side/Express_Nodejs +tags: + - Express + - Express.js + - Введение + - Для начинающих + - Программирование на стороне сервера + - Учебник +translation_of: Learn/Server-side/Express_Nodejs +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Express представляет собой популярный веб-фреймворк, написанный на JavaScript и работающий внутри среды исполнения node.js. Этот модуль освещает некоторые ключевые преимущества этого фреймворка, установку среды разработки и выполнение основных задач веб-разработки и развертывания.</p> + +<h2 id="Предварительные_требования">Предварительные требования</h2> + +<p>Перед началом этого модуля вам необходимо представлять, что из себя представляет серверное программирование и веб-фреймворки, желательно из прочтения статей другого модуля <a href="/en-US/docs/Learn/Server-side/First_steps">Server-side website programming first steps</a>. Знакомство с основными концепциями программирования и языком программирования <a href="/en-US/docs/Web/JavaScript">JavaScript</a> будет очень полезным, но оно не является обязательным для понимания базовых понятий этого модуля.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Этот веб-сайт содержит множество источников для изучения JavaScript<em> в контексте разработки на стороне клиента</em>: <a href="/en-US/docs/Web/JavaScript">JavaScript</a>, <a href="/en-US/docs/Web/JavaScript/Guide">JavaScript Guide</a>, <a href="/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript Basics</a>, <a href="/en-US/docs/Learn/JavaScript">JavaScript</a> (изучение). Ключевые особенности и коцепции языка JavaScript остаются сходными и для серверной разработки на Node.js и используемый материал достаточно релевантен. Node.js предоставляет <a href="https://nodejs.org/dist/latest-v6.x/docs/api/">additional APIs</a> для обеспечения функционала, который полезен для "безбраузерной" разработки, т.е. для создания HTTP-сервера и доступа к файловой системе, но не поддерживает JavaScript APIs для работы с браузером и DOM.</p> + +<p>Это руководство обеспечит вас некоторой информацией о работе с Node.js и Express, но также существуют и другие многочисленные отличные ресурсы в Интернете и книгах — некоторые из них доступны из тем <a href="http://stackoverflow.com/a/5511507/894359">How do I get started with Node.js</a> (StackOverflow) и <a href="https://www.quora.com/What-are-the-best-resources-for-learning-Node-js?">What are the best resources for learning Node.js?</a> (Quora).</p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Введение в Express/Node</a></dt> + <dd>В первой статье об Express мы ответим на вопросы "Что такое Node?" и "Что такое Express?" и дадим вам представление о том, что делает веб-фреймворк Express особенным. <span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_3">Мы расскажем об основных функциях и покажем вам некоторые из основных строительных блоков приложений Express (хотя на данный момент у вас еще нет среды разработки, в которой можно ее протестировать)</span>.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Настройка среды разработки Node (Express)</a></dt> + <dd> + <div style="padding-bottom: 30px;"><span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_0">Теперь, когда вы знаете, что такое Express, мы покажем вам, как настроить и протестировать среду разработки Node/Express в Windows, Linux (Ubuntu) и Mac OS X. Независимо от того, какую популярную операционную систему вы используете, эта статья </span><span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_1">даст вам то, что вам нужно, чтобы начать разработку приложений Express.</span></div> + </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Учебник Express: сайт LocalLibrary</a></dt> + <dd> + <div style="padding-bottom: 30px;"><span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_0">Первая статья в нашей серии практических уроков объясняет, что вы будете изучать, и предоставит обзор веб-сайта «локальной библиотеки», над которым мы будем работать и развивать в последующих статьях.</span></div> + </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Учебник Express часть 2: Создание скелета веб-сайта</a></dt> + <dd> + <div style="padding-bottom: 30px;"><span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_0">В этой статье показано, как вы можете создать «скелет»</span><span class="s3gt_translate_tooltip_variant"> веб-сайта, который затем можно будет заполнить с помощью маршрутов сайта, шаблонов/представлений и баз данных.</span></div> + </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Учебник Express часть 3: Использование базы данных (с помощью Mongoose)</a></dt> + <dd>В этой статье кратко представлены базы данных для Node/Express. Затем показывается, как мы можем использовать <a href="http://mongoosejs.com/">Mongoose</a> для обеспечения доступа к баз данных для сайта <em>LocalLibrary</em>. <span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_2">В уроке объясняется, как объявляются объектная схема и модели, основные типы полей и базовая валидация.</span> <span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_3">Также кратко показаны некоторые из основных способов доступа к данным модели.</span></dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Учебник Express часть 4: Маршруты и контроллеры</a></dt> + <dd>В этом уроке мы создадим маршруты (код обработки URL) с "фиктивным" обработчиком функций для всех конечных точек ресурсов, которые нам в конечном итоге понадобятся для сайта<em> LocalLibrary</em>. По завершении мы будем иметь модульную структуру нашего кода обработки маршрута, который мы можем расширить с помощью функций реального обработчика в следующих статьях. Мы также будем очень хорошо понимать, как создавать модульные маршруты, используя Express.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Учебник Express часть 5: Отображение данных библиотеки</a></dt> + <dd>Теперь мы готовы добавить страницы, на которых будут отображаться книги веб-сайта <em>LocalLibrary</em> и другие данные. Страницы будут включать главную страницу, которая показывает сколько записей определенного типа мы имеем и отдельную страницу для детального просмотра записи. По пути мы получим практический опыт в получении записей из баз данных и использовании шаблонов.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Учебник Express часть 6: Работы с формами</a></dt> + <dd>В этой части мы покажем вам, как работать с <a href="/en-US/docs/Web/Guide/HTML/Forms">HTML формами</a> в Express, используя Pug, и в частности, как создавать, обновлять и удалять документы из базы данных.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Учебник Express часть 7: Выкладка в production</a></dt> + <dd>Теперь когда вы создали восхитительный сайт <em>LocalLibrary</em>, вы захотите установить его на общедоступном сервере, чтобы он мог дать доступ персоналу библиотеки и пользователям в Интернет. В этой статье представлен обзор того, как вы можете найти хост для развертывания вашего сайта и что вам нужно сделать, чтобы подготовить ваш сайт к публикации.</dd> +</dl> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Installing_on_PWS_Cloud_Foundry">Установка LocalLibrary на PWS/Cloud Foundry</a></dt> + <dd>В этой статье представлена практическая демонстрация того, как установить <em>LocalLibrary</em> на <a href="http://run.pivotal.io">облаке Pivotal Web Services PaaS</a> — это полнофункциональная альтернатива с открытым исходным кодом для Heroku, облачного сервиса PaaS используемого в части 7 этого учебника, представленного выше. PWS/Cloud Foundry опредленно стоит попробовать, если вы ищете альтернативу Heroku (или другому PaaS облачному сервису), или просто хотите попробовать что-то другое.</dd> +</dl> + +<h2 id="Изучите_другие_учебники">Изучите другие учебники</h2> + +<div> +<p>Это все статьи учебника (на данный момент). Если вы хотите продолжить обучение, есть другие интересные темы:</p> + +<ul> + <li>Использование сессий</li> + <li>Авторизация пользователей</li> + <li>Авторизация пользователей и уровни доступа</li> + <li>Тестирование веб приложений Express</li> + <li>Веб безопасность для веб приложений Express.</li> +</ul> + +<p>И, конечно, было бы неплохо создать какой-либо проверочный тест знаний!</p> +</div> diff --git a/files/ru/learn/server-side/express_nodejs/introduction/index.html b/files/ru/learn/server-side/express_nodejs/introduction/index.html new file mode 100644 index 0000000000..bbe40c95f7 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/introduction/index.html @@ -0,0 +1,512 @@ +--- +title: Express/Node introduction +slug: Learn/Server-side/Express_Nodejs/Introduction +translation_of: Learn/Server-side/Express_Nodejs/Introduction +--- +<div>{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">В этой первой статье по Express мы ответим на вопросы "Что такое Node?" и "Что такое Express?", и сделаем обзор того, что делает веб-фреймворк Express таким особенным. <span id="result_box" lang="ru"><span>Мы расскажем об основных функциях и покажем вам некоторые из основных строительных блоков приложения Express (хотя на данный момент у вас еще нет среды разработки, в которой можно ее протестировать).</span></span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные знания:</th> + <td><span id="result_box" lang="ru"><span>Базовая компьютерная грамотность.</span> <span>Общее понимание </span></span><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps">серверного программирования веб-сайтов </a><span lang="ru"><span>и, в частности, механики </span></span><a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">клиент-серверного взаимодействия на веб-сайтах</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Ознакомить Вас с фреймворком <span id="result_box" lang="ru"><span>Express и как он вписывается в среду Node, какие функции он предоставляет, и основные строительные блоки приложения Express.</span></span></td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_Express_и_Node">Что такое Express и Node?</h2> + +<p><a href="https://nodejs.org/">Node</a> (или более формально<em> Node.js</em>) <span id="result_box" lang="ru"><span>- кросплатформенная среда исполнения с открытым исходным кодом, которая позволяет разработчикам создавать всевозможные серверные инструменты и приложения используя язык </span></span><a href="/en-US/docs/Glossary/JavaScript">JavaScript</a><span lang="ru"><span>. Среда исполнения предназначена для использования вне контекста браузера </span></span>(т.е. <span id="result_box" lang="ru"><span>выполняется непосредственно на компьютере или на серверной ОС)</span></span>. <span id="result_box" lang="ru"><span>Таким образом, среда исключает API-интерфейсы JavaScript для браузера и добавляет поддержку более традиционных OS API-интерфейсов</span></span><span lang="ru"><span>, включая библиотеки HTTP и файловых систем.</span></span></p> + +<p>С точки зрения веб-серверной разработки Node имеет ряд преимуществ:</p> + +<ul> + <li>Отличная производительность! Node <span id="result_box" lang="ru"><span>был разработан для оптимизации пропускной способности и масштабируемости в веб-приложениях и очень хорошо справляется со многими распространенными проблемами веб-разработки (например, веб-приложения реального времени).</span></span></li> + <li><span id="result_box" lang="ru"><span>Код написан на «обычном старом JavaScript», а это означает, что затрачивается меньше времени при написании кода для браузера и веб-сервера связанное с «переключением технологий» между языками.</span></span></li> + <li><span id="result_box" lang="ru"><span>JavaScript является относительно новым языком программирования и имеет преимущества от улучшения дизайна языка по сравнению с другими традиционными языками для веб-серверов</span></span> (например, Python, PHP, и т.д.). Многие другие новые и популярные языки компилируются/конвертируются в JavaScript, поэтому вы можете также использовать CoffeeScript, ClosureScript, Scala, LiveScript, etc.</li> + <li>Менеджер пакетов Node (NPM) <span id="result_box" lang="ru"><span>обеспечивает доступ к сотням тысяч многоразовых пакетов.</span> <span>Он также имеет лучшее в своем классе разрешение зависимостей и может также использоваться для автоматизации большинства инструментов построения.</span></span></li> + <li>Он портативен, имеет версии для Microsoft Windows, OS X, Linux, Solaris, FreeBSD, OpenBSD, WebOS, и NonStop OS. Кроме того, он имеет хорошую поддержку среди многих хостинг-провайдеров, <span id="result_box" lang="ru"><span>которые часто предоставляют конкретную инфраструктуру и документацию для размещения сайтов, работающих на Node.</span></span></li> + <li><span id="result_box" lang="ru"><span>Он имеет очень активную стороннюю экосистему и сообщество разработчиков, которые всегда готовы помочь.</span></span></li> +</ul> + +<p><span lang="ru"><span>Вы можете изпользовать Node.js для создания простого веб сервера используя пакет Node HTTP. </span></span></p> + +<h3 id="Hello_Node.js">Hello Node.js</h3> + +<p>Следующий пример создаёт веб сервер который прослушивает любой HTTP запрос на <span id="result_box" lang="ru"><span>URL <code>http://127.0.0.1:8000/</code> </span></span>— когда запрос будет получен, скрипт ответит строкой "Hello World". Если Вы уже установили node, можете, следуя шагам инструкции попробовать пример:</p> + +<ol> + <li>Откройте терминал (в Windows окно командной строки)</li> + <li>Создайте папку, куда вы хотите сохранить программу, к примеру <code>test-node</code> и перейдите в нее с помощью следующей команды:</li> +</ol> + +<pre class="notranslate"><code>cd test-node</code></pre> + +<ol start="3"> + <li>Используя любимый текстовый редактор, создайте файл <code>hello.js</code> и вставьте в него код:</li> +</ol> + +<pre class="brush: js notranslate">// Загружаем HTTP модуль +const http = require("http"); + +const hostname = "127.0.0.1"; +const port = 8000; + +// Создаем HTTP-сервер +const server = http.createServer((req, res) => { + + // Устанавливаем HTTP-заголовок ответа с HTTP статусом и Content type + res.writeHead(200, {'Content-Type': 'text/plain'}); + + // Отсылаем тело ответа "Hello World" + res.end('Hello World\n'); +}); + +// Выводим лог как только сервер будет запущен +server.listen(port, hostname, () => { + console.log(`Server running at http://${hostname}:${port}/`); +}) +</pre> + +<ol start="4"> + <li>Сохраните файл в папку, созданную выше.</li> + <li>Вернитесь в терминал и выполните следующую команду:</li> +</ol> + +<pre class="notranslate"><code>node hello.js</code></pre> + +<p>В итоге, перейдите по ссылке <code>http://localhost:8000</code> в вашем браузере; вы должны увидеть текст "<strong>Hello World</strong>" в верху слева на чистой странице.</p> + +<h2 id="Веб_фреймворк">Веб фреймворк</h2> + +<p>Другие общие для веб-программирования задачи не поддерживаются на прямую Node. Если вы хотите добавить специфичную поддержку различных HTTP методов (например <code>GET</code>, <code>POST</code>, <code>DELETE</code>, и т.д.) по разному для разных URL путей ("routes"), отдачу статических файлов, или использовать шаблоны для создания динамических ответов, вам нужно написать код самим, или можете отказаться от изобретения колеса и использовать фреймворк!</p> + +<h2 id="Введение_в_Express">Введение в Express</h2> + +<p><a href="https://expressjs.com/">Express</a> - самый популярный веб-фреймворк для <em>Node</em>. Он является базовой библиотекой для ряда других популярных <a href="https://expressjs.com/en/resources/frameworks.html">веб-фреймворков Node</a>. Он предоставляет следующие механизмы:</p> + +<ul> + <li>Написание обработчиков для запросов с различными HTTP-методами в разных URL-адресах (маршрутах).</li> + <li>Интеграцию с механизмами рендеринга «view», для генерации ответов, вставляя данные в шаблоны.</li> + <li>Установка общих параметров веб-приложения, такие как порт для подключения, и расположение шаблонов, которые используются для отображения ответа.</li> + <li>«промежуточное ПО» для дополнительной обработки запроса в любой момент в конвейере обработки запросов.</li> +</ul> + +<p>В то время как сам express довольно минималистичный, разработчики создали совместимые пакеты промежуточного программного обеспечения для решения практически любой проблемы с веб-разработкой. Существуют библиотеки для работы с куки-файлами, сеансами, входами пользователей, параметрами URL, данными POST, заголовками безопасности и многими другими. Вы можете найти список пакетов промежуточного программного обеспечения, поддерживаемых командой Express в <a href="http://expressjs.com/en/resources/middleware.html">Express Middleware</a> (наряду со списком некоторых популярных пакетов сторонних производителей) .</p> + +<div class="note"> +<p><strong>Примечание:</strong> Гибкость это палка о двух концах. <span id="result_box" lang="ru"><span>Существуют пакеты промежуточного программного обеспечения (middleware) для решения практически любых проблем или для удовлетворения любых ваших требований, но правильный выбор подходящих пакетов иногда может быть проблемой.</span> <span>Также нет «правильного пути» для структурирования приложения, и многие примеры, которые вы можете найти в Интернете, не являются оптимальными или лишь показывают небольшую часть того, что вам нужно сделать для разработки веб-приложения.</span></span></p> +</div> + +<h2 id="Откуда_это_все_взялось">Откуда это все взялось?</h2> + +<p>Node первоначально был выпущен только под Linux в 2009. Менеджер пакетов NPM был выпущен в 2010, а поддержка Windows была добавлена в 2012. Текущая LTS-версия Node v12.16.1 , в то время как последний выпуск Node версии 13.11.0. Это короткий экскурс в историю; обратитесь к <a href="https://en.wikipedia.org/wiki/Node.js#History">Википедии</a>, если вы хотите узнать больше).</p> + +<p>Express первоначально был выпущен в ноябре 2010 и текущая версия API 4.17.1 Вы можете отследить <a href="https://expressjs.com/en/changelog/4x.html">изменения</a> и текущий релиз, и <a href="https://github.com/expressjs/express/blob/master/History.md">GitHub</a> для более детальной информации о релизах.</p> + +<h2 id="Насколько_популярен_NodeExpress">Насколько популярен Node/Express?</h2> + +<p>Популярность веб-фрэймворка важна, поскольку она является индикатором того, будет ли она продолжаться, и какие ресурсы, вероятно, будут доступны с точки зрения документации, дополнительных библиотек и технической поддержки.</p> + +<p>Не существует какого-либо доступного и точного измерения популярности серверных фреймворков (хотя сайты, такие как Hot Frameworks, пытаются оценить популярность, используя такие механизмы, как подсчет количества проектов на GitHub и вопросов на StackOverflow для каждой платформы). Лучший вопрос заключается в том, достаточно ли популярны Node и Express, чтобы избежать проблем с непопулярными платформами. Они продолжают развиваться? Можете ли вы получить помощь, если вам это нужно? Есть ли у вас возможность получить оплачиваемую работу, если вы изучаете Express?</p> + +<p>Как только мы посмотрим на список <a href="https://expressjs.com/en/resources/companies-using-express.html">широкоизвестных компаний</a> пользующихся Express, количество разработчиков участвующих в разработке Express, и громадному числу людей, которые занимаются поддержкой Express, то мы с уверенностью скажем - <em>Express</em> поистине популярный фреймворк!</p> + +<h2 id="Является_ли_Express_ограничивающим">Является ли Express ограничивающим?</h2> + +<p>Web-фрэймворки часто принято делить на "ограничивающие" и "неограничивающие".</p> + +<p>Ограничивающими фрэймворки считаются фрэймворки, которые следуют "должным" ограничениям при выполнении отдельных задач. Довольно часто они ориентированы на ускоренную разработку <em>в конкретной области</em> (решение задач определенного типа), поскольку должный подход к произвольно выбранной задаче бывает не прост для понимания и плохо документирован. При этом они лишаются гибкости при решении задач выходящих за сферу их обычного применения, а так же проявляют тенденцию к ограничению выбора компонентов и подходов своего применения. </p> + +<p>Напротив, неограничивающие фреймворки имеют гораздо меньше ограничений для связи компонентов, что бы достичь цели или ограничений в выборе используемых компонентов. Они облегчают разработчикам использование наиболее подходящих инструментов для выполнения конкретной задачи, но платой за это будет то, что вы самостоятельно должны найти такие компоненты.</p> + +<p>Express не ограничивающий. Вы можете вставить в цепочку обработки (middleware) запросов практически любое совместимые промежуточные компоненты, которые вам нравятся. Вы можете структурировать приложение в одном файле или в нескольких, использую любую структуру каталогов. Иногда вы можете чувствовать, что у вас слишком много вариантов!</p> + +<h2 id="Как_выглядит_код_Express">Как выглядит код Express?</h2> + +<p>В традиционных динамических веб-сайтах, веб-приложение ожидает HTTP-запроса от веб-браузера (или другого клиента). Когда запрос получен, приложение определяет, какое действие необходимо выполнить на основе URL шаблна и, возможно, связанной информации, содержащейся в данных <code>POST</code> или <code>GET</code>. В зависимости от того, что требуется, Express может затем читать или записывать данные из/в базы данных или выполнять другие задачи, в соответствии с полученным запросом. Затем приложение возвращает ответ в веб-браузер, зачастую динамически создавая HTML страницу для отображения браузером, вставляя извлеченные данные в заполнители HTML шаблона.</p> + +<p>Express предоставляет методы позволяющие указать, какая функция вызывается для конкретного HTTP запроса (<code>GET</code>, <code>POST</code>, <code>SET</code>, etc.), и URL шаблон ("Route"), а также методы позволяющие указать, какой механизм шаблона ("view") используется, где находятся шаблоныы файлов и какой шаблон использовать для вывода ответа. Вы можете использовать Express middleware для добавления поддержки файлов cookies, сеансов, и пользователей, получения <code>POST</code>/<code>GET</code> параметров, и т.д. Вы можете использовать любой механизм базы данных, поддерживаемый Node (Express не определяет поведение, связанное с базой данных).</p> + +<p>В следующих разделах объясняются некоторые общие моменты, которые вы увидите при работе с кодом <em>Express</em> and <em>Node</em>.</p> + +<h3 id="Helloworld_Express">Helloworld Express</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Сначала давайте рассмотрим стандартный пример Express Hello World (мы обсудим каждую часть этого ниже и в следующих разделах).</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Совет: Если у вас уже установлены Node и Express (или если вы устанавливаете их, как показано в следующей статье), вы можете сохранить этот код в файле с именем app.js и запустить его в командной строке, вызвав узел app.js.</span> <span title="">отражения</span><span title="">)</span><span title="">.</span></span></p> +</div> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); + +<strong>app.get('/', function(req, res) { + res.send('Hello World!'); +});</strong> + +app.listen(3000, function() { + console.log('Example app listening on port 3000!'); +}); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Первые две строки требуют () (импорт) модуля Express и создания приложения Express.</span> <span title="">Этот объект, который традиционно называется app, имеет методы для маршрутизации HTTP-запросов, настройки промежуточного программного обеспечения, рендеринга представлений HTML, регистрации механизма шаблонов и изменения параметров приложения, которые управляют поведением приложения (например, режим среды, чувствительны ли определения маршрута к регистру).</span> <span title="">, и т.д.)</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Средняя часть кода (три строки, начинающиеся с app.get) показывает определение маршрута.</span> <span title="">Метод app.get () указывает функцию обратного вызова, которая будет вызываться всякий раз, когда есть HTTP-запрос GET с путем ('/') относительно корня сайта.</span> <span title="">Функция обратного вызова принимает запрос и объект ответа в качестве аргументов и просто вызывает send () для ответа, чтобы вернуть строку «Hello World!»</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Последний блок запускает сервер через порт «3000» и печатает комментарий журнала в консоль.</span> <span title="">Когда сервер работает, вы можете перейти к localhost: 3000 в вашем браузере, чтобы увидеть возвращенный пример ответа.</span></span></p> + +<h3 id="Импорт_и_создание_модулей"><span class="tlid-translation translation" lang="ru"><span title="">Импорт и создание модулей</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Модуль - это библиотека / файл JavaScript, который вы можете импортировать в другой код с помощью функции require () Node.</span> <span title="">Express сам по себе является модулем, как и промежуточное программное обеспечение и библиотеки баз данных, которые мы используем в наших приложениях Express.</span><br> + <br> + <span title="">Приведенный ниже код показывает, как мы импортируем модуль по имени, используя в качестве примера платформу Express.</span> <span title="">Сначала мы вызываем функцию require (), определяя имя модуля в виде строки («express») и вызывая возвращенный объект для создания приложения Express.</span> <span title="">Затем мы можем получить доступ к свойствам и функциям объекта приложения.</span></span></p> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы также можете создавать свои собственные модули, которые можно импортировать таким же образом.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Совет: вы захотите создать свои собственные модули, потому что это позволяет вам организовать ваш код в управляемые части - монолитное однофайловое приложение трудно понять и поддерживать.</span> <span title="">Использование модулей также помогает вам управлять пространством имен, поскольку при использовании модуля импортируются только те переменные, которые вы явно экспортировали.</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Чтобы сделать объекты доступными вне модуля, вам просто нужно назначить их объекту экспорта.</span> <span title="">Например, модуль square.js ниже представляет собой файл, который экспортирует методы area () и perimeter ():</span></span></p> + +<pre class="brush: js notranslate">exports.area = function(width) { return width * width; }; +exports.perimeter = function(width) { return 4 * width; }; +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Мы можем импортировать этот модуль, используя require (), а затем вызвать экспортированные методы, как показано:</span></span></p> + +<pre class="brush: js notranslate">var square = require('./square'); // Here we require() the name of the file without the (optional) .js file extension +console.log('The area of a square with a width of 4 is ' + square.area(4));</pre> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание. Вы также можете указать абсолютный путь к модулю (или имя, как мы делали изначально).</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Если вы хотите экспортировать полный объект в одном назначении, а не создавать его по одному свойству за раз, назначьте его для module.exports, как показано ниже (вы также можете сделать это, чтобы сделать корень объекта экспорта конструктором или другой функцией)</span> <span title="">:</span></span></p> + +<pre class="brush: js notranslate">module.exports = { + area: function(width) { + return width * width; + }, + + perimeter: function(width) { + return 4 * width; + } +}; +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Для получения дополнительной информации о модулях см.</span></span> <a href="https://nodejs.org/api/modules.html#modules_modules">Modules</a> (Node API docs).</p> + +<h3 id="Использование_асинхронных_API"><span class="tlid-translation translation" lang="ru"><span title="">Использование асинхронных API</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Код JavaScript часто использует асинхронные, а не синхронные API для операций, выполнение которых может занять некоторое время.</span> <span title="">Синхронный API - это тот, в котором каждая операция должна завершиться до начала следующей операции.</span> <span title="">Например, следующие функции журнала являются синхронными и выводят текст на консоль по порядку (первый, второй).</span></span></p> + +<pre class="brush: js notranslate">console.log('First'); +console.log('Second'); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В отличие от этого, асинхронный API - это тот, в котором API начнет операцию и сразу же вернется (до завершения операции).</span> <span title="">После завершения операции API будет использовать некоторый механизм для выполнения дополнительных операций.</span> <span title="">Например, приведенный ниже код выведет «Second, First», потому что хотя метод setTimeout () вызывается первым и возвращается немедленно, операция не завершается в течение нескольких секунд.</span></span></p> + +<pre class="brush: js notranslate">setTimeout(function() { + console.log('First'); + }, 3000); +console.log('Second'); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Использование неблокирующих асинхронных API-интерфейсов еще более важно в Node, чем в браузере, поскольку Node - это однопоточная среда выполнения, управляемая событиями.</span> <span title="">«Однопоточный» означает, что все запросы к серверу выполняются в одном потоке (а не порождаются в отдельных процессах).</span> <span title="">Эта модель чрезвычайно эффективна с точки зрения скорости и ресурсов сервера, но это означает, что если любая из ваших функций вызывает синхронные методы, выполнение которых занимает много времени, они будут блокировать не только текущий запрос, но и любой другой запрос, обрабатываемый</span> <span title="">ваше веб-приложение.</span><br> + <br> + <span title="">Есть несколько способов, которыми асинхронный API уведомляет ваше приложение о том, что оно завершено.</span> <span title="">Наиболее распространенный способ - зарегистрировать функцию обратного вызова при вызове асинхронного API, который будет вызываться после завершения операции.</span> <span title="">Это подход, использованный выше.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Совет: Использование обратных вызовов может быть довольно «грязным», если у вас есть последовательность зависимых асинхронных операций, которые должны выполняться по порядку, потому что это приводит к нескольким уровням вложенных обратных вызовов.</span> <span title="">Эта проблема широко известна как «ад обратного вызова».</span> <span title="">Эту проблему можно решить с помощью хороших методов кодирования (см. Http://callbackhell.com/), использования такого модуля, как async, или даже перехода к функциям ES6, таким как Promises.</span></span></p> +</div> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание. Общим соглашением для Node и Express является использование обратных вызовов с ошибками.</span> <span title="">В этом соглашении первое значение в ваших функциях обратного вызова является значением ошибки, в то время как последующие аргументы содержат данные об успехе.</span> <span title="">В этом блоге есть хорошее объяснение того, почему этот подход полезен: путь Node.js - понимание обратных вызовов с ошибками (fredkschott.com).</span></span></p> +</div> + +<h3 id="Создание_обработчиков_маршрута"><span class="tlid-translation translation" lang="ru"><span title="">Создание обработчиков маршрута</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В нашем примере Hello World Express (см. Выше) мы определили функцию обработчика маршрута (обратного вызова) для HTTP-запросов GET к корню сайта ('/').</span></span></p> + +<pre class="brush: js notranslate">app.<strong>get</strong>('/', function(req, res) { + res.send('Hello World!'); +}); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Функция обратного вызова принимает запрос и объект ответа в качестве аргументов.</span> <span title="">В этом случае метод просто вызывает send () в ответе, чтобы вернуть строку «Hello World!»</span> <span title="">Существует ряд других методов ответа для завершения цикла запрос / ответ, например, вы можете вызвать res.json () для отправки ответа JSON или res.sendFile () для отправки файла.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Совет по JavaScript: вы можете использовать любые имена аргументов, которые вам нравятся, в функциях обратного вызова;</span> <span title="">при вызове обратного вызова первый аргумент всегда будет запросом, а второй всегда будет ответом.</span> <span title="">Имеет смысл назвать их так, чтобы вы могли идентифицировать объект, с которым работаете, в теле обратного вызова.</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Объект приложения Express также предоставляет методы для определения обработчиков маршрутов для всех других HTTP-глаголов, которые в основном используются одинаково: post (), put (), delete (), options (), trace (), copy (</span> <span title="">), lock (), mkcol (), move (), purge (), propfind (), proppatch (), unlock (), report (), mkactivity (), checkout (), merge (</span> <span title="">), m-search (), notify (), subscribe (), unsubscribe (), patch (), search () и connect ().</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Существует специальный метод маршрутизации app.all (), который будет вызываться в ответ на любой метод HTTP.</span> <span title="">Это используется для загрузки функций промежуточного программного обеспечения по определенному пути для всех методов запроса.</span> <span title="">В следующем примере (из документации Express) показан обработчик, который будет выполняться для запросов к / secret независимо от используемого глагола HTTP (при условии, что он поддерживается модулем http).</span></span></p> + +<pre class="brush: js notranslate">app.all('/secret', function(req, res, next) { + console.log('Accessing the secret section ...'); + next(); // pass control to the next handler +});</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Маршруты позволяют сопоставлять определенные шаблоны символов в URL-адресе, извлекать некоторые значения из URL-адреса и передавать их в качестве параметров обработчику маршрута (в качестве атрибутов объекта запроса, передаваемого в качестве параметра).</span><br> + <br> + <span title="">Часто полезно группировать обработчики маршрутов для определенной части сайта и получать к ним доступ с помощью общего префикса маршрута (например, сайт с вики может иметь все связанные с вики маршруты в одном файле и иметь к ним доступ с префиксом маршрута</span> <span title="">из / вики /).</span> <span title="">В Express это достигается с помощью объекта express.Router.</span> <span title="">Например, мы можем создать наш вики-маршрут в модуле с именем wiki.js, а затем экспортировать объект Router, как показано ниже:</span></span></p> + +<pre class="brush: js notranslate">// wiki.js - Wiki route module + +var express = require('express'); +var router = express.Router(); + +// Home page route +router.get('/', function(req, res) { + res.send('Wiki home page'); +}); + +// About page route +router.get('/about', function(req, res) { + res.send('About this wiki'); +}); + +module.exports = router; +</pre> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание. Добавление маршрутов к объекту Router аналогично добавлению маршрутов к объекту приложения (как показано ранее).</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Чтобы использовать маршрутизатор в нашем главном файле приложения, нам потребуется () модуль route (wiki.js), а затем вызовите use () в приложении Express, чтобы добавить маршрутизатор в путь обработки промежуточного программного обеспечения.</span> <span title="">Эти два маршрута будут доступны из / wiki / и / wiki / about /.</span></span></p> + +<pre class="brush: js notranslate">var wiki = require('./wiki.js'); +// ... +app.use('/wiki', wiki);</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Мы покажем вам намного больше о работе с маршрутами, и в частности об использовании маршрутизатора, позже в связанном разделе</span></span> <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes"> Routes and controllers .</a></p> + +<h3 id="Использование_промежуточного_программного_обеспечения"><span class="tlid-translation translation" lang="ru"><span title="">Использование промежуточного программного обеспечения</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Промежуточное программное обеспечение широко используется в приложениях Express для задач от обслуживания статических файлов до обработки ошибок и сжатия HTTP-ответов.</span> <span title="">Принимая во внимание, что функции маршрута заканчивают цикл запроса-ответа HTTP, возвращая некоторый ответ клиенту HTTP, функции промежуточного программного обеспечения обычно выполняют некоторую операцию над запросом или ответом и затем вызывают следующую функцию в «стеке», которая может быть большим количеством промежуточного программного обеспечения или маршрута</span> <span title="">обработчик</span><span title="">.</span> <span title="">Порядок вызова промежуточного программного обеспечения зависит от разработчика приложения.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание. Промежуточное программное обеспечение может выполнять любую операцию, выполнять любой код, вносить изменения в объект запроса и ответа, а также может завершать цикл запрос-ответ.</span> <span title="">Если он не завершает цикл, он должен вызвать next (), чтобы передать управление следующей функции промежуточного программного обеспечения (или запрос останется зависшим).</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Большинство приложений используют стороннее промежуточное программное обеспечение для упрощения общих задач веб-разработки, таких как работа с файлами cookie, сессиями, аутентификацией пользователя, доступом к данным запросов POST и JSON, ведение журнала и т. д. Список пакетов промежуточного программного обеспечения, поддерживаемых командой Express, можно найти.</span> <span title="">(который также включает в себя другие популярные сторонние пакеты).</span> <span title="">Другие экспресс-пакеты доступны в диспетчере пакетов NPM.</span><br> + <br> + <span title="">Для использования стороннего промежуточного программного обеспечения сначала необходимо установить его в свое приложение с помощью NPM.</span> <span title="">Например, чтобы установить промежуточное программное обеспечение средства регистрации HTTP-запросов morgan, вы должны сделать следующее:</span></span></p> + +<pre class="brush: bash notranslate"><code>$ npm install morgan +</code></pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Затем вы можете вызвать use () для объекта приложения Express, чтобы добавить промежуточное программное обеспечение в стек:</span></span></p> + +<pre class="brush: js notranslate">var express = require('express'); +<strong>var logger = require('morgan');</strong> +var app = express(); +<strong>app.use(logger('dev'));</strong> +...</pre> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание. Промежуточное программное обеспечение и функции маршрутизации вызываются в том порядке, в котором они были объявлены.</span> <span title="">Для некоторого промежуточного программного обеспечения важен порядок (например, если промежуточное программное обеспечение сеанса зависит от промежуточного программного обеспечения cookie, то сначала должен быть добавлен обработчик cookie).</span> <span title="">Почти всегда случается так, что промежуточное ПО вызывается перед настройкой маршрутов, иначе ваши обработчики маршрутов не будут иметь доступа к функциям, добавленным вашим промежуточным ПО.</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете написать свои собственные функции промежуточного программного обеспечения, и вам, вероятно, придется это сделать (хотя бы для создания кода обработки ошибок).</span> <span title="">Единственное различие между функцией промежуточного программного обеспечения и обратным вызовом обработчика маршрута состоит в том, что функции промежуточного программного обеспечения имеют третий аргумент, следующий: какие функции промежуточного программного обеспечения должны вызываться, если они не завершают цикл запроса (когда вызывается функция промежуточного программного обеспечения, она содержит следующую функцию).</span> <span title="">это надо называть).</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете добавить функцию промежуточного программного обеспечения в цепочку обработки с помощью app.use () или app.add (), в зависимости от того, хотите ли вы применить промежуточное программное обеспечение ко всем ответам или к ответам с определенным глаголом HTTP (GET, POST и т. д.).</span> <span title="">)</span><span title="">.</span> <span title="">Маршруты задаются одинаково в обоих случаях, хотя маршрут необязателен при вызове app.use ().</span><br> + <br> + <span title="">В приведенном ниже примере показано, как можно добавить функцию промежуточного программного обеспечения, используя оба метода, а также с / без маршрута.</span></span></p> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); + +// An example middleware function +var a_middleware_function = function(req, res, <em>next</em>) { + // ... perform some operations + next(); // Call next() so Express will call the next middleware function in the chain. +} + +// Function added with use() for all routes and verbs +app.use(a_middleware_function); + +// Function added with use() for a specific route +app.use('/someroute', a_middleware_function); + +// A middleware function added for a specific HTTP verb and route +app.get('/', a_middleware_function); + +app.listen(3000);</pre> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Совет по JavaScript: выше мы объявляем функцию промежуточного программного обеспечения отдельно, а затем устанавливаем ее в качестве обратного вызова.</span> <span title="">В нашей предыдущей функции обработчика маршрута мы объявили функцию обратного вызова, когда она использовалась.</span> <span title="">В JavaScript любой подход является допустимым.</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Документация по Express содержит намного больше отличной информации по использованию и написанию промежуточного программного обеспечения Express.</span></span></p> + +<h3 id="Обслуживание_статических_файлов"><span class="tlid-translation translation" lang="ru"><span title="">Обслуживание статических файлов</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете использовать промежуточное программное обеспечение express.static для обслуживания статических файлов, включая ваши изображения, CSS и JavaScript (static () - единственная функция промежуточного программного обеспечения, которая фактически является частью Express).</span> <span title="">Например, вы должны использовать строку ниже для обслуживания изображений, файлов CSS и файлов JavaScript из каталога с именем public на том же уровне, где вы вызываете узел:</span></span></p> + +<pre class="brush: js notranslate">app.use(express.static('public')); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Любые файлы в публичном каталоге обслуживаются путем добавления их имени файла (относительно базового «публичного» каталога) к базовому URL.</span> <span title="">Так, например:</span></span></p> + +<pre class="notranslate"><code>http://localhost:3000/images/dog.jpg +http://localhost:3000/css/style.css +http://localhost:3000/js/app.js +http://localhost:3000/about.html +</code></pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы можете вызывать static () несколько раз для обслуживания нескольких каталогов.</span> <span title="">Если файл не может быть найден одной функцией промежуточного программного обеспечения, он будет просто передан последующему промежуточному программному обеспечению (порядок вызова промежуточного программного обеспечения основан на вашем порядке объявления).</span></span></p> + +<pre class="brush: js notranslate">app.use(express.static('public')); +app.use(express.static('media')); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вы также можете создать виртуальный префикс для ваших статических URL-адресов, вместо добавления файлов к базовому URL-адресу.</span> <span title="">Например, здесь мы указываем путь монтирования, чтобы файлы загружались с префиксом "/ media":</span></span></p> + +<pre class="brush: js notranslate">app.use('/media', express.static('public')); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Теперь вы можете загружать файлы, находящиеся в публичном каталоге, из префикса / media path.</span></span></p> + +<pre class="notranslate"><code>http://localhost:3000/media/images/dog.jpg +http://localhost:3000/media/video/cat.mp4 +http://localhost:3000/media/cry.mp3</code> +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Для получения дополнительной информации см.</span></span> <a href="Serving static files in Express">Serving static files in Express</a>.</p> + +<h3 id="Обработка_ошибок"><span class="tlid-translation translation" lang="ru"><span title="">Обработка ошибок</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Ошибки обрабатываются одной или несколькими специальными функциями промежуточного программного обеспечения, которые имеют четыре аргумента вместо обычных трех: (err, req, res, next).</span> <span title="">Например:</span></span></p> + +<pre class="brush: js notranslate">app.use(function(err, req, res, next) { + console.error(err.stack); + res.status(500).send('Something broke!'); +}); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Они могут возвращать любой требуемый контент, но должны вызываться после всех других app.use () и маршрутизировать вызовы, чтобы они были последним промежуточным ПО в процессе обработки запросов!</span><br> + <br> + <span title="">Express поставляется со встроенным обработчиком ошибок, который заботится обо всех оставшихся ошибках, которые могут возникнуть в приложении.</span> <span title="">Эта промежуточная функция обработки ошибок по умолчанию добавляется в конец стека функций промежуточного программного обеспечения.</span> <span title="">Если вы передаете ошибку в next () и не обрабатываете ее в обработчике ошибок, она будет обработана встроенным обработчиком ошибок;</span> <span title="">ошибка будет записана клиенту с трассировкой стека.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание. Трассировка стека не включена в производственную среду.</span> <span title="">Чтобы запустить его в производственном режиме, необходимо установить переменную среды NODE_ENV в «производство».</span></span></p> +</div> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание. HTTP404 и другие коды состояния «ошибка» не считаются ошибками.</span> <span title="">Если вы хотите справиться с этим, вы можете добавить функцию промежуточного программного обеспечения для этого.</span> <span title="">Для получения дополнительной информации см. FAQ.</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Для получения дополнительной информации см.</span></span> <a href="http://expressjs.com/en/guide/error-handling.html">Error handling</a> (Express docs).</p> + +<h3 id="Использование_баз_данных"><span class="tlid-translation translation" lang="ru"><span title="">Использование баз данных</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Приложения Express могут использовать любой механизм базы данных, поддерживаемый Node (сам по себе Express не определяет каких-либо дополнительных действий / требований для управления базой данных).</span> <span title="">Есть много вариантов, включая PostgreSQL, MySQL, Redis, SQLite, MongoDB и т. Д.</span><br> + <br> + <span title="">Чтобы использовать их, вы должны сначала установить драйвер базы данных, используя NPM.</span> <span title="">Например, чтобы установить драйвер для популярной NoSQL MongoDB, вы должны использовать команду:</span></span></p> + +<pre class="brush: bash notranslate"><code>$ npm install mongodb +</code></pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Сама база данных может быть установлена локально или на облачном сервере.</span> <span title="">В вашем экспресс-коде вам требуется драйвер, подключиться к базе данных, а затем выполнить операции создания, чтения, обновления и удаления (CRUD).</span> <span title="">Пример ниже (из документации Express) показывает, как вы можете найти записи «млекопитающих», используя MongoDB.</span></span></p> + +<pre class="brush: js notranslate">var MongoClient = require('mongodb').MongoClient; + +MongoClient.connect('mongodb://localhost:27017/animals', function(err, db) { + if (err) throw err; + + db.collection('mammals').find().toArray(function (err, result) { + if (err) throw err; + + console.log(result); + }); +});</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Другим популярным подходом является косвенный доступ к вашей базе данных с помощью Object Relational Mapper («ORM»).</span> <span title="">При таком подходе вы определяете свои данные как «объекты» или «модели», и ORM отображает их в базовый формат базы данных.</span> <span title="">Этот подход имеет то преимущество, что как разработчик вы можете продолжать думать с точки зрения объектов JavaScript, а не семантики базы данных, и что есть очевидное место для выполнения проверки и проверки входящих данных.</span> <span title="">Подробнее о базах данных мы поговорим в следующей статье.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Для получения дополнительной информации см.</span></span> <a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs).</p> + +<h3 id="Рендеринг_данных_просмотров"><span class="tlid-translation translation" lang="ru"><span title="">Рендеринг данных (просмотров)</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Механизмы шаблонов (в Express называемые «механизмами просмотра») позволяют указывать структуру выходного документа в шаблоне, используя заполнители для данных, которые будут заполняться при создании страницы.</span> <span title="">Шаблоны часто используются для создания HTML, но могут также создавать другие типы документов.</span> <span title="">В Express есть поддержка ряда шаблонных движков, и здесь есть полезное сравнение более популярных движков: Сравнение шаблонизаторов JavaScript: Jade, Mustache, Dust и More.</span><br> + <br> + <span title="">В своем коде настроек приложения вы задаете механизм шаблонов для использования и место, где Express должен искать шаблоны, используя настройки «views» и «engine», как показано ниже (вам также нужно будет установить пакет, содержащий вашу библиотеку шаблонов).</span> <span title="">!</span><span title="">)</span></span></p> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); + +// Set directory to contain the templates ('views') +app.set('views', path.join(__dirname, 'views')); + +// Set view engine to use, in this case 'some_template_engine_name' +app.set('view engine', 'some_template_engine_name'); +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Внешний вид шаблона будет зависеть от того, какой движок вы используете.</span> <span title="">Предполагая, что у вас есть файл шаблона с именем «index. <Template_extension>», который содержит заполнители для переменных данных с именами «title» и «message», вы должны вызвать Response.render () в функции обработчика маршрута для создания и отправки ответа HTML.</span> <span title="">:</span></span></p> + +<pre class="brush: js notranslate">app.get('/', function(req, res) { + res.render('index', { title: 'About dogs', message: 'Dogs rock!' }); +});</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Для получения дополнительной информации см.</span></span> <a href="http://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs).</p> + +<h3 id="Файловая_структура"><span class="tlid-translation translation" lang="ru"><span title="">Файловая структура</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Express не делает никаких предположений относительно структуры или компонентов, которые вы используете.</span> <span title="">Маршруты, представления, статические файлы и другая логика конкретного приложения могут находиться в любом количестве файлов с любой структурой каталогов.</span> <span title="">Хотя вполне возможно иметь все приложения Express в одном файле, обычно имеет смысл разделить ваше приложение на файлы на основе функций (например, управление учетными записями, блоги, доски обсуждений) и проблемной области архитектуры (например, модель, представление или контроллер, если</span> <span title="">вы случайно используете</span></span> <a href="/en-US/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">MVC architecture</a>).</p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">В более поздней теме мы будем использовать Express Application Generator, который создает модульный каркас приложения, который мы можем легко расширить для создания веб-приложений.</span></span></p> + +<ul> +</ul> + +<h2 id="Резюме">Резюме</h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Поздравляем, вы завершили первый шаг в своем путешествии Express / Node!</span> <span title="">Теперь вы должны понимать основные преимущества Express и Node, а также примерно то, как могут выглядеть основные части приложения Express (маршруты, промежуточное ПО, обработка ошибок и код шаблона).</span> <span title="">Вы также должны понимать, что с Express, который является непонятным фреймворком, то, как вы собираете эти части вместе, и библиотеки, которые вы используете, в значительной степени зависит от вас!</span><br> + <br> + <span title="">Конечно, Express - это очень легкая платформа для веб-приложений, поэтому большая часть ее преимуществ и возможностей обеспечивается сторонними библиотеками и функциями.</span> <span title="">Мы рассмотрим это более подробно в следующих статьях.</span> <span title="">В нашей следующей статье мы рассмотрим настройку среды разработки Node, чтобы вы могли увидеть некоторый код Express в действии.</span></span></p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://nodejs.org/api/modules.html#modules_modules">Modules</a> (Node API docs)</li> + <li><a href="https://expressjs.com/">Express</a> (home page)</li> + <li><a href="http://expressjs.com/en/starter/basic-routing.html">Basic routing</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/routing.html">Routing guide</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs)</li> + <li><a href="https://expressjs.com/en/guide/using-middleware.html">Using middleware</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/writing-middleware.html">Writing middleware for use in Express apps</a> (Express docs)</li> + <li><a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs)</li> + <li><a href="Serving static files in Express">Serving static files in Express</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/error-handling.html">Error handling</a> (Express docs)</li> +</ul> + +<div>{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}</div> + +<div id="gtx-anchor" style="position: absolute; left: 20px; top: 6224px; width: 616.578px; height: 17px;"></div> + +<div class="jfk-bubble gtx-bubble"> +<div class="jfk-bubble-content-id" id="bubble-22"> +<div id="gtx-host" style="max-width: 400px;"></div> +</div> + +<div class="jfk-bubble-closebtn-id jfk-bubble-closebtn"></div> + +<div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowup" style="left: 288.5px;"> +<div class="jfk-bubble-arrowimplbefore"></div> + +<div class="jfk-bubble-arrowimplafter"></div> +</div> +</div> diff --git a/files/ru/learn/server-side/express_nodejs/mongoose/index.html b/files/ru/learn/server-side/express_nodejs/mongoose/index.html new file mode 100644 index 0000000000..18cdb9922a --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/mongoose/index.html @@ -0,0 +1,800 @@ +--- +title: 'Учебник Express часть 3: Использование базы данных (с помощью Mongoose)' +slug: Learn/Server-side/Express_Nodejs/mongoose +translation_of: Learn/Server-side/Express_Nodejs/mongoose +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">В этой статье дается краткое введение в базы данных, и методика их использования в приложнениях Node/Express. Затем мы покажем, как можно использовать <a href="http://mongoosejs.com/">Mongoose</a> для доступа к базе данных веб-сайта <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a>. Мы объясним, как объявляются схемы и модели объектов, укажем основные типы полей, и методику базовой валидации. В статье также кратко показаны основные методы доступа к данным модели.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительные сведения:</th> + <td><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Уметь спроектировать и создать свои модели, используя Mongoose.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>Сотрудники библиотеки будут использовать сайт Local Library для хранения информации о книгах и абонентах, а абоненты библиотеки будут использовать его для просмотра и поиска книг, для получения информации о доступных копиях, для резервирования или одалживния книг. Чтобы эффективно хранить и извлекать информацию, мы будем хранить ее в базе данных.</p> + +<p>Express-приложения могут использовать различные базы данных, и есть несколько подходов, которые можно использовать для выполнения операций <strong>C</strong>reate, <strong>R</strong>ead, <strong>U</strong>pdate and <strong>D</strong>elete (CRUD) (создать, прочесть, обновить, удалить). В руководстве дан краткий обзор некоторых доступных опций, и детально рассмотрены некоторые механизмы работы.</p> + +<h3 id="Какие_базы_данных_можно_использовать">Какие базы данных можно использовать?</h3> + +<p><em>Express-</em>приложение может использовать любые базы данных, поддерживаемые <em>Node</em> (сам по себе Express не определяет каких-либо конкретных дополнительных свойств и требований для управления базами данных). Есть <a href="https://expressjs.com/en/guide/database-integration.html">много популярных </a>вариантов -- PostgreSQL, MySQL, Redis, SQLite, и MongoDB.</p> + +<p>При выборе базы данных следует учитывать такие факторы как время разработки, время обучения, простота репликации и копирования, расходы, поддержка сообщества и т. д. Хотя нет единственной "лучшей" базы данных, почти любое из популярных решений будет приемлемым для сайта малого и среднего размера, такого как наша Local Library.</p> + +<p>Более подробно о вариантах смотрите в: <a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs).</p> + +<h3 id="Каков_наилучший_способ_взаимодействия_с_базой_данных">Каков наилучший способ взаимодействия с базой данных?</h3> + +<p>Существует два подхода при работе с базой данных:</p> + +<ul> + <li>Использование родного языка запросов баз данных (т.е. SQL)</li> + <li>Использование объектной модели данных (ODM) или объектно-реляционной модели (ORM). ODM / ORM представлют данные веб-сайта как объекты JavaScript, которые затем отображаются на поддерживающую базу данных. Некоторые ORM привязаны к определенной базе данных, тогда как другие не зависят от конкретной базы данных.</li> +</ul> + +<p>Наилучшую производительность можно получить с помощью SQL или другого языка запросов, поддерживаемого базой данных. Объектные модели (ODM) часто медленнее, потому что требуют перевода объектов в формат базы данных, при этом не обязательно будут использованы наиболее эффективные запросы к базе данных (особенно, если ODM предназначена для различных баз данных и должна идти на большие компромиссы в смысле поддержки тех или иных функций базы данных).</p> + +<p>Преимущество применения ORM состоит в том, что программисты могут сосредоточиться на объектах JavaScript, а не на семантике базы данных — особенно, если требуется работать с разными базами данных (на одном или разных веб-сайтах). Они также дают очевидное место для валидации и проверки данных.</p> + +<div class="note"> +<p>Совет: Применение ODM / ORMs часто приводит к снижению затрат на разработку и обслуживание! Если Вы не очень хорошо знакомы с родным языком запросов или если производительность имеет первостепенное значение, следует серьезно рассмотреть возможность применения ODM.</p> +</div> + +<h3 id="Какую_модель_ORMODM_следует_использовать">Какую модель ORM/ODM следует использовать?</h3> + +<p>Есть много ODM/ORM доступных решений на сайте менеджера пакетов NPM (проверьте теги по подгруппе <a href="https://www.npmjs.com/browse/keyword/odm">odm</a> и <a href="https://www.npmjs.com/browse/keyword/orm">orm</a>).</p> + +<p>Популярные решения на момент написания статьи:</p> + +<ul> + <li><a href="https://www.npmjs.com/package/mongoose">Mongoose</a>: -- это средство моделирование обьектов базы данных <a href="https://www.mongodb.org/">MongoDB</a>, предназначенное для асинхронной работы.</li> + <li><a href="https://www.npmjs.com/package/waterline">Waterline</a>: ORM фреймворка <a href="http://sailsjs.com/">Sails</a> (основан на Express) . Она предоставляет единый API для доступа к множеству баз данных, в том числе Redis, mySQL, LDAP, MongoDB, и Postgres.</li> + <li><a href="https://www.npmjs.com/package/bookshelf">Bookshelf</a>: поддерживает как promise- так и традиционные callback- интерфейсы, поддержка транзакций, eager/nested-eager relation loading, полиморфные ассоциации, и поддержка, один к одному, один ко многим, и многие ко многим. Работает с PostgreSQL, MySQL, и SQLite3.</li> + <li><a href="https://www.npmjs.com/package/objection">Objection</a>: Делает настолько легким, насколько возможно, использование всей мощи SQL и движка базы данных ( поддерживает SQLite3, Postgres, и MySQL).</li> + <li><a href="https://www.npmjs.com/package/sequelize">Sequelize</a>: Основанная на промисах ORM для Node.js и <a href="https://ru.wikipedia.org/wiki/Io.js">io.js</a>. Поддерживает диалекты PostgreSQL, MySQL, MariaDB, SQLite и MSSQL, обладает надежной поддержкой транзакций, отношений, чтения копий и т.д.</li> + <li> + <p><a href="https://node-orm.readthedocs.io/en/latest/"><font color="#3d7e9a"><font face="Arial, x-locale-body, sans-serif"><font size="3">Node ORM2</font></font></font></a><font color="#333333"><font face="Arial, x-locale-body, sans-serif"><font size="3"> -- это OR менеджер для NodeJS. Поддерживает MySQL, SQLite и Progress, помогает работать с БД, используя объектный подход.</font></font></font></p> + </li> + <li> + <p><a href="http://1602.github.io/jugglingdb/"><font color="#3d7e9a"><font face="Arial, x-locale-body, sans-serif"><font size="3">JugglingDB</font></font></font></a><font color="#333333"><font face="Arial, x-locale-body, sans-serif"><font size="3"> -- это кросс-ДБ ORM для NodeJS, обеспечивающая общий интерфейс для доступа к наиболее популярным форматам БД. Поддерживает MySQL, SQLite3, Postgres, MongoDB, Redis и хранение данных в памяти js (собственный движок, только для тестирования).</font></font></font></p> + </li> +</ul> + +<p>Как правило, при выборе решения следует учитывать как предоставляемые функции, так и "деятельность сообщества" ( загрузки, вклад, отчеты об ошибках, качество документации, и т.д. ) . На момент написания статьи Mongoose являлась очень популярной ORM, и разумно, если вы выбрали MongoDB.</p> + +<h3 id="Применение_Mongoose_и_MongoDb_для_LocalLibrary">Применение Mongoose и MongoDb для LocalLibrary</h3> + +<p><span id="result_box" lang="ru"><span class="alt-edited">В примере LocalLibrary (и до конца раздела) мы будем использовать Mongoose ODM для доступа к данным </span></span><span lang="ru"><span class="alt-edited">нашей библиотеки.</span> <span class="alt-edited">Mongoose является интерфейсом для MongoDB, NoSQL-базы данных с открытым исходным кодом, в которой использована документо-ориентированная модель данных.</span> В <span class="alt-edited">MongoDB </span><span class="alt-edited">«коллекции» и «документы» -- это аналоги «таблиц» и «строк» в реляционных БД</span></span>.</p> + +<p><span id="result_box" lang="ru"><span>Это сочетание ODM и БД весьма популярно в сообществе Node, частично потому, что система хранения документов и запросов очень похожа на JSON и поэтому знакома разработчикам JavaScript</span></span>.</p> + +<div class="note"> +<p><span id="result_box" lang="ru"><span><strong>Совет</strong>: Не обязательно знать MongoDB, чтобы использовать Mongoose, хотя <a href="http://mongoosejs.com/docs/guide.html"> документацию Mongoose</a> легче использовать и понимать, если вы уже знакомы с MongoDB.</span></span></p> +</div> + +<p><span id="result_box" lang="ru"><span>Далее показано, как определить и получить доступ к схеме и моделям Mongoose для примера веб-сайта LocalLibrary.</span></span></p> + +<h2 id="Проектирование_моделей_LocalLibrary">Проектирование моделей LocalLibrary</h2> + +<p> </p> + +<p>Прежде чем начинать писать код моделей, стоит обдумать, какие данные нам нужно хранить, и каковы отношения между разными объектами.</p> + +<p>Мы знаем, что нужно хранить информацию о книгах (название, резюме (краткое описание), автор, жанр, ISBN (Международный стандартный книжный номер) ) и что может быть несколько доступных экземпляров (с уникальными идентификаторами, статусом наличия и т. д.). Может потребоваться хранить больше информации об авторе (не только имя, т.к. могут быть авторы с одинаковыми или похожими именами). Мы хотим иметь возможность сортировать данные по названиям книг, по авторам, по жанрам и категориям.</p> + +<p>При проектировании моделей имеет смысл иметь отдельные модели для каждого «объекта» (группы связанных данных). В этом случае очевидными объектами являются книги, экземпляры книг и авторы.</p> + +<p>Можно также использовать модели для представления параметров списка выбора (например, как выпадающий список вариантов), вместо жесткого кодирования выбора на самом веб-сайте - рекомендуется, когда не все параметры известны или могут быть изменены. Явный кандидат для модели такого типа -- это жанр книги (например, «Научная фантастика», «Французская поэзия» и т.д.),</p> + +<p>Как только мы определились с моделями и полями, следует подумать об отношениях между ними.</p> + +<p>С учетом сказанного, UML-диаграмма связей (см. ниже) показывает модели, которые представлены как прямоугольники. Мы решили, что создадим модели для книги (общие сведения о книге), для экземпляра книги (состояние отдельных физических копий книги, доступных в системе) и для автора. Кроме того, у нас будет модель для жанра, чтобы эти значения можно было создавать динамически. Решено не создавать модель для <code>BookInstance:status</code> — мы пропишем в коде необходимые значения, потому что не ожидаем их изменения. На элементах диаграммы показаны имя модели, имена и типы полей, имена методов и типы их результатов .</p> + +<p>Также показаны отношения между моделями, включая множественные отношения. Числа на линиях связи показывают максимум и минимум моделей, участвующих отношении. Например, линия между <code>Book</code> и <code>Genre</code> показывает, что <code>Book</code> и <code>Genre</code> связаны. Числа на этой линии рядом с моделью <code>Book</code> показывают, что жанр может быть связан с любым количеством книг, а числа на другом конце линии рядом с <code>Genre</code> отмечают, что книга может быть связана с любым количеством жанров.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Как показано в примере<a href="#related_documents">Mongoose primer</a> ниже, часто лучше иметь поле, определяющее отношение между документами (моделями), только в одной модели (обратное отношение можно найти по присвоенному идентификатору <code>_id</code> в другой модели). Ниже мы предпочли задать отношения между Book/Genre и между Book/Author в схеме Book, а отношение между Book/BookInstance -- в схеме BookInstance. Этот выбор в некотором смысле был произвольным -- таким же хорошим мог бы быть выбор другого поля в другой схеме.</p> +</div> + +<p><img alt="Mongoose Library Model with correct cardinality" src="https://mdn.mozillademos.org/files/15645/Library%20Website%20-%20Mongoose_Express.png" style="height: 620px; width: 737px;"></p> + +<div class="note"> +<p><strong>Заметка</strong>: В следующем разделе дан базовый пример, в котором объясняется, как задавать и как использовать модели. При чтении обратите внимание, как будут создаваться модели, приведенные на диагарамме.</p> +</div> + +<h2 id="Mongoose_Справочник">Mongoose Справочник</h2> + +<p>В этом разделе кратко описано как подключиться к базе MongoDB с помощью Mongooseе, как определить схемы и модели, как сформировать основные запросы.</p> + +<div class="note"> +<p><strong> Примечание: </strong>На этот пример значительно повлияли документы <a href="https://www.npmjs.com/package/mongoose">Mongoose <font color="#3d7e9a"><font face="x-locale-heading-primary, zillaslab, Palatino, Palatino Linotype, x-locale-heading-secondary, serif"><font size="3">quick start</font></font></font></a> на npm и <a href="http://mongoosejs.com/docs/guide.html">официальная документация.</a></p> +</div> + +<h3 id="Установка_Mongoose_и_MongoDB">Установка Mongoose и MongoDB</h3> + +<p>Mongoose устанавливается в ваш проект (<strong>package.json</strong>) как и другие зависимости - при помощи NPM. Команда установки (выполняется из каталога проекта): </p> + +<pre class="brush: bash"><code>npm install mongoose</code> +</pre> + +<p>Установка <em>Mongoose </em>добавит все зависимости, включая драйвер MongoDB, но не установит саму базу данных. При желании установить сервер MongoDB локально, можно <a href="https://www.mongodb.com/download-center">скачать установочный файл здесь</a> для своей операционной системы и установить его. Также можно использовать облако MongoDB.</p> + +<div class="note"> +<p><strong>Примечание:</strong> В примере для хранения базы данных мы используем облачный сервис <a href="https://mlab.com/plans/pricing/">sandbox tier</a> ("песочницу"). This is suitable for development, and makes sense for the tutorial because it makes "installation" operating system independent (database-as-a-service is also one approach you might well use for your production database).</p> +</div> + +<h3 id="Подключенние_к_MongoDB">Подключенние к MongoDB</h3> + +<p><em>Mongoose </em>требует подключение к MongoDB. Вы можете использовать require() и подключится к локальной БД при помощи <code>mongoose.connect(),</code> как показано ниже.</p> + +<pre class="brush: js">// Импортировать модуль mongoose +var mongoose = require('mongoose'); + +// Установим подключение по умолчанию +var mongoDB = 'mongodb://127.0.0.1/my_database'; +mongoose.connect(mongoDB); +// Позволим Mongoose использовать глобальную библиотеку промисов +mongoose.Promise = global.Promise; +// Получение подключения по умолчанию +var db = mongoose.connection; + +// Привязать подключение к событию ошибки (получать сообщения об ошибках подключения) +db.on('error', console.error.bind(console, 'MongoDB connection error:')); +</pre> + +<p>При помощи <code>mongoose.connection</code> можно получить стандартный объект <code>Connection</code>. После подключения в экземпляре <code>Connection</code> возникает событие open (открыт).</p> + +<div class="note"> +<p><strong>Tip:</strong> Если необходимо создать дополнительные подключения, можно использовать <code>mongoose.createConnection()</code>. При этом будут применены те же БД URI (хост, БД, порт, опции и т.д.), что и в <code>connect()</code> и будет возвращен объект <code>Connection</code>.</p> +</div> + +<h3 id="Определение_и_создание_моделей">Определение и создание моделей</h3> + +<p>Модели можно создать при помощи интерфейса <code>Schema</code> . Schema позволяет указать поля, которые будут в каждом документе, значения полей по умолчанию и требования по валидации. Кроме того, можно задать статические методы и методы-хелперы (от help), облегчающие работу с вашими типами данных, а также задать виртуальные свойства, которые можно использовать как и обычные поля, но без влияния на данные в самой базе данных.</p> + +<p>Схемы "компилируются " в окончательную модель методом <code>mongoose.model()</code>. После создания модели ее можно использовать для поиска, создания, обновления и удаления объектов данного типа.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Каждой модели соответствует <em>коллекция</em> <em>документов</em> в ДБ MongoDB. Документы будут содержать поля тех типов, которые заданы в модели <code>Schema</code>.</p> +</div> + +<h4 id="Определение_схем_данных">Определение схем данных</h4> + +<p>Код ниже показывает, как можно задать простую схему. Сначала при помощи <code>require()</code> создается объект mongoose, затем конструктор Schema создает новый экземпляр схемы, при этом различные поля задаются как параметры конструктора.</p> + +<pre class="brush: js">//Требуется Mongoose +var mongoose = require('mongoose'); + +//Определяем схему +var Schema = mongoose.Schema; + +var SomeModelSchema = new Schema({ + a_string: String, + a_date: Date +}); +</pre> + +<p>В примере созданы два поля, типа String и типа Date. В следующем разделе будут примеры полей других типов, их валидации и примеры других методов.</p> + +<h4 id="Создание_модели">Создание модели</h4> + +<p>Модели создаются из схем методом <code>mongoose.model()</code>:</p> + +<pre class="brush: js">// Определяем схему +var Schema = mongoose.Schema; + +var SomeModelSchema = new Schema({ + a_string: String, + a_date: Date +}); + +<strong>// Компилируем модель из схемы +var SomeModel = mongoose.model('SomeModel', SomeModelSchema );</strong></pre> + +<p>Первый аргумент - уникальное имя создаваемой для модели коллекции(Mongoose создаст коллекцию для модели <em>SomeModel</em>), второй аргумент - схема, которая используется для создания модели.</p> + +<div class="note"> +<p><strong>Заметка:</strong> После создания классов модели они могут применяться для создания, обновления или удаления записей в базе, для выполнения запросов по всем записям или по их подмножествам. Как это делать, будет показано в разделе <a href="#Using_models">Использование моделей</a>, и когда будут создаваться представления.</p> +</div> + +<h4 id="Типы_схемы_(поля)">Типы схемы (поля)</h4> + +<p>Схема может содержать любое количество полей, причем каждое поле будет полем документа, хранимого в БД <em>MongoDB</em>. Схема-пример содержит определения многих широко используемых типов полей.</p> + +<pre class="brush: js">var schema = new Schema( +{ + name: <strong>String</strong>, + binary: <strong>Buffer</strong>, + living: <strong>Boolean</strong>, + updated: { type: <strong>Date</strong>, default: Date.now }, + age: { type: <strong>Number</strong>, min: 18, max: 65, required: true }, + mixed: <strong>Schema.Types.Mixed</strong>, + _someId: <strong>Schema.Types.ObjectId</strong>, + array: <strong>[]</strong>, + ofString: [<strong>String</strong>], // You can also have an array of each of the other types too. + nested: { stuff: { type: <strong>String</strong>, lowercase: true, trim: true } } +})</pre> + +<p>Большинство типов в <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> (указаны после “type:” или после имен полей) достаточно очевидны. Исключения:</p> + +<ul> + <li><code>ObjectId</code>: Представляет отдельный экземпляр модели в БД. Например, book может ссылаться на объект- автора. Поле будет содержать уникальный идентификатор (<code>_id</code>) отдельного объекта. При необходимости использования этой информации применяют метод <code>populate()</code>.</li> + <li><a href="http://mongoosejs.com/docs/schematypes.html#mixed">Mixed</a>: Произвольный тип в схеме.</li> + <li><font face="Consolas, Liberation Mono, Courier, monospace">[]</font>: Массив элементов. В таких моделях можно выполнять JavaScript-операции для массивов (push, pop, unshift, etc.). Выше показан пример массивы объектов неопределенного типа и массив строк, но можно использовать массив объектов любого типа.</li> +</ul> + +<p>Код содержит также два способа объявления полей:</p> + +<ul> + <li><em>Имя</em> и <em>тип</em>поля как пара "ключ-значение" (поля <code>name</code>, <code>binary и</code> <code>living</code>).</li> + <li><em>Имя</em> поля, после которого указывается объект, определяющий <em>тип</em> и другие возможности поля, такие как: + <ul> + <li>значения по умолчанию.</li> + <li>встроенные валидаторы (например, значения max и min) и функции-валидаторы пользователя.</li> + <li>Является ли поле обязательным</li> + <li>Должны ли строковые поля автоматически преобразовываться в нижний или верхний регистр, удалять ли ведущие и хвостовые пробелы (<code>пример:</code> <code>{ type: <strong>String</strong>, lowercase: true, trim: true }</code>)</li> + </ul> + </li> +</ul> + +<p>Дополнительная информация - в <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> (документация Mongoose).</p> + +<h4 id="Валидация_(проверка_допустимости)">Валидация (проверка допустимости)</h4> + +<p>Mongoose предусматривает встроенные валидаторы, валидаторы пользователя, синхронные и асинхронные валидаторы. Во всех случаях можно задать допустимые диапазоны или значения, а также сообщения об ошибках при нарушении условий валидации.</p> + +<p>Встроенные валидаторы включают:</p> + +<ul> + <li>Все <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> имеют встроенный валидатор <a href="http://mongoosejs.com/docs/api.html#schematype_SchemaType-required">required</a>, который определяет, должно ли поле быть заданным перед сохранением документа.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema-number-js">Числа</a> имеют валидаторы <a href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-min">min</a> и <a href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-max">max</a>.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema-string-js">Строки</a> имеют: + <ul> + <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-enum">enum</a> (перечисления): задают множество допустимых для поля значений.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-match">match</a> (соответствия)): задают регулярное выражение, которому должна соответствовать строка.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-maxlength">maxlength</a>, <a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-minlength">minlength</a> -максимальная и минимальная длина строки.</li> + </ul> + </li> +</ul> + +<p>Пример ниже (с небольшими изменениями из документации Mongoose) показывает, как задать некоторые валидаторы и сообщения об ошибках:</p> + +<pre class="brush: js"><code> + var breakfastSchema = new Schema({ + eggs: { + type: Number, + min: [6, 'Too few eggs'], + max: 12 + required: [true, 'Why no eggs?'] + }, + drink: { + type: String, + enum: ['Coffee', 'Tea', 'Water',] + } + }); +</code></pre> + +<p>Подробная информация по валидации полей - в разделе <a href="http://mongoosejs.com/docs/validation.html">Validation</a> (документация Mongoose).</p> + +<h4 id="Виртуальные_свойства">Виртуальные свойства</h4> + +<p>Виртуальные свойства - это свойства документа, которые можно читать (get) и задавать (set), но которые не хранятся в MongoDB. Методы "геттеры" полезны для форматирования и соединения полей, а "сеттеры" применяют для декомпозиции отдельных значений на несколько частей перед сохранением в БД. Пример из документации собирает (и разбирает) виртуальное свойство "полное имя" из полей "имя" и "фамилия", что удобнее, чем конструировать полное имя каждый раз, когда оно используется в шаблоне.</p> + +<div class="note"> +<p><strong>Замечание:</strong> В библиотеке виртуальное свойство будет применено для определения уникального URL каждой записи в модели по пути и по значению <code>_id</code> записи.</p> +</div> + +<p>Подробная информация - в разделе <a href="http://mongoosejs.com/docs/guide.html#virtuals">Virtuals</a> (документация Mongoose).</p> + +<h4 id="Методы_и_помощники_запросов">Методы и помощники запросов</h4> + +<p>В схеме можно также задать методы экземпляра (<a href="http://mongoosejs.com/docs/guide.html#methods">instance methods</a>), статические (<a href="http://mongoosejs.com/docs/guide.html#statics">static</a>) методы и <a href="http://mongoosejs.com/docs/guide.html#query-helpers">помощники запросов</a>. Статические методы и методы экземпляра аналогичны, но различаются тем, что методы экземпляра связаны с конкретной записью и имеют доступ к текущему объекту. Помощники запросов позволяют расширить <a href="http://mongoosejs.com/docs/queries.html"> API построителя цепочек запросов</a> (например, можно добавить запрос "byName" ("по имени") в дополнение к методам <code>find()</code>, <code>findOne()</code> и <code>findById()</code>).</p> + +<h3 id="Применение_моделей">Применение моделей</h3> + +<p>Подготовленную схему можно использовать для создания моделей. Модель представляет коллекцию документов в базе данных, в которой можно выполнять поиск, тогда как экземпляры модели представляют отдельные документы, которые можно сохранять и извлекать.</p> + +<p>Ниже предлагается краткий обзор. Более подробно смотрите в <a href="http://mongoosejs.com/docs/models.html">Models</a> (документация Mongoose).</p> + +<h4 id="Создание_и_изменение_документов">Создание и изменение документов</h4> + +<p>Чтобы создать запись, следует определить экземпляр модели и вызвать метод <code>save()</code>. В примере ниже SomeModel -- это модель с единственным полем "name", которую мы создадим из нашей схемы.</p> + +<pre class="brush: js"><code>// Создать экземпляр модели SomeModel +var awesome_instance = new </code>SomeModel<code>({ name: 'awesome' }); + +// Сохранить новый экземпляр, передав callback +awesome_instance.save(function (err) { + if (err) return handleError(err); + // сохранили! +}); +</code></pre> + +<p>Создание записей (а также обновления, удаления и запросы) - это асинхронные операции, поэтому следует предусмотреть callback-функцию, которая будет вызвана при завершении операции. В API используется соглашение о первом аргументе, согласно которому первый аргумент callback-функции должен быть значением ошибки (или null). Если API возвращает некоторый результат, он должен быть вторым аргументом.</p> + +<p>Можно использовать метод <code>create()</code> для создании экземпляра модели при его сохранении. Тогда callback-функция вернет ошибку (или null) как первый аргумент и только что созданный экземпляр как второй аргумент.</p> + +<pre class="brush: js">SomeModel<code>.create({ name: 'also_awesome' }, function (err, awesome_instance) { + if (err) return handleError(err); + // сохранили! +});</code></pre> + +<p>Каждая модель ассоциирована с соединением (с соединением по умолчанию, если используется <code>mongoose.model()</code>). Следует создать новое соединение и вызвать для него <code>.model()</code>, чтобы создать документ в другой базе данных.</p> + +<p>Поля в новой записи могут быть получены и изменены с применением dot (точка)-синтаксиса. Для сохранения изменений служат методы <code>save()</code> и <code>update()</code>.</p> + +<pre class="brush: js">// Доступ к полям модели в dot-нотации +console.log(<code>awesome_instance.name</code>); //вывод в консоль '<code>also_awesome</code>' + +// Изменить запись, модифицируя поля, потом вызвать save(). +<code>awesome_instance</code>.name="New cool name"; +<code>awesome_instance.save(function (err) { + if (err) return handleError(err); // сохранили! + });</code> +</pre> + +<h4 id="Поиск_записей">Поиск записей</h4> + +<p>При поиске записей методами запросов, условия поиска следует задавать как документ JSON. Приведенный фрагмент кода (ниже) показывает, как в БД найти имена (<em>name</em>) и возраст (<em>age</em>) всех спортсменов-теннисистов. Соответствие будет определяться по одному полю (sport), но можно добавить критерии поиска, задав, например, регулярное выражение, или удалить все критерии, чтобы получить список всех спортсменов.</p> + +<pre class="brush: js"><code>var Athlete = mongoose.model('Athlete', yourSchema); + +// найти всех теннисистов, выбирать поля 'name' и 'age' +Athlete.find({ 'sport': 'Tennis' }, 'name age', function (err, athletes) { + if (err) return handleError(err); + // 'athletes' содержит список спортсменов, соответствующих критерию. +})</code></pre> + +<p>Если задать callback-функцию так, как показано выше, запрос будет выполнен немедленно. Однако callback-функция будет вызвана только после завершения поиска.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Все callbacks-функции в Mongoose используют образец <code>callback(error, result)</code>. Если при выполнении запроса возникает ошибка, параметр <code>error</code> будет содержать объект error, а <code>result</code> будет null. При успешном запросе параметр <code>error</code> будет null, а <code>result</code> будет содержать результат запроса.</p> +</div> + +<p>Если не задать callback-функцию, API вернет переменную типа <a href="http://mongoosejs.com/docs/api.html#query-js">Query</a>. Можно использовать объект запроса, чтобы создать и выполнить свой запрос (с callback-функцией) позже, при помощи метода <code>exec()</code>.</p> + +<pre class="brush: js"><code>// найти всех теннисистов +var query = Athlete.find({ 'sport': 'Tennis' }); + +// выбрать поля 'name' и 'age' +query.select('name age'); + +// ограничить результат 5 элементами +query.limit(5); + +// сортировать по возрасту +query.sort({ age: -1 }); + +// выполнить запрос позже +query.exec(function (err, athletes) { + if (err) return handleError(err); + // athletes содержит упорядоченный список из 5 теннисистов +})</code></pre> + +<p>Выше условия поиска были заданы в методе <code>find()</code>. Можно также использовать функцию <code>where()</code>, кроме того, можно соединить все части в одном запросе применением оператора dot (.) вместо того, чтобы выполнять их раздельно. Фрагмент кода (см. ниже) выполняет тот же запрос, что и предыдущий фрагмент, но с дополнительным условием для возраста. </p> + +<pre><code>Athlete. + find(). + where('sport').equals('Tennis'). + where('age').gt(17).lt(50). //Дополнительное условие + limit(5). + sort({ age: -1 }). + select('name age'). + exec(callback); // callback - имя нашей callback-функции.</code></pre> + +<p>Метод <a href="http://mongoosejs.com/docs/api.html#query_Query-find">find()</a> находит все записи, удовлетворяющие условию, но часто требуется найти только одну из таких записей. Вот методы для поиска одной записи:</p> + +<ul> + <li><code><a href="http://mongoosejs.com/docs/api.html#model_Model.findById">findById()</a></code>: Находит документ по заданному идентификатору <code>id</code> (каждый документ имеет уникальный идентификатор <code>id</code>).</li> + <li><code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOne">findOne()</a></code>: Находит один документ, удовлетворяющий заданному критерию.</li> + <li><code><a href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndRemove">findByIdAndRemove()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate">findByIdAndUpdate()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndRemove">findOneAndRemove()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate">findOneAndUpdate()</a></code>: Находит один документ по <code>id</code> или по критерию, а затем или обновляет, или удаляет его. Эти методы весьма полезны для обновления или удаления записей.</li> +</ul> + +<div class="note"> +<p><strong>Заметка:</strong> Есть также метод <code><a href="http://mongoosejs.com/docs/api.html#model_Model.count">count()</a></code>, который определяет количество записей, соответствующих условию. Он полезен при выполнении подсчетов без фактического извлечения записей.</p> +</div> + +<p>Запросы полезны и во многих других случаях. Дополнительная информация - в <a href="http://mongoosejs.com/docs/queries.html">Queries</a> (документация Mongoose).</p> + +<h4 id="Работа_со_связанными_документами_—_загрузка">Работа со связанными документами — загрузка</h4> + +<p>Один документ (экземпляр модели) может ссылаться на другой документ при помощи поля <code>ObjectId</code> схемы, или на много других документов, используя массив идентификаторов <code>ObjectIds</code>. Идентификатор соответствующей модели хранится в поле. При необходимости получить действительное содержимое связанного документа, следует использовать в запросе метод <code><a href="http://mongoosejs.com/docs/api.html#query_Query-populate">populate()</a></code>, который заменит идентификатор в запросе действительными данными.</p> + +<p>Например, в следующей схеме определены авторы и рассказы. У каждого автора может быть несколько рассказов, которые представим массивом ссылок of <code>ObjectId</code>. У каждого рассказа может быть только один автор. Ссылка "ref" (выделена жирным) указывает в схеме, какая модель должна быть связана с этим полем.</p> + +<pre class="brush: js"><code>var mongoose = require('mongoose') + , Schema = mongoose.Schema + +var authorSchema = Schema({ + name : String, + stories : [{ type: Schema.Types.ObjectId, <strong>ref</strong>: 'Story' }] +}); + +var storySchema = Schema({ + author : { type: Schema.Types.ObjectId, <strong>ref</strong>: 'Author' }, + title : String +}); + +var Story = mongoose.model('Story', storySchema); +var Author = mongoose.model('Author', authorSchema);</code></pre> + +<p>Можно сохранить ссылки в связанном документе, используя значение идентификатора <code>_id</code>. Ниже создается автор, затем рассказ, и значение идентификатора id автора сохраняется в поле "author" рассказа.</p> + +<pre class="brush: js"><code>var bob = new Author({ name: 'Bob Smith' }); + +bob.save(function (err) { + if (err) return handleError(err); + + //автор Bob создан, создаем рассказ + var story = new Story({ + title: "Bob goes sledding", + author: bob._id // присваиваем полю значение идентификатора Боба. Идентификатор создается по умолчанию! + }); + + story.save(function (err) { + if (err) return handleError(err); + // У Боба теперь есть рассказ! + }); +});</code></pre> + +<p>Теперь документ "story" ссылается на автора по идентификатору документа "author". Для получения информации об авторе применяется метод <code>populate()</code> (показано ниже).</p> + +<pre class="brush: js"><code>Story +.findOne({ title: 'Bob goes sledding' }) +.populate('author') //подменяет идентификатор автора информацией об авторе! +.exec(function (err, story) { + if (err) return handleError(err); + console.log('The author is %s', story.author.name); + // выводит "The author is Bob Smith" +});</code></pre> + +<div class="note"> +<p><strong>Заметка:</strong> Внимательные читатели заметили, что автор добавлен к рассказу, но ничего не сделано, чтобы добавить рассказ к массиву рассказов <code>stories</code> автора. Как же тогда получить список всех рассказов конкретного автора? Один из возможных вариантов - добавить автора в массив рассказов, но при этом пришлось бы хранить данные об авторах и рассказах в двух местах и поддерживать их актуальность.</p> + +<p>Лучше получить <code>_id</code> нашего автора <em>author</em>, и применить <code>find()</code> для поиска этого идентификатора в поле "author" всех рассказов.</p> + +<pre class="brush: js"><code>Story +.find({ author : bob._id }) +.exec(function (err, stories) { + if (err) return handleError(err); + // возвращает все рассказы, у которых идентификатор Боба. +});</code> +</pre> +</div> + +<p>Это почти все, что следует знать для работы со связанными данными <em>в нашем руководстве</em>. Более полную информацию можно найти в <a href="http://mongoosejs.com/docs/populate.html">Population</a> (документация Mongoose).</p> + +<h3 id="Одна_схема_(модель)_-_один_файл">Одна схема (модель) - один файл</h3> + +<p>Можно использовать любую структуру файлов при создании схем и моделей, однако мы настоятельно рекомендуем определять каждую схему модели в отдельном модуле (файле), экспортируя метод для создания модели. Пример приведен ниже:</p> + +<pre class="brush: js"><code>// Файл: ./models/somemodel.js + +//Требуется Mongoose +var mongoose = require('mongoose'); + +//Определяем схему +var Schema = mongoose.Schema; + +var SomeModelSchema = new Schema({ + a_string : String, + a_date : Date, +}); + +<strong>//экспортируется функция для содания класса модели "SomeModel" +module.exports = mongoose.model('SomeModel', SomeModelSchema );</strong></code></pre> + +<p>You can then require and use the model immediately in other files. Below we show how you might use it to get all instances of the model.</p> + +<pre class="brush: js"><code>//Создаем модель SomeModel просто вызовом модуля из файла +var SomeModel = require('../models/somemodel') + +// Используем объект SomeModel (модель) для поиска всех записей в SomeModel +SomeModel.find(callback_function);</code></pre> + +<h2 id="Установка_базы_данных_MongoDB">Установка базы данных MongoDB</h2> + +<p>Мы уже немного понимаем, что может делать Mongoose и как следует проектировать модели. Теперь самое время начать работу над сайтом <em>LocalLibrary</em>. Самое первое, что мы должны сделать - установить базу данных MongoDb, в которой будут храниться данные нашей библиотеки.</p> + +<p>В этом руководстве мы будем использовать базу данных в "песочнице" ("<a href="https://mlab.com/plans/pricing/">sandbox</a>") - бесплатный облачный сервис, предоставляемый <a href="https://mlab.com/welcome/">mLab</a>. Такая база не очень подходит для промышленных вебсайтов, поскольку не имеет избыточности, но она очень удобна для разработки и прототипирования. Мы используем ее, так как она бесплатна, ее легко установить, и потому что mLab - популярный поставщик <em>базы данных как сервиса, </em>и это может быть разумным выбором для промышленной базы данных (на данный момент другие известные возможности включают <a href="https://www.compose.com/">Compose</a>, <a href="https://scalegrid.io/pricing.html">ScaleGrid</a> и <a href="https://www.mongodb.com/cloud/atlas">MongoDB Atlas</a>).</p> + +<div class="note"> +<p><strong>Заметка:</strong> При желании можно установить БД MongoDb локально, загрузив и установив <a href="https://www.mongodb.com/download-center">подходящие для вашей системы двоичные файлы</a>. В этом случае приводимые ниже инструкции не изменятся, за исключением URL базы данных, который нужно будет задать для установки соединения.</p> +</div> + +<p>Первым делом надо <a href="https://mlab.com/signup/">создать аккаунт</a> на mLab (это бесплатно, требует только основных контактных данных и ознакомления с условиями обслуживания). </p> + +<p>После входа в систему вы увидите главную страницу <a href="https://mlab.com/home">home</a>:</p> + +<ol> + <li>Щелкните <strong>Create New</strong> в разделе <em>MongoDB Deployments</em> для создания новой БД.<img alt="" src="https://mdn.mozillademos.org/files/14446/mLabCreateNewDeployment.png" style="height: 415px; width: 1000px;"></li> + <li>Откроется экран <em>Cloud Provider Selection - раздела провайдера облака</em>.<br> + <img alt="MLab - screen for new deployment" src="https://mdn.mozillademos.org/files/15661/mLab_new_deployment_form_v2.png" style="height: 931px; width: 1297px;"><br> + + <ul> + <li>Выберите план SANDBOX (Free) из раздела Plan Type (тип плана). </li> + <li>Выберите любого провайдера в разделе <em>Cloud Provider (провайдер облака)</em>. Разные провайдеры обслуживают разные регионы (показаны под выбранным типом плана).</li> + <li>Щелкните кнопку <strong>Continue</strong>.</li> + </ul> + </li> + <li>Откроется экран выбора региона <em>Select Region</em>. + <p><img alt="Select new region screen" src="https://mdn.mozillademos.org/files/15662/mLab_new_deployment_select_region_v2.png" style="height: 570px; width: 1293px;"></p> + + <ul> + <li> + <p>Выберите ближайщий к Вам регион и щелкните кнопку <strong>Continue</strong>.</p> + </li> + </ul> + </li> + <li> + <p>Откроется экран <em>Final Details </em>для ввода названия БД.</p> + + <ul> + <li> + <p>Введите имя новой базы - <code>local_library</code> и нажмите <strong>Continue</strong>.</p> + </li> + </ul> + </li> + <li> + <p>Откроется экран подтверждения заказа <em>Order Confirmation</em>.<br> + <img alt="Order confirmation screen" src="https://mdn.mozillademos.org/files/15664/mLab_new_deployment_order_confirmation.png" style="height: 687px; width: 1290px;"></p> + + <ul> + <li> + <p>Щелкните <strong>Submit Order</strong> (подтвердить заказ), чтобы создать БД.</p> + </li> + </ul> + </li> + <li> + <p>Вы вернетесь на главный (home) экран. Щелкните по вновь созданной базе, чтобы открыть экран с детальной информацией. Как видно, в БД нет коллекций (данных).<br> + <img alt="mLab - Database details screen" src="https://mdn.mozillademos.org/files/15665/mLab_new_deployment_database_details.png" style="height: 700px; width: 1398px;"><br> + <br> + На форме выше обведен URL для соединения с вашей БДthat you need to use to access your database is displayed on the form above (shown for this database circled above). Чтобы его использовать, необходимо создать пользователя БД, который позже введет этот URL.</p> + </li> + <li>Щелкните по вкладке <strong>Users</strong> и выберите кнопку <strong>Add database user </strong>(добавить пользователя БД).</li> + <li>Введите имя пользователя и пароль (дважды), затем нажмите <strong>Create </strong>(создать). Не отмечайте <em>Make read only </em>(только для чтения)!<br> + <img alt="" src="https://mdn.mozillademos.org/files/14454/mLab_database_users.png" style="height: 204px; width: 600px;"></li> +</ol> + +<p>Теперь БД создана, и для доступа к ней есть URL, имя пользователя и пароль. Это должно выглядеть примерно так: <code>mongodb://your_user_namer:your_password@ds119748.mlab.com:19748/local_library</code>.</p> + +<h2 id="Установка_Mongoose">Установка Mongoose</h2> + +<p>Откройте окно команд и перейдите в каталог, в котором создан <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">каркас вебсайта Local Library</a>. Введите команду install, чтобы установить Mongoose (и ее зависимости), а также добавьте ее в файл <strong>package.json</strong>, если вы еще не сделали этого ранее, при чтении примера <a href="#Installing_Mongoose_and_MongoDB">Mongoose Primer</a>.</p> + +<pre class="brush: bash">npm install mongoose +</pre> + +<h2 id="Подключение_к_MongoDB">Подключение к MongoDB</h2> + +<p>Откройте <strong>/app.js</strong> (в корне проекта) и скопируйте приведенный ниже текст, в котором объявляется <em>объект приложения</em> <em>Express</em> (после строки <code>var app = express();</code>). Замените строку url БД ('<em>insert_your_database_url_here</em>') тем URL, который представляет вашу БД (т.е. используйте информацию, полученную от<a href="#Setting_up_the_MongoDB_database"> mLab</a>).</p> + +<pre class="brush: js">//Устанавливаем соединение с mongoose +var mongoose = require('mongoose'); +var mongoDB = '<em>insert_your_database_url_here</em>';//замените url!!! +mongoose.connect(mongoDB); +mongoose.Promise = global.Promise; +var db = mongoose.connection; +db.on('error', console.error.bind(console, 'MongoDB connection error:'));</pre> + +<p>Как указано ранее в примере <a href="#Connecting_to_MongoDB">Mongoose primer</a>, этот код задает соединение по умолчанию с привязкой события ошибки error (так что ошибки будут выведены в консоль). </p> + +<h2 id="Определение_схемы_LocalLibrary">Определение схемы LocalLibrary</h2> + +<p>Мы определим отдельный модуль для каждой модели как уже обсуждалось <a href="#One_schemamodel_per_file">выше</a>. Начнем с создания каталога для моделей в корне проекта (<strong>/models</strong>), после чего создадим отдельные файлы для кажой модели:</p> + +<pre>/express-locallibrary-tutorial //the project root + <strong>/models</strong> + <strong>author.js</strong> + <strong>book.js</strong> + <strong>bookinstance.js</strong> + <strong>genre.js</strong> +</pre> + +<h3 id="Модель_автора_Author">Модель автора Author</h3> + +<p>Скопируйте код схемы автора <code>Author</code> (приведен ниже) в файл <strong>./models/author.js</strong> . В схеме определено, что у автора есть обязательные поля имени и фамилии типа <code>String</code> длиной не более 100 символов, и поля типа <code>Date</code> дата рождения и дата смерти.</p> + +<pre class="brush: js">var mongoose = require('mongoose'); + +var Schema = mongoose.Schema; + +var AuthorSchema = new Schema( + { + first_name: {type: String, required: true, max: 100}, + family_name: {type: String, required: true, max: 100}, + date_of_birth: {type: Date}, + date_of_death: {type: Date}, + } +); + +<strong>// Виртуальное свойство для полного имени автора +AuthorSchema +.virtual('name') +.get(function () { + return this.family_name + ', ' + this.first_name; +});</strong> + +// Виртуальное свойство - URL автора +AuthorSchema +.virtual('url') +.get(function () { + return '/catalog/author/' + this._id; +}); + +//Export model +module.exports = mongoose.model('Author', AuthorSchema); + +</pre> + +<p>Мы объявим также в схеме AuthorSchema <a href="#Virtual_properties">виртуальное</a> свойство "url" , которое позволит получить абсолютный URL конкретного экземпляра модели — используем это свойство в шаблонах, если потребуется получить связь с конкретным автором.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Объявить в схеме URL как виртуальные свойства - хорошая идея, т.к. URL отдельного элемента при необходимости изменения требует коррекции только в одном месте.<br> + Сейчас связь при помощи этого URL еще не работает, так как у нас еще нет кода, поддерживающего маршруты для экземпляров модели. Мы построим его в следующей статье!</p> +</div> + +<p>В конце модуля экспортируется модель.</p> + +<h3 id="Модель_книги_Book">Модель книги Book</h3> + +<p>Скопируйте код схемы <code>Book</code> (приведен ниже) в файл <strong>./models/book.js</strong>. Большая часть кода подобна коду для модели автора — объявляется схема с рядом строковых полей, с виртуальным свойством URL для получения URL конкретных книг, затем модель экспортируется.</p> + +<pre class="brush: js">var mongoose = require('mongoose'); + +var Schema = mongoose.Schema; + +var BookSchema = new Schema( + { + title: {type: String, required: true}, + <strong> author: {type: Schema.ObjectId, ref: 'Author', required: true},</strong> + summary: {type: String, required: true}, + isbn: {type: String, required: true}, + <strong> genre: [{type: Schema.ObjectId, ref: 'Genre'}]</strong> + } +); + +// Virtual for book's URL +BookSchema +.virtual('url') +.get(function () { + return '/catalog/book/' + this._id; +}); + +//Export model +module.exports = mongoose.model('Book', BookSchema); +</pre> + +<p>Основное отличие в том, что созданы две ссылки на другие модели:</p> + +<ul> + <li>author - это ссылка на единственный объект модели <code>Author</code> , обязательный элемент.</li> + <li>genre (жанр) - ссылка на массив объектов модели <code>Genre</code>. Эта модель еще не объявлена!</li> +</ul> + +<h3 id="Модель_экземпляра_книги_BookInstance">Модель экземпляра книги BookInstance</h3> + +<p>Наконец, скопируйте код схемы <code>BookInstance</code> (приведен ниже) в файл <strong>./models/bookinstance.js</strong>. Схема <code>BookInstance</code> представляет конкретный экземпляр книги, которую можно одолжить на время, и содержит информацию о доступности экземпляров книги, о дате возврата одолженной книги, о деталях версии или печатного экземпляра.</p> + +<pre class="brush: js">var mongoose = require('mongoose'); + +var Schema = mongoose.Schema; + +var BookInstanceSchema = new Schema( + { + book: { type: Schema.ObjectId, ref: 'Book', required: true }, //ссылка на книгу + imprint: {type: String, required: true}, + status: {type: String, required: true, <strong>enum: ['Available', 'Maintenance', 'Loaned', 'Reserved']</strong>, <strong>default: 'Maintenance'</strong>}, + due_back: {type: Date, <strong>default: Date.now</strong>} + } +); + +// Virtual for bookinstance's URL +BookInstanceSchema +.virtual('url') +.get(function () { + return '/catalog/bookinstance/' + this._id; +}); + +//Export model +module.exports = mongoose.model('BookInstance', BookInstanceSchema);</pre> + +<p>В этой схеме новыми являются опции поля:</p> + +<ul> + <li><code>enum</code>: Позволяет указать допустимые значения строки. В нашем случае используются, чтобы задать статус доступности книги (применение enum (перечисления) означает, что мы ходим предотвратить ошибочное написание и произвольные значения статуса)</li> + <li><code>default</code>: определяет значание статуса по умолчанию (maintenance) при создании экземпляра книги, и дату <code>due_back </code>возврата книги (<code>now,</code> сейчас). Отметьте, как используется функция Date при установке даты!</li> +</ul> + +<p>Все остальное знакомо по предыдущим схемам.</p> + +<h3 id="Модель_жанра_Genre_-_проверьте_себя!">Модель жанра Genre - проверьте себя!</h3> + +<p>Откройте файл <strong>./models/genre.js</strong> и создайте схему для хранения жанра (категории книги, т.е. художественная или научная, романтика или военная история и т.д.).</p> + +<p>Определение будет подобно другим моделям:</p> + +<ul> + <li>В модели должно быть поле <code>name</code> типа <code>String</code> для указания жанра.</li> + <li>Это поле должно быть обязательным, допустимый размер - от 3 до 100 символов.</li> + <li>Объявите виртуальное (<a href="#Virtual_properties">virtual</a>) свойство с именем <code>url</code> для URL жанра.</li> + <li>Экспортируйте модель.</li> +</ul> + +<h2 id="Тестирование_—_создаем_элементы_БД">Тестирование — создаем элементы БД</h2> + +<p>Вот так. У нас теперь есть все модели для создания сайта!</p> + +<p>Для тестирования моделей (и для создания примеров книг и других элементов, которые потребуются в следующих статьях) выполним <em>независимый </em>скрипт, который создаст элементы каждого типа:</p> + +<ol> + <li>Загрузите (или создайте) файл <a href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js">populatedb.js</a> в каталоге <em>express-locallibrary-tutorial</em> (на том же уровне, что и <code>package.json</code>). + + <div class="note"> + <p><strong>Заметка:</strong> Не обязательно понимать, как работает <a href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js">populatedb.js</a>; он просто помещает некоторые данные в базу данных.</p> + </div> + </li> + <li>Введите в корне проекта команду для установки модуля <em>async, </em>который потребуется скрипту populatedb.js (роль async обсудим в следующих руководствах) + <pre class="brush: bash">npm install async</pre> + </li> + <li>Запустите скрипт из командной строки, используя node. В качестве параметра укажите URL вашей БД <em>MongoDB</em> (тот самый, которым вы ранее заменили <em>insert_your_database_url_here </em>в<em> </em>файле <code>app.js</code> ): + <pre class="brush: bash">node populatedb <your mongodb url></pre> + </li> + <li>Скрипт должен выполниться до конца, выводя в терминал создаваемые элементы.</li> +</ol> + +<div class="note"> +<p><strong>Совет:</strong> Откройте свою базу на <a href="https://mlab.com/home">Lab</a>. Вы сможете увидеть коллекции Book, Author, Genre, BookInstance (книги, авторы, жанры, экземпляры книг) и просмотреть содержащиеся в них документы.</p> +</div> + +<h2 id="Итог">Итог</h2> + +<p>В этой статье мы познакомились с БД и ОРМ (объектно-реляционными моделями) в системе Node/Express, узнали, как определяются схемы и модели Mongoose. Мы применили эти знания при проектировании и реализации моделей <code>Book</code>, <code>BookInstance</code>, <code>Author</code> и <code>Genre</code> для вебсайта <em>LocalLibrary</em>.</p> + +<p>В конце мы испытали свои модели путем создания ряда элементов (при помощи автономного скрипта). В следующей статье мы рассмотрим создание страниц, на которых будут показаны эти элементы.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> Интеграция БД (документация Express)</li> + <li><a href="http://mongoosejs.com/">Mongoose website</a> Вебсайт Mongoose (документация Mongoose)</li> + <li><a href="http://mongoosejs.com/docs/guide.html">Mongoose Guide</a> Справочник Mongoose (документация Mongoose)</li> + <li><a href="http://mongoosejs.com/docs/validation.html">Validation</a> Валидация (документация Mongoose)</li> + <li><a href="http://mongoosejs.com/docs/schematypes.html">Schema Types</a> Типы в схемах (документация Mongoose)</li> + <li><a href="http://mongoosejs.com/docs/models.html">Models</a> Модели (документация Mongoose)</li> + <li><a href="http://mongoosejs.com/docs/queries.html">Queries</a> Запросы (документация Mongoose)</li> + <li><a href="http://mongoosejs.com/docs/populate.html">Population</a> Пополнение БД (документация Mongoose)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/server-side/express_nodejs/routes/index.html b/files/ru/learn/server-side/express_nodejs/routes/index.html new file mode 100644 index 0000000000..c8610eba1b --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/routes/index.html @@ -0,0 +1,655 @@ +--- +title: 'Учебник Express часть 4: Маршруты и контроллеры' +slug: Learn/Server-side/Express_Nodejs/routes +translation_of: Learn/Server-side/Express_Nodejs/routes +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">В этом уроке мы настроим маршруты (код обработки URL) с "фиктивными" функциями-обработчиками для всех конечных точек ресурса, которые нам понадобятся на веб-сайте <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a>. По завершении мы получим модульную структуру для нашего кода обработки маршрута, который будет расширен реальными функциями-обработчиками в следующих статьях. У нас также будет хорошее понимание того, как создавать модульные маршруты с помощью Express!</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row"> + <table> + <tbody> + <tr> + <th scope="row">Предварительные знания:</th> + </tr> + </tbody> + </table> + </th> + <td>Прочесть <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">введение в Express/Node </a>. Завершить предыдущие уроки (включая <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a>).</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять, как создать простые маршруты. Настроить конечные точки URL.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>В <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">последней статье </a>мы определили модели <em>Mongoose</em> для взаимодействия с базой данных, и использовали (автономный) скрипт, который создал некоторые исходные записи библиотеки. Теперь можно написать код, чтобы представить эту информацию пользователям. Первое, что нужно сделать, это решить, какие возможности для отображения информации мы хотим иметь на наших страницах, а затем определить соответствующие URL-адреса для получения этих ресурсов. Затем нужно будет создать маршруты (обработчики URL-адресов) и представления (шаблоны) для отображения этих страниц.</p> + +<p>Приведенная ниже диаграмма напоминает об основном потоке данных и об элементах, которые необходимо реализовать при обработке HTTP-запроса/ответа. Кроме представлений и маршрутов на диаграмме показаны "контроллеры" - функции, которые отделяют код для маршрутизации запросов от кода, который фактически обрабатывает запросы.</p> + +<p>Поскольку модели уже созданы, основные элементы, которые следует создать, таковы:</p> + +<ul> + <li>"Маршруты" для перенаправления поддерживаемых запросов (и любой закодированной информации в URL-запросах) соответствующим функциям контроллера.</li> + <li>Контроллеры -функции для получения запрашиваемых данных из моделей, создание HTML страницы, отображающей данные, и возращение их пользователю для просмотра в браузере.</li> + <li>Представления (шаблоны), используемые контроллерами для отрисовки данных.</li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14456/MVC%20Express.png" style="height: 460px; width: 800px;"></p> + +<p>В итоге, у нас должны быть страницы для вывода списков и детальной информации по книгам, жанрам, авторам и экземплярам книг, а также страницы для создания, обновления и удаления записей. Это много для одной статьи. Поэтому большая часть этой статьи будет сосредоточена на настройке наших маршрутов и контроллеров для возврата "фиктивного" контента. Мы расширим методы контроллеров для работы с данными модели в следующих статьях .</p> + +<p>В первом разделе ниже приведен краткие основы того, как использовать промежуточное средство (middleware) Express <a href="http://expressjs.com/en/4x/api.html#router">Router</a>. Эти знания будут использованы в следующих разделах при настройке маршрутов для LocalLibrary.</p> + +<h2 id="Маршруты_-_основы">Маршруты - основы</h2> + +<p>Маршруты - это часть кода Express, связывающая HTTP действия (<code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>DELETE</code>, etc.), URL пути (шаблона), и функцию, которая обрабатывает этот шаблон.</p> + +<p>Есть несколько способов создания маршрутов. В этом уроке мы используем промежуточные запросы <code><a href="http://expressjs.com/en/guide/routing.html#express-router">express.Router</a>,</code> так как они позволяют группировать обработчики маршрутов для определенной части сайта и получать к ним доступ через общий префикс маршрута. Все маршруты, связанные с библиотекой, будут сохранены в модуле "catalog", и если мы добавим маршруты для обработки учетных записей пользователей или других функций, мы сможем сгруппировать их отдельно.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Маршруты приложения Express уже кратко рассматривались в <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction#Creating_route_handlers">Express Introduction > Creating route handlers</a> (Введение -> Создание обработчиков маршрутов). Применение <em>Router </em>обеспечивает лучшую поддержку модульности (как обсуждается в первой подсекции ниже), а в остальном очень похоже на определение маршрутов непосредственно в объекте приложения <em>Express</em>.</p> +</div> + +<p>В оставшейся части этого раздела представлен обзор того, как Router может быть использован для определения маршрутов.</p> + +<h3 id="Определение_и_использование_отдельных_модулей_маршрутов">Определение и использование отдельных модулей маршрутов</h3> + +<p>Код ниже является реальным примером того, как можно создать модуль маршрута, а затем использовать его в приложении <em>Express</em>.</p> + +<p>Первым делом в модуле <strong>wiki.js </strong>создадим маршруты для wiki . Код сначала импортирует объект приложения Express, использует его для получения объекта <code>Router</code> и затем, применяя метод <code>get(),</code> добавляет к объекту пару маршрутов. В завершение модуль экспортирует объект <code>Router</code> .</p> + +<pre class="brush: js"><code>// wiki.js - Wiki route module. + +var express = require('express'); +var router = express.Router(); + +// Home page route. +router.get('/', function (req, res) { + res.send('Wiki home page'); +}) + +// About page route. +router.get('/about', function (req, res) { + res.send('About this wiki'); +}) + +module.exports = router;</code> + +</pre> + +<div class="note"> +<p><strong>Заметка:</strong> В примере callback-функции обработчиков маршрутов определены непосредственно в функциях роутеров. А в LocalLibrary мы определим эти callback-функции в отдельном модуле контроллера.</p> +</div> + +<p>Чтобы использовать модуль роутера в главном приложении, прежде всего следует выполнить <code>require()</code> модуля маршрута (<strong>wiki.js</strong>). Потом вызовем <code>use()</code> для приложения Express с аргументом, в котором указан URL-путь 'wiki', что добавит Router к пути обработки промежуточного слоя.</p> + +<pre class="brush: js"><code>var wiki = require('./wiki.js'); +// ... +app.use('/wiki', wiki);</code></pre> + +<p>После этого два маршрута, определенные в нашем модуле маршрутов wiki, станут доступны из <code>/wiki/</code> и <code>/wiki/about/</code>.</p> + +<h3 id="Функции_Route">Функции Route</h3> + +<p>В модуле выше определена пара типовых функций маршрута. Маршрут "about" (еще раз показан ниже) определен при помощи метода <code>Router.get()</code>, который отвечает только на HTTP GET-запросы. Первый аргумент метода - URL-путь, а второй - callback-функция, которая будет вызвана, если получен HTTP GET-запрос с указанным путем.</p> + +<pre class="brush: js"><code>router.get('/about', function (req, res) { + res.send('About this wiki'); +})</code> +</pre> + +<p>Эта callback-функция имеет три аргумента takes three arguments (обычно именуемых как указано: <code>req</code>, <code>res</code>, <code>next</code>), которые соответствуют объекту HTTP запроса, ответу HTTP, и <em>следующей</em> <br> + функции в цепочке промежуточных элементов.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Фукции в Router - это промежуточный слой (<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction#Using_middleware">middleware</a>) are <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction#Using_middleware">Express </a>, что означает, что они должны или завершить (ответить на) запрос reqили вызвать следующую (<code>next)</code> функцию в цепочке. В нашем случае запрос завершается вызовом <code>send()</code>, поэтому аргумент <code>next</code> не нужен (и поэтому не указан).</p> + +<p>Выше у функции роутера только один callback-аргумент, но можно указать столько таких аргументов, сколько хотите, или указать массив callback-функций. каждая из функций - это элемент в цепочке промежуточного слоя, и они будут вызываться в порядке их добавления в цепочку (если предыдущая функция не завершит запрос).</p> +</div> + +<p>Здесь, когда приходит GET-запрос с путем ('<code>/about'</code>) callback-функция при ответе вызывает <code><a href="https://expressjs.com/en/4x/api.html#res.send">send()</a></code> , возвращая строку "About this wiki". Существует <a href="https://expressjs.com/en/guide/routing.html#response-methods">ряд других методов ответа</a> , завершающих цикл запрос-ответ. Например, можно вызвать <code><a href="https://expressjs.com/en/4x/api.html#res.json">res.json()</a></code> , чтобы послать ответ JSON, или <code><a href="https://expressjs.com/en/4x/api.html#res.sendFile">res.sendFile()</a>,</code> чтобы послать файл. Метод ответа, который будет использован чаще всего при построении нашей библиотеки - это <a href="https://expressjs.com/en/4x/api.html#res.render">render()</a>, создающий, на основе шаблонов и данных, и возвращающий HTML-файлы —мы поговорим об этом подробнее в следующей статье!</p> + +<h3 id="HTTP_глаголы_(действия)">HTTP глаголы (действия)</h3> + +<p>Рассмотренный пример использует метод <code>Router.get()</code> для ответа на HTTP GET- запросы с указанным путем.</p> + +<p>Кроме того, <code>Router</code> обеспечивает также методы маршрутизации для других HTTP глаголов, которые обычно используются точно таким же способом: <code>post()</code>, <code>put()</code>, <code>delete()</code>, <code>options()</code>, <code>trace()</code>, <code>copy()</code>, <code>lock()</code>, <code>mkcol()</code>, <code>move()</code>, <code>purge()</code>, <code>propfind()</code>, <code>proppatch()</code>, <code>unlock()</code>, <code>report()</code>, <code>mkactivity()</code>, <code>checkout()</code>, <code>merge()</code>, <code>m-</code><code>search()</code>, <code>notify()</code>, <code>subscribe()</code>, <code>unsubscribe()</code>, <code>patch()</code>, <code>search()</code>, и <code>connect()</code>.</p> + +<p>Например, код ниже делает то же, что и предыдущий, с путем <code>/about,</code> но отвечает на HTTP POST-запросы.</p> + +<pre class="brush: js"><code>router.post('/about', function (req, res) { + res.send('About this wiki'); +})</code></pre> + +<h3 id="Маршруты_путей">Маршруты путей</h3> + +<p>Маршруты путей определяют конечные точки, в которых могут быть сделаны запросы. В уже рассмотренных примерах это были просто строки, которые использовались точно так, как были записаны: '/', '/about', '/book', '/any-random.path'.</p> + +<p>Маршруты путей могут быть также образцами строк. Образцы строк используют подмножество синтаксиса регулярных выражений для определения <em>образцов</em> конечных точек, для которых должно проверяться соответствие. Подмножество приведено ниже (отметим, что перенос (<code>-</code>) и точка (<code>.</code>) в путях на основе строк понимаются буквально):</p> + +<ul> + <li>? : Конечная точка должна иметь 0 или 1 предыдущий символ. Так, путь маршрута <code>'/ab?cd'</code> соответствует конечным точкам <code>acd</code> или <code>abcd</code> (т.е. b может присутствовать или нет).</li> + <li>+ : Конечная точка должна иметь 1 или более предыдущих символов. Так, путь маршрута <code>'/ab+cd'</code> будет соответствовать конечным точкам <code>abcd</code>, <code>abbcd</code>, <code>abbbcd</code>, и так далее.</li> + <li>* : Конечная точка может содержать произвольную строку там, где находится символ '*'. Так, путь маршрута <code>'ab\*cd'</code> будет соответствовать конечным точкам <code>abcd</code>, <code>abXcd</code>, <code>abSOMErandomTEXTcd</code>, и так далее.</li> + <li>() : Группировка символов для выполнения другой операции. Так, <code>'/ab(cd)?e'</code> выполнит ?-проверку (0 или 1 появление) для группы (cd) — соответствия таковы: <code>abe</code> и <code>abcde</code>.</li> +</ul> + +<p>Пути маршрутов могут быть также <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">регулярными выражениями</a> JavaScript. Например, путь маршрутов (ниже) будет соответствовать <code>catfish и</code> <code>dogfish</code>, но не <code>catflap</code>, <code>catfishhead</code>, и так далее. Отметим, регулярное выражение как путь использует синтаксис регулярных выражений (это не строка в кавычках, как в предыдущих случаях).</p> + +<pre class="brush: js"><code>app.get(/.*fish$/, function (req, res) { + ... +})</code></pre> + +<div class="note"> +<p><strong>Заметка:</strong> Большинство наших маршрутов для библиотеки будут просто строками, а не образцами строк или регулярными выражениями. Кроме того, будут использоваться параметры маршрутов, что обсуждается в следующем разделе.</p> +</div> + +<h3 id="Параметры_маршрутов">Параметры маршрутов</h3> + +<p>Параметры маршрутов - это <em>именованные сегменты URL</em> , которые используются для выбора значений из указанной позиции URL. Именованные сегменты начинаются двоеточием, после которого следует имя (например, <code>/<strong>:</strong>your_parameter_name/</code>. Выбранные значения сохраняются в объекте <code>req.params,</code> причем имя параметра используется как ключ (т.е. <code>req.params.your_parameter_name</code>).</p> + +<p>Предположим, например, что URL содержит информацию о пользователях и книгах: <code>http://localhost:3000/users/34/books/8989</code>. Можно извлечь эту информацию (см. ниже) в параметры <code>userId</code> и <code>bookId</code> пути:</p> + +<pre><code>app.get('/users/:userId/books/:bookId', function (req, res) { + // доступ к userId через: req.params.userId + // доступ к bookId через: req.params.bookId + res.send(req.params); +}) +</code></pre> + +<p>Имена параметров пути должны состоять из “символов слова” (A-Z, a-z, 0-9, и _).</p> + +<div class="note"> +<p><strong>Заметка:</strong> URL <em>/book/create</em> будет соответствовать маршрутам вида <code>/book/:bookId</code> (и '<code>create</code>' станет значением "bookId"). Будет использован первый маршрут, соответствующий введенному URL, поэтому, если необходимо обрабатывать URL вида <code>/book/create</code> отдельно, обработчик этого маршрута должен быть расположен до маршрута <code>/book/:bookId</code> .</p> +</div> + +<p>Для начала этих сведений достаточно - если потребуется, можно найти дополнительную информацию в документации Express: <a href="http://expressjs.com/en/starter/basic-routing.html">Basic routing</a> (основы маршрутизации) и <a href="http://expressjs.com/en/guide/routing.html">Routing guide</a> (руководство по маршрутизации). В следующем разделе показано, как задать маршруты и контроллеры для нашей библиотеки LocalLibrary.</p> + +<h2 id="Маршруты_необходимые_для_библиотеки_LocalLibrary">Маршруты, необходимые для библиотеки LocalLibrary</h2> + +<p>Те URL, котрые в итоге будут нужны для наших страниц, показаны ниже. Слово <em>object</em> должно быть заменено на имя каждой из наших моделей (book, bookinstance, genre, author), слово <em>objects</em> - множественное число для <em>object, </em>а <em>id</em> - уникальное значение для поля(<code>_id</code>), которое Mongoose создает по умолчанию для каждого экземпляра модели.</p> + +<ul> + <li><code>catalog/</code> — Домашняя страница home/index.</li> + <li><code>catalog/<objects>/</code> — Список всех книг, экземпляров книг, жанров и авторов (т.е. /<code>catalog/books/</code>, /<code>catalog/genres/</code>, и т.д.)</li> + <li><code>catalog/<object>/<em><id></em></code> — Страница с подробностями для отдельной книги, экземпляра книги, жанра или автора с заданным полем идентификатора <code><em>_id</em></code> (т.е. <code>/catalog/book/584493c1f4887f06c0e67d37)</code>.</li> + <li><code>catalog/<object>/create</code> — Форма для создания новой книги, экземпляра книги, жанра или автора (т.е. <code>/catalog/book/create)</code>.</li> + <li><code>catalog/<object>/<em><id></em>/update</code> — Форма для обновления отдельной книги, экземпляра книги, жанра или автора с заданным идентификатором <code><em>_id</em></code> (т.е. <code>/catalog/book/584493c1f4887f06c0e67d37/update)</code>.</li> + <li><code>catalog/<object>/<em><id></em>/delete</code> — Форма для удаления отдельной книги, экземпляра книги, жанра или автора по заданному идентификатору <code><em>_id</em></code> (т.е. <code>/catalog/book/584493c1f4887f06c0e67d37/delete)</code>.</li> +</ul> + +<p>Первая домашняя страница и страницы со списками не кодируют никакой дополнительной информации. Хотя результаты, возвращаемые запросами, будут зависеть от типа модели и от содержимого БД, запросы для получения этой информации всегда будут одинаковы (подобно тому, как код для создания объектов всегда будет одним и тем же). </p> + +<p>В противоположность этому, другие URL используются для работы с определенными экземплярами документов и моделей— индивидуальность элементов кодируется в URL (как <code><em><id></em></code> выше). Параметры путей используются для извлечения информации и передачи ее в обработчик пути (и в следующей статье мы применим этот прием для того, чтобы динамически определять, какую информацию следует получить из БД). By encoding the information in our URL we only need one route for every resource of a particular type (e.g. one route to handle the display of every single book item).</p> + +<div class="note"> +<p><strong>Заметка</strong>: Express позволяет строить URL любым способом, который вам нравится — можно кодировать информацию в теле URL как показано выше или использовать URL <code>GET</code> -запрос с параметрами (например, <code>/book/?id=6</code>). Какой бы подход вы не применяли, URL должны быть ясными, логичными и читаемыми (ознакомьтесь с советами<a href="https://www.w3.org/Provider/Style/URI"> W3C</a>).</p> +</div> + +<p>Далее мы создадим callback-функции обработчиков маршрутов и код маршрутов для всех указанных выше URL.</p> + +<h2 id="Создаем_callback-функции_обработчиков_маршрутов">Создаем callback-функции обработчиков маршрутов</h2> + +<p>Перед определением маршрутов сначала создадим фиктивные (каркасные) callback-функции, которые они будут вызывать. Эти функции будут храниться в отдельных модулях -"контроллерах" для моделей Book, BookInstance, Genre, и Author (можно использовать любую структуру моделей и файлов, но кажется, что выбранная обеспечивает приемлемую модульность нашего проекта).</p> + +<p>Начнем с создания каталога для контроллеров в корне проекта (<strong>/controllers</strong>), а затем создадим отдельные файлы (модули) контроллеров для работы с моделями:</p> + +<pre>/express-locallibrary-tutorial //корень проекта + <strong>/controllers</strong> + <strong>authorController.js</strong> + <strong>bookController.js</strong> + <strong>bookinstanceController.js</strong> + <strong>genreController.js</strong></pre> + +<h3 id="Контроллер_автора">Контроллер автора</h3> + +<p>Скопируем следующий код в файл <strong>/controllers/authorController.js</strong>:</p> + +<pre class="brush: js">var Author = require('../models/author'); + +// Показать список всех авторов. +exports.author_list = function(req, res) { + res.send('NOT IMPLEMENTED: Author list'); +}; + +// Показать подробную страницу для данного автора. +exports.author_detail = function(req, res) { + res.send('NOT IMPLEMENTED: Author detail: ' + req.params.id); +}; + +// Показать форму создания автора по запросу GET. +exports.author_create_get = function(req, res) { + res.send('NOT IMPLEMENTED: Author create GET'); +}; + +// Создать автора по запросу POST. +exports.author_create_post = function(req, res) { + res.send('NOT IMPLEMENTED: Author create POST'); +}; + +// Показать форму удаления автора по запросу GET. +exports.author_delete_get = function(req, res) { + res.send('NOT IMPLEMENTED: Author delete GET'); +}; + +// Удалить автора по запросу POST. +exports.author_delete_post = function(req, res) { + res.send('NOT IMPLEMENTED: Author delete POST'); +}; + +// Показать форму обновления автора по запросу GET. +exports.author_update_get = function(req, res) { + res.send('NOT IMPLEMENTED: Author update GET'); +}; + +// Обновить автора по запросу POST. +exports.author_update_post = function(req, res) { + res.send('NOT IMPLEMENTED: Author update POST'); +}; +</pre> + +<p>В модуле сначала подключается (requires) модель, которая далее будет использована для получения данных и их обновления. Далее экспортируются функции для каждого URL, который мы хотим обрабатывать (операции create-создать, update-обновить и delete-удалить используют формы, следовательно, должны быть дополнительные методы для обработки post-запросов от форм - эти методы обсуждаются далее, в статье "forms article" ("формы")).</p> + +<p>Все функции имеют стандартную форму функций среднего слоя <em>Express </em>, с арнументами для запроса, ответа и следующей <code>(next)</code> функции, которая должна быть вызвана, если метод не завершил цикл запроса (во всех приведенных в коде случаях - завершает!). Методы просто возвращают строку, информирующую о том, что соответствующая страница еще не создана. Если функция контроллера должна получить параметры маршрута, эти параметры будут выведены в строке сообщения (смотри выше <code>req.params.id</code> ).</p> + +<h4 id="BookInstance_controller">BookInstance controller</h4> + +<p>Скопируйте следующий код в файл <strong>/controllers/bookinstanceController.js</strong> (он построен по образцу модуля контроллера для автора <code>Author</code> ):</p> + +<pre class="brush: js">var BookInstance = require('../models/bookinstance'); + +// Display list of all BookInstances. +exports.bookinstance_list = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance list'); +}; + +// Display detail page for a specific BookInstance. +exports.bookinstance_detail = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance detail: ' + req.params.id); +}; + +// Display BookInstance create form on GET. +exports.bookinstance_create_get = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance create GET'); +}; + +// Handle BookInstance create on POST. +exports.bookinstance_create_post = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance create POST'); +}; + +// Display BookInstance delete form on GET. +exports.bookinstance_delete_get = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance delete GET'); +}; + +// Handle BookInstance delete on POST. +exports.bookinstance_delete_post = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance delete POST'); +}; + +// Display BookInstance update form on GET. +exports.bookinstance_update_get = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance update GET'); +}; + +// Handle bookinstance update on POST. +exports.bookinstance_update_post = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance update POST'); +}; +</pre> + +<h4 id="Контроллер_жанра">Контроллер жанра</h4> + +<p>Скопируйте следующий код в файл <strong>/controllers/genreController.js</strong> (он построен по образцу модулей контроллеров для автора <code>Author</code> и экземпляра книги <code>BookInstance</code>):</p> + +<pre class="brush: js">var Genre = require('../models/genre'); + +// Display list of all Genre. +exports.genre_list = function(req, res) { + res.send('NOT IMPLEMENTED: Genre list'); +}; + +// Display detail page for a specific Genre. +exports.genre_detail = function(req, res) { + res.send('NOT IMPLEMENTED: Genre detail: ' + req.params.id); +}; + +// Display Genre create form on GET. +exports.genre_create_get = function(req, res) { + res.send('NOT IMPLEMENTED: Genre create GET'); +}; + +// Handle Genre create on POST. +exports.genre_create_post = function(req, res) { + res.send('NOT IMPLEMENTED: Genre create POST'); +}; + +// Display Genre delete form on GET. +exports.genre_delete_get = function(req, res) { + res.send('NOT IMPLEMENTED: Genre delete GET'); +}; + +// Handle Genre delete on POST. +exports.genre_delete_post = function(req, res) { + res.send('NOT IMPLEMENTED: Genre delete POST'); +}; + +// Display Genre update form on GET. +exports.genre_update_get = function(req, res) { + res.send('NOT IMPLEMENTED: Genre update GET'); +}; + +// Handle Genre update on POST. +exports.genre_update_post = function(req, res) { + res.send('NOT IMPLEMENTED: Genre update POST'); +}; +</pre> + +<h4 id="Контроллер_книги">Контроллер книги</h4> + +<p>Скопируйте следующий код в файл <strong>/controllers/bookController.js</strong>. Он построен по образцу других модулей контроллеров, но еще содержит функцию <code>index()</code> для вывода странички с приветствием:</p> + +<pre class="brush: js">var Book = require('../models/book'); + +<strong>exports.index = function(req, res) { + res.send('NOT IMPLEMENTED: Site Home Page'); +};</strong> + +// Display list of all books. +exports.book_list = function(req, res) { + res.send('NOT IMPLEMENTED: Book list'); +}; + +// Display detail page for a specific book. +exports.book_detail = function(req, res) { + res.send('NOT IMPLEMENTED: Book detail: ' + req.params.id); +}; + +// Display book create form on GET. +exports.book_create_get = function(req, res) { + res.send('NOT IMPLEMENTED: Book create GET'); +}; + +// Handle book create on POST. +exports.book_create_post = function(req, res) { + res.send('NOT IMPLEMENTED: Book create POST'); +}; + +// Display book delete form on GET. +exports.book_delete_get = function(req, res) { + res.send('NOT IMPLEMENTED: Book delete GET'); +}; + +// Handle book delete on POST. +exports.book_delete_post = function(req, res) { + res.send('NOT IMPLEMENTED: Book delete POST'); +}; + +// Display book update form on GET. +exports.book_update_get = function(req, res) { + res.send('NOT IMPLEMENTED: Book update GET'); +}; + +// Handle book update on POST. +exports.book_update_post = function(req, res) { + res.send('NOT IMPLEMENTED: Book update POST'); +}; +</pre> + +<h2 id="Создание_модуля_для_маршрута_catalog">Создание модуля для маршрута catalog</h2> + +<p>Далее мы создадим маршруты для всех URL, необходимых веб-сайту<a href="#local_libary_routes"> LocalLibrary</a>, которые будут вызывать функции контроллеров, определенные в предыдущем разделе.</p> + +<p>Каркас приложения уже содержит каталог <strong>./routes</strong>, в котором есть маршруты для <em>index</em> и <em>users</em>. Внутри этого каталога создадим еще один файл маршрутов — <strong>catalog.js</strong> ( см. ниже).</p> + +<pre>/express-locallibrary-tutorial //the project root + /routes + index.js + users.js + <strong>catalog.js</strong></pre> + +<p>Скопируйте приведенный ниже код в файл <strong>/routes/</strong><strong>catalog.js</strong> :</p> + +<pre class="brush: js"><strong>var express = require('express'); +var router = express.Router(); +</strong> +// Требующиеся модули контроллеров. +var book_controller = require('../controllers/bookController'); +var author_controller = require('../controllers/authorController'); +var genre_controller = require('../controllers/genreController'); +var book_instance_controller = require('../controllers/bookinstanceController'); + +/// BOOK ROUTES МАРШРУТЫ КНИГ/// + +// GET catalog home page. +router.get('/', book_controller.index); + +// GET request for creating a Book. NOTE This must come before routes that display Book (uses id). +// GET запрос для создания книги. Должен появиться до маршрута, показывающего книгу(использует id) +router.get('/book/create', book_controller.book_create_get); + +// POST request for creating Book. +router.post('/book/create', book_controller.book_create_post); + +// GET request to delete Book. +router.get('/book/:id/delete', book_controller.book_delete_get); + +// POST request to delete Book. +router.post('/book/:id/delete', book_controller.book_delete_post); + +// GET request to update Book. +router.get('/book/:id/update', book_controller.book_update_get); + +// POST request to update Book. +router.post('/book/:id/update', book_controller.book_update_post); + +// GET request for one Book. +router.get('/book/:id', book_controller.book_detail); + +// GET request for list of all Book items. +router.get('/books', book_controller.book_list); + +/// AUTHOR ROUTES /// + +// GET request for creating Author. NOTE This must come before route for id (i.e. display author). +// GET-запрос для создания автора. Должен появиться до маршрута для id (для вывода автора) +router.get('/author/create', author_controller.author_create_get); + +// POST request for creating Author. +router.post('/author/create', author_controller.author_create_post); + +// GET request to delete Author. +router.get('/author/:id/delete', author_controller.author_delete_get); + +// POST request to delete Author. +router.post('/author/:id/delete', author_controller.author_delete_post); + +// GET request to update Author. +router.get('/author/:id/update', author_controller.author_update_get); + +// POST request to update Author. +router.post('/author/:id/update', author_controller.author_update_post); + +// GET request for one Author. +router.get('/author/:id', author_controller.author_detail); + +// GET request for list of all Authors. +router.get('/authors', author_controller.author_list); + +/// GENRE ROUTES /// + +// GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id). +// GET-запрос для создания жанра. Должен появиться до маршрута, выводящего жанр (( с использованием id) +router.get('/genre/create', genre_controller.genre_create_get); + +//POST request for creating Genre. +router.post('/genre/create', genre_controller.genre_create_post); + +// GET request to delete Genre. +router.get('/genre/:id/delete', genre_controller.genre_delete_get); + +// POST request to delete Genre. +router.post('/genre/:id/delete', genre_controller.genre_delete_post); + +// GET request to update Genre. +router.get('/genre/:id/update', genre_controller.genre_update_get); + +// POST request to update Genre. +router.post('/genre/:id/update', genre_controller.genre_update_post); + +// GET request for one Genre. +router.get('/genre/:id', genre_controller.genre_detail); + +// GET request for list of all Genre. +router.get('/genres', genre_controller.genre_list); + +/// BOOKINSTANCE ROUTES /// + +// GET request for creating a BookInstance. NOTE This must come before route that displays BookInstance (uses id). +// GET-запрос для создания экземпляра книги. Должен появиться до маршрута, выводящего BookInstance с использованием id +router.get('/bookinstance/create', book_instance_controller.bookinstance_create_get); + +// POST request for creating BookInstance. +router.post('/bookinstance/create', book_instance_controller.bookinstance_create_post); + +// GET request to delete BookInstance. +router.get('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_get); + +// POST request to delete BookInstance. +router.post('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_post); + +// GET request to update BookInstance. +router.get('/bookinstance/:id/update', book_instance_controller.bookinstance_update_get); + +// POST request to update BookInstance. +router.post('/bookinstance/:id/update', book_instance_controller.bookinstance_update_post); + +// GET request for one BookInstance. +router.get('/bookinstance/:id', book_instance_controller.bookinstance_detail); + +// GET request for list of all BookInstance. +router.get('/bookinstances', book_instance_controller.bookinstance_list); + +<strong>module.exports = router;</strong> +</pre> + +<p>Модуль загружает Express и использует его для создания объекта <code>Router</code> . В маршутизаторе задаются маршруты и производится их экспорт.</p> + +<p>Маршруты определяют в объекте маршрутизатора или <code>.get()</code> или <code>.post()</code> методы. Все пути заданы как строки (образцы строк и регулярные выражения не использовались). Маршруты, которые взаимодействуют с конкретным ресурсом (скажем, с книгой), для получения из URL идентификатора объекта используют параметры путей.</p> + +<p>Все функции-обработчики импортируются из созданных в предыдущем разделе модулей контроллеров.</p> + +<h3 id="Обновление_модуля_маршрута_index">Обновление модуля маршрута index</h3> + +<p>Все новые маршруты заданы, а маршрут на начальную страницу остался без изменения. Давайте перенаправим его на новую страницу "index", которая создана в каталоге '/catalog'.</p> + +<p>Откройте <strong>/routes/index.js</strong> и замените существущий маршрут нприведенную ниже.</p> + +<pre class="brush: js">// GET home page. +router.get('/', function(req, res) { + res.redirect('/catalog'); +});</pre> + +<div class="note"> +<p><strong>Заметка:</strong> Это первое использование метода ответа <a href="https://expressjs.com/en/4x/api.html#res.redirect">redirect()</a> . Он делает перенаправление на указанную страницу, и по умолчанию устанавливает код возврата HTTP в "302 Found" (найдено). Если требуется, можно изменить код возврата. Путь можно задавать как абсолютный или как относительный.</p> +</div> + +<h3 id="Обновление_app.js">Обновление app.js</h3> + +<p>Завершающий шаг - добавление маршрутов в цепочку промежуточного слоя. Это будет сделано в <code>app.js</code>.</p> + +<p>Откройте файл <strong>app.js</strong> и поместите require для маршрута каталог ниже других маршрутов (добавьте третью строку. показанную ниже, после имеющихся двух строк):</p> + +<pre class="brush: js">var indexRouter = require('./routes/index'); +var usersRouter = require('./routes/users'); +<strong>var catalogRouter = require('./routes/catalog'); //Import routes for "catalog" area of site</strong></pre> + +<p>Далее, добавьте маршрут каталога в стек промежуточного слоя после других маршрутов (добавтьте третью строку после имеющихся двух):</p> + +<pre class="brush: js">app.use('/', indexRouter); +app.use('/users', usersRouter); +<strong>app.use('/catalog', catalogRouter); // Add catalog routes to middleware chain.</strong></pre> + +<div class="note"> +<p><strong>Заметка:</strong> Мы добавили модуль каталога в путь<code>'/catalog'</code>. Этот путь будет предшествовать всем путям, определенным в модуле каталога. Например, для доступа к списку книг URL будет таким: <code>/catalog/books/</code>.</p> +</div> + +<p>Вот так. Теперь у нас есть пути и фиктивные функции, подготовленные для всех URL, которые мы собираемся поддерживать на веб-сайте LocalLibrary.</p> + +<h3 id="Проверка_маршрутов">Проверка маршрутов</h3> + +<p>Чтобы проверить маршруты, сначала запустим веб-сайт обычным способом</p> + +<ul> + <li>Обычный способ + <pre class="brush: bash"><code>// Windows +SET DEBUG=express-locallibrary-tutorial:* & npm start + +// macOS or Linux +DEBUG=express-locallibrary-tutorial:* npm start</code> +</pre> + </li> + <li>Если предварительно установлен <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">nodemon</a>, для запуска можно использовать: + <pre><code>// Windows +SET DEBUG=express-locallibrary-tutorial:* & npm <strong>run devstart</strong> + +// macOS or Linux +</code> DEBUG=express-locallibrary-tutorial:* npm <strong style="font-family: inherit; font-size: 1rem;">run devstart</strong> +</pre> + </li> +</ul> + +<p>После запуска перейдите к совокупности URL нашей LocalLibrary, и проверьте, что не появляется страница ошибки (HTTP 404). Небольшая часть наших URL для удобства приводится ниже:</p> + +<ul> + <li><a href="http://localhost:3000/">http://localhost:3000/</a></li> + <li><a href="http://localhost:3000/catalog">http://localhost:3000/catalog</a></li> + <li><a href="http://localhost:3000/catalog/books">http://localhost:3000/catalog/books</a></li> + <li><a href="http://localhost:3000/catalog/bookinstances/">http://localhost:3000/catalog/bookinstances/</a></li> + <li><a href="http://localhost:3000/catalog/authors/">http://localhost:3000/catalog/authors/</a></li> + <li><a href="http://localhost:3000/catalog/genres/">http://localhost:3000/catalog/genres/</a></li> + <li><a href="http://localhost:3000/catalog/book/5846437593935e2f8c2aa226/">http://localhost:3000/catalog/book/5846437593935e2f8c2aa226</a></li> + <li><a href="http://localhost:3000/catalog/book/create">http://localhost:3000/catalog/book/create</a></li> +</ul> + +<h2 id="Итог">Итог</h2> + +<p>Созданы все маршруты для нашего сайта. Созданы также фиктивные функции контроллеров, которые мы полностью реализуем в последующих статьях. Попутно мы изучили массу базовых сведений о маршрутах Express, и ознакомились с некоторыми подходами по структурированию маршрутов и контроллеров.</p> + +<p>В следующей статье мы создадим настоящую страничку приветствия нашего сайта, для чего используем представления (шаблоны) и данные, хранящиеся в наших моделях.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="http://expressjs.com/en/starter/basic-routing.html">Basic routing</a> Основы маршрутизации (документация Express)</li> + <li><a href="http://expressjs.com/en/guide/routing.html">Routing guide</a> Руководство по маршрутизации (документация Express)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/ru/learn/server-side/express_nodejs/skeleton_website/index.html b/files/ru/learn/server-side/express_nodejs/skeleton_website/index.html new file mode 100644 index 0000000000..51af5515d4 --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/skeleton_website/index.html @@ -0,0 +1,507 @@ +--- +title: 'Учебник Express часть 2: Создание скелета сайта' +slug: Learn/Server-side/Express_Nodejs/skeleton_website +translation_of: Learn/Server-side/Express_Nodejs/skeleton_website +--- +<div>{{LearnSidebar}}</div> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}</p> + +<p class="summary">Эта вторая статья в нашем <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">учебнике Express</a> показывает, как создать каркас проекта веб-сайта, который позже можно будет заполнить с помощью путей сайта, шаблонов представлений и обращений к базе данных.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Установить среду разработки Node</a>. Просмотреть учебник Express.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Научиться запускать свои проекты используя <em>Express Application Generator</em>.</td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p>В этой статье показано, как создать каркас сайта с помощью средства <a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a>. Каркас затем можно будет заполнить с помощью путей сайта, шаблонов/представлений и обращений к базе данных. Мы используем это средство для создания основы нашего <a>сайта Local Library</a>. К основе будет добавлен код, необходимый сайту. Создание каркаса чрезвычайно просто -- требуется только вызвать генератор в командной строке, указав имя нового проекта, дополнительно можно указать также движок шаблона сайта и генератор CSS.</p> + +<p>Далее показано, как вызвать генератор приложений, и даётся небольшое пояснение различных вариантов представлений и CSS. Мы поясним структуру каркаса веб-сайта. В конце мы покажем, как запустить веб-сайт, чтобы убедиться, что он работает.</p> + +<div class="note"> +<p><span style="line-height: 1.5;"><strong>Замечание</strong>: </span><em>Express Application Generator</em> — не единственный генератор Express-приложений, и созданный проект --не единственный жизнеспособный способ организации ваших файлов и каталогов. Однако созданный сайт имеет модульную структуру, которую легко понять и расширить. О <em>минимальном</em> Express приложении смотрите <a href="https://expressjs.com/en/starter/hello-world.html">Hello world example</a> в документации Express.</p> +</div> + +<h2 id="Применение_генератора_приложений">Применение генератора приложений</h2> + +<p>Вы уже должны были устанавить <code>express-generator</code>, читая статью <a>установка среды разработки Node</a>. Напомним, что генератор установлен с помощью менеджера пакетов NPM, при выполнении команды:</p> + +<pre class="brush: bash notranslate"><code>npm install express-generator -g</code> +</pre> + +<p><code>E</code><code>xpress-generator </code>имеет ряд параметров, которые можно увидеть, выполнив команду express --help (или express -h):</p> + +<pre class="brush: bash notranslate">> express --help + + Usage: express [options] [dir] + + Options: + + -h, --help output usage information (информация по применению) + --version output the version number (номер версии express) + -e, --ejs add ejs engine support (добавить поддержку движка ejs) + --pug add pug engine support (добавить поддержку движка pug) + --hbs add handlebars engine support (добавить поддержку движка handlebar) + -H, --hogan add hogan.js engine support (добавить поддержку движка hogan.js) + -v, --view <engine> add view <engine> support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade) + (добавить поддержку движков представлений. По умолчанию - jade) + -c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css) + (добавить поддержку движков стилей, по умолчанию - простой CSS) + --git add .gitignore (добавить поддержку .gitignore) + -f, --force force on non-empty directory (работать в каталоге с файлами) +</pre> + +<p>Команда <code>express</code> создаст проект в <em>текущем</em> каталоге с использованием (устаревшего) движка представления <em>Jade</em> и обычного CSS. Если указать <font face="Courier New, monospace">express </font><font face="Courier New, monospace">name</font>, проект будет создан в подкаталоге name текущего каталога. </p> + +<pre class="brush: bash notranslate"><code>express</code></pre> + +<p>Можно выбрать движок представления (шаблон), используя --<code>view; </code><code><font face="Times New Roman, serif">параметр</font></code><code> --</code><code>css </code> позволяет выбрать движок для создания CSS.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Другие опции (<code>--hogan</code>, <code>--ejs</code>, <code>--hbs</code> и пр.) для выбора шаблонизатора устарели. Используйте <code>--view</code> (или<code> -v</code>)!</p> +</div> + +<h3 id="Какой_движок_представлений_следует_использовать">Какой движок представлений следует использовать?</h3> + +<p><em>Express-generator</em><em> </em>дает возможность сконфигурировать несколько популярных движков, включая <a href="https://www.npmjs.com/package/ejs">EJS</a>, <a href="http://github.com/donpark/hbs">Hbs</a>, <a href="https://pugjs.org/api/getting-started.html">Pug</a> (Jade), <a href="https://www.npmjs.com/package/twig">Twig</a>, и <a href="https://www.npmjs.com/package/vash">Vash</a>, но по умолчанию выбран Jade. Экспресс сразу после установки может поддерживать большое количество и других шаблонизаторов.</p> + +<div class="note"> +<p><strong>Заметка:</strong> При желании использовать шаблонизатор, который не поддерживается генератором, просмотрите документацию <a href="https://expressjs.com/en/guide/using-template-engines.html"><font color="#3d7e9a"><font face="x-locale-heading-primary, zillaslab, Palatino, Palatino Linotype, x-locale-heading-secondary, serif"><font size="3">Using template engines with Express</font></font></font></a><font color="#333333"><font face="x-locale-heading-primary, zillaslab, Palatino, Palatino Linotype, x-locale-heading-secondary, serif"><font size="3"> </font></font></font> и документацию для нужного шаблонизатора.</p> +</div> + +<p>Как правило, следует выбрать шаблонизатор, который имеет весь необходимый вам функционал и обеспечивает вам высокую производительность - так же, как вы выбираете любой другой компонент! Некоторые критерии для сравнения шаблонизаторов:</p> + +<ul> + <li>Время до получения результата — если ваша команда уже имела дело с шаблонизатором, то, скоре всего, продуктивнее будет использовать этот шаблонизатор. Если нет, тогда следует учесть все относительные сложности изучения кандидатов в шаблонизаторы.</li> + <li>Популярность и активность — проверьте популярность движка, возможно, у него есть активное сообщество. Очень важно иметь поддержку для движка, если у вас возникнут проблемы в течении жизни вебсайта.</li> + <li>Стиль — некоторые шаблонизаторы используют особую разметку для отображения вставленного контента внутри "обычного" HTML, а другие строят HTML, используя специальный синтаксис (например, используя отступы или блочные имена).</li> + <li>Производительность и время интерпретации.</li> + <li>Особенности — следует выбирать движок с учетом таких особенностей: + <ul> + <li>Наследование макета: позволяет определить базовый шаблон и затем наследовать только те части, которые отличаются для конкретной страницы. Это, как правило, лучший подход, чем создание шаблонов путём включения нескольких необходимых компонентов или создания шаблона с нуля каждый раз.</li> + <li>Поддержка «Include»: позволяет создавать шаблоны, включая другие шаблоны.</li> + <li>Краткий синтаксис управления переменными и циклами.</li> + <li>Возможность фильтровать значения переменных на уровне шаблона (например, делать переменные в верхнем регистре или форматировать значение даты).</li> + <li>Возможность создавать выходные форматы, отличные от HTML (например, JSON или XML).</li> + <li>Поддержка асинхронных операций и потоковой передачи.</li> + <li> Возможность использования как на клиенте, так и на сервере. Возможность применения движка шаблона на клиенте позволяет обслуживать данные и выполнять все действия или их большую часть на стороне клиента.</li> + </ul> + </li> +</ul> + +<div class="note"> +<p><strong>Совет:</strong> В интернете множество ресурсов, которые помогут сравнить различные варианты!</p> +</div> + +<p>Для этого проекта мы используем шаблонизатор <a href="https://pugjs.org/api/getting-started.html">Pug</a> (в прошлом назывался Jade) -- один из популярнейших Express/JavaScript шаблонизаторов, который поддерживается в Express-generator "из коробки".</p> + +<h3 id="Какие_шаблонизаторы_CSS_следует_использовать">Какие шаблонизаторы CSS следует использовать?</h3> + +<p><em>Express Application Generator</em> позволяет создавать проекты, настроенные для применения шаблонизаторов CSS: <a href="http://lesscss.org/">LESS</a>, <a href="http://sass-lang.com/">SASS</a>, <a href="http://compass-style.org/">Compass</a>, <a href="http://stylus-lang.com/">Stylus</a>.</p> + +<div class="note"> +<p><strong>Заметка: </strong>простой<strong> </strong>CSS имеет некоторые ограничения, затрудняющие выполнение задач. Шаблонизаторы CSS позволяют использовать более эффективный подход для создании таблиц стилей CSS, но требуют компиляции файлов таблиц стилей в стандартный CSS для применения в браузере.</p> +</div> + +<p>Как и в случае с шаблонизаторами сайта, следует применять шаблонизатор, обеспечивающий высокую производительность работы. В этом проекте мы используем обычный CSS (по умолчанию), поскольку простота наших требований к CSS не оправдает применение чего-то более сложного.</p> + +<h3 id="Какую_базу_данных_следует_использовать">Какую базу данных следует использовать?</h3> + +<p>Сгенерированный код не использует и не содержит в себе какой-либо базы данных. <em>Express</em> может использовать любой движок <a href="https://expressjs.com/en/guide/database-integration.html">базы данных</a>, который поддерживается <em>Node</em> (<em>Express</em> не предъявляет каких-либо особых требований к базе данных).</p> + +<p>Мы обсудим взаимодействие с базой данных в следующей статье.</p> + +<h2 id="Создание_проекта">Создание проекта</h2> + +<p>Разрабатывая пример - приложение <em>Local Library, </em>мы построим проект с именем <em>express-locallibrary-tutorial. </em>Используем библиотеку шаблонов Pug, а движок CSS применять не будем.</p> + +<p>Выберем место для нового проекта — каталог <font face="Courier New, monospace">express-locallibrary-tutorial - </font><font face="Times New Roman, serif">и выполним</font><font face="Courier New, monospace"> </font>команду:</p> + +<pre class="brush: bash notranslate">express express-locallibrary-tutorial --view=pug +</pre> + +<p>Будет создан каталог <font face="Courier New, monospace">express-locallibrary-tutorial </font><font face="Times New Roman, serif">и выведен список созданных внутри каталога проектных файлов</font>.</p> + +<pre class="brush: bash notranslate"> create : express-locallibrary-tutorial + create : express-locallibrary-tutorial/package.json + create : express-locallibrary-tutorial/app.js + create : express-locallibrary-tutorial/public/images + create : express-locallibrary-tutorial/public + create : express-locallibrary-tutorial/public/stylesheets + create : express-locallibrary-tutorial/public/stylesheets/style.css + create : express-locallibrary-tutorial/public/javascripts + create : express-locallibrary-tutorial/routes + create : express-locallibrary-tutorial/routes/index.js + create : express-locallibrary-tutorial/routes/users.js + create : express-locallibrary-tutorial/views + create : express-locallibrary-tutorial/views/index.pug + create : express-locallibrary-tutorial/views/layout.pug + create : express-locallibrary-tutorial/views/error.pug + create : express-locallibrary-tutorial/bin + create : express-locallibrary-tutorial/bin/www + + install dependencies: + > cd express-locallibrary-tutorial && npm install + + run the app: + > SET DEBUG=express-locallibrary-tutorial:* & npm start</pre> + +<p>После списка файлов генератор выведет инструкции для установки зависимостей (указанных в файле <strong>package.json</strong>) и запуска приложения (инструкции предназначены для Windows; для Linux/Mac OS X они могут слегка отличаться).</p> + +<h2 id="Запускаем_каркас_сайта">Запускаем каркас сайта</h2> + + + +<p>Сейчас у нас есть готовый каркас проекта. Сайт пока ничего не делает, но его стоит запустить, чтобы убедиться в его работоспособности.</p> + + + +<ol> + <li>Прежде всего установим зависимости (команда <code>install</code> запросит все пакеты зависимостей, указанные в файле<strong> package.json</strong>). + + <pre class="brush: bash notranslate">cd express-locallibrary-tutorial +npm install</pre> + </li> + <li>Затем запустим приложение. + <ul> + <li>В Windows используйте команду: + <pre class="brush: bash notranslate">SET DEBUG=express-locallibrary-tutorial:* & npm start</pre> + </li> + <li>В Mac OS X или Linux используйте команду: + <pre class="brush: bash notranslate">DEBUG=express-locallibrary-tutorial:* npm start +</pre> + </li> + </ul> + </li> + <li>Откроем <a href="http://localhost:3000/">http://localhost:3000/</a> в браузере. Мы должны увидеть такую страницу:</li> +</ol> + +<p><img alt="Browser for default Express app generator website" src="https://mdn.mozillademos.org/files/14375/ExpressGeneratorSkeletonWebsite.png" style="display: block; height: 403px; margin: 0px auto; width: 576px;"></p> + +<p>У нас получилось веб-приложение на базе Express, работающее по адресу <em>localhost:3000</em>.</p> + +<div class="note"> +<p><strong>Заметка:</strong> Можно также запустить приложение командой <code>npm start</code>. Переменная DEBUG, указанная в примере, включает логгирование в консоль для дальнейшей отладки. Так, при посещении страницы веб-приложения, вы увидите похожий вывод в консоль:</p> + +<pre class="brush: bash notranslate">>SET DEBUG=express-locallibrary-tutorial:* & npm start + +> express-locallibrary-tutorial@0.0.0 start D:\express-locallibrary-tutorial +> node ./bin/www + + express-locallibrary-tutorial:server Listening on port 3000 +0ms +GET / 200 288.474 ms - 170 +GET /stylesheets/style.css 200 5.799 ms - 111 +GET /favicon.ico 404 34.134 ms - 1335</pre> +</div> + +<h2 id="Обеспечиваем_перезапуск_сервера_при_изменении_файлов">Обеспечиваем<br> + перезапуск сервера при изменении файлов</h2> + +<p>Любые изменения, внесенные на веб-сайт Express, не будут отображаться до перезапуска сервера. Остановка (Ctrl-C) и перезапуск сервера каждый раз после внесения изменений быстро становится раздражающей, поэтому стоит автоматизировать перезапуск.</p> + +<p>Одно из самых простых средств для этого --<br> + <a href="https://github.com/remy/nodemon">nodemon</a>. Его обычно устанавливают глобально (так как это "инструмент"), но сейчас мы устанавим его и будем применять локально как зависимость разработки, так что любые разработчики проекта получат его автоматически при установке приложения. Выполним следующую команду (предполагаем, что мы находимся в корневом каталоге):</p> + +<pre class="brush: bash notranslate">npm install --save-dev nodemon</pre> + + + +<p>Если вы предпочитаете установить nodemon глобально, не только для этого проекта, надо выполнить команду</p> + + + +<pre class="notranslate"><code><font color="#333333"><font face="Consolas, Monaco, Andale Mono, Ubuntu Mono, monospace"><font size="3">npm install -g nodemon</font></font></font></code></pre> + + + +<p>В файле <strong>package.json </strong>проекта появится новый раздел с этой зависимостью (на вашей машине номер версии nodemon может бытьдругим) :</p> + +<pre class="brush: json notranslate"> "devDependencies": { + "nodemon": "^1.11.0" + } +</pre> + +<p>Поскольку nodemon не установлен глобально, его нельзя запустить из командной строки (пока мы не добавим его в путь), но его можно вызвать из сценария NPM, так как NPM знает все об установленных пакетах. Раздел <code>scripts</code> в файле package.json исходно будет содержать одну строку, которая начинается с <code>"start"</code>. Обновите его, поставив запятую в конце строки, и добавьте строку <code>"devstart",</code> показанную ниже:</p> + +<pre class="brush: json notranslate"> "scripts": { + "start": "node ./bin/www"<strong>,</strong> +<strong> "devstart": "nodemon ./bin/www"</strong> + }, +</pre> + +<p>Теперь можно запустить сервер почти так же, как и ранее, но командой npm run devstart:</p> + +<ul> + <li>В Windows:</li> +</ul> + +<pre class="brush: bash notranslate">SET DEBUG=express-locallibrary-tutorial:* & npm <strong>run devstart</strong></pre> + +<ul> + <li>Для macOS или Linux:</li> +</ul> + +<pre class="notranslate"><code>DEBUG=express-locallibrary-tutorial:* npm <strong>run devstart</strong></code></pre> + +<div class="note"> +<p><strong>Заметка:</strong> Сейчас после изменения любого файла проекта сервер будет перезапускаться (или можно самостоятельно перезапустить его, введя <code>rs</code> в командной строке). Вам все равно придется обновить страницу в браузере .</p> + +<p>Теперь мы должны выполнять команду "<code>npm run </code><em><scriptname></em>" а не просто <code>npm start</code>, поскольку "start", это, по сути, команда NPM, сопоставленная сценарию в файле package.json. Можно заменить команду в сценарии "start", но, так как мы хотим использовать nodemon только во время разработки, разумно создать новую команду сценария.</p> +</div> + +<h2 id="Созданный_проект">Созданный проект</h2> + +<p>Давайте посмотрим на созданный проект.</p> + +<h3 id="Структура_каталогов">Структура каталогов</h3> + +<p>После установки зависимостей проект имеет такую структуру файлов (файлы - это элементы <strong>без </strong>префикса"/"). Файл <strong>package.json</strong> определяет имя файла с приложением, сценарии запуска, зависимости и др. Сценарий запуска задает точку входа приложения, у нас -- файл JavaScript <strong>/bin/www</strong>. Этот файл настраивает некоторые обработчики ошибок приложения, а затем загружает <strong>app.js </strong>для выполнения остальной работы. Пути приложения хранятся в отдельных модулях каталога <strong>routes/</strong>. Шаблоны хранятся в каталоге /<strong>views</strong>.</p> + +<pre class="notranslate">/express-locallibrary-tutorial + <strong>app.js</strong> + /bin + <strong>www</strong> + <strong>package.json</strong> + /node_modules + [about 4,500 subdirectories and files] + /public + /images + /javascripts + /stylesheets + <strong>style.css</strong> + /routes + <strong>index.js</strong> + <strong>users.js</strong> + /views + <strong>error.pug</strong> + <strong>index.pug</strong> + <strong>layout.pug</strong> + +</pre> + +<p>Далее файлы описаны более подробно.</p> + +<h3 id="package.json">package.json</h3> + +<p>Файл <strong>package.json </strong>указывает зависимости приложения и содержит другие данные:</p> + +<pre class="brush: json notranslate">{ + "name": "express-locallibrary-tutorial", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www", + "devstart": "nodemon ./bin/www" + }, + "dependencies": { + "body-parser": "~1.15.2", + "cookie-parser": "~1.4.3", + "debug": "~2.2.0", +<strong> "express": "~4.14.0",</strong> + "morgan": "~1.7.0", +<strong> "pug": "~2.0.0-beta6",</strong> + "serve-favicon": "~2.3.0" + }, + "devDependencies": { + "nodemon": "^1.11.0" + } +}</pre> + +<p>Зависимости включают пакет express и пакет для выбранного движка представления (pug). Кроме того, указаны пакеты, полезные во многих веб-приложениях:</p> + +<ul> + <li><a href="https://www.npmjs.com/package/body-parser">body-parser</a>: -- анализирует часть тела входящего запроса HTTP и облегчает извлечение из него различных частей. Например, мы можно читать <code>POST-</code>параметры.</li> + <li><a href="https://www.npmjs.com/package/cookie-parser">cookie-parser</a>: разбирает заголовок и заполняет <code>req.cookies</code> (по сути, дает удобный метод для доступа к информации cookie).</li> + <li><a href="https://www.npmjs.com/package/debug">debug</a>: небольшой отладчик, работающий по образцу методики отладки ядра node.</li> + <li><a href="https://www.npmjs.com/package/morgan">morgan</a>: средство логгирования запросов HTTP для node.</li> + <li><a href="https://www.npmjs.com/package/serve-favicon">serve-favicon</a>: средство обработки <a href="https://en.wikipedia.org/wiki/Favicon">favicon</a> (значка, используемого для представления сайта на вкладках браузера, закладках и т. д).</li> +</ul> + +<p>Раздел "scripts" определяет скрипт" start", выполняемый при запуске сервера командой <code>npm start</code>. Можно видеть, что самом деле выполняется команда node <strong>./bin/www</strong>. Кроме того, определяется script "<em>devstart</em>", который вызывается командой <code>npm run devstart</code>. Запускается тот же файл <strong>./bin/www</strong> ,но командой <em>nodemon</em> вместо <em>node</em>.</p> + +<pre class="notranslate"><code>"scripts": { + "start": "node ./bin/www", + "devstart": "nodemon ./bin/www" + },</code></pre> + +<h3 id="Файл_www">Файл www</h3> + +<p>Файл <strong>/bin/www</strong> – это входная точка приложения. Сначала в файле создается объект основного приложения, расположенного в app.js — выполняется app=<code>require(./</code><code>app</code><code>).</code></p> + +<pre class="brush: js notranslate">#!/usr/bin/env node + +/** + * Module dependencies. + */ + +<strong>var app = require('../app');</strong> +</pre> + +<div class="note"> +<p><strong>Заметка:</strong> <code>require()</code> -- это глобальная функция node для импорта модулей в текущий файл. Для модуля <strong>app.js </strong>указан относительный путь, а расширение файла по умолчанию (.js) опущено.</p> +</div> + +<p>Оставшаяся часть кода настраивает порт сервера node для HTTP (определен в переменной среды или 3000, если не определен), и начинает прослушивание и протоколирование соединений и ошибок сервера. Сейчас вам не требуется дополнительных сведений о коде (все в этом файле шаблонно), но, при желании, его можно посмотреть.</p> + +<h3 id="Файл_app.js">Файл app.js</h3> + +<p>Этот файл создает объект приложения <code>express </code>(с именем<code>app</code>, по соглашению), настраивает приложение и промежуточное ПО, а затем экспортирует приложение из модуля. В приведенном ниже коде показаны только те части файла, которые создают и экспортируют объект приложения:</p> + +<pre class="brush: js notranslate"><code>var express = require('express'); +var app = express(); +... +</code>module.exports = app; +</pre> + +<p>Именно этот экспортированный объект использован в рассмотренном ранее файле www.</p> + +<p>Рассмотрим детали файла app.js. Сначала при помощи require(...) выполняется импорт некоторых полезных библиотек node: <em>express,</em> s<em>erve-favicon</em>, <em>morgan</em>, <em>cookie-parse, body-parser </em>(они ранее были загружены для нашего приложения командой npm install), а также path из основной библиотеки node (применяется для разбора путей каталогов и файлов).</p> + +<pre class="brush: js notranslate">var express = require('express'); +var path = require('path'); +var favicon = require('serve-favicon'); +var logger = require('morgan'); +var cookieParser = require('cookie-parser'); +var bodyParser = require('body-parser'); +</pre> + +<p>Затем require запрашивает модули из каталога путей route. Эти модули и файлы содержат код для обработки конкретного набора соответствующих путей (URL маршрутов). Если мы расширим каркас приложения, например, чтобы получить список книг библиотеки, нам следует добавить новый файл для обработки пути, связанного с книгами.</p> + +<pre class="brush: js notranslate">var index = require('./routes/index'); +var users = require('./routes/users'); +</pre> + +<div class="note"> +<p><strong>Заметка:</strong> Здесь мы только импортируем модули. В действительности эти пути еще не используются — это произойдет в файле несколько позже.</p> +</div> + +<p>Далее, импортированные модули express применяются для создания объекта app, который потом устанавливает движки-шаблоны представления. Установка движков состоит их двух частей. В первой мы задаем значение 'view', указывая папку, в которой будут размещаться шаблоны (у нас это /views). Во второй мы задаем значение движка 'view engine', указывая на библиотеку шаблона (у нас — "pug").</p> + +<pre class="brush: js notranslate">var app = express(); + +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +</pre> + +<p>Следующие строки вызывают app.use(...), чтобы добавить промежуточные (middleware) библиотеки в цепочку обработки запросов. Кроме сторонних библиотек, импортированных ранее, используем библиотеку Express.static, что позволит обрабатывать статические файлы из папки <strong>/public </strong>корня проекта.</p> + +<pre class="brush: js notranslate">// uncomment after placing your favicon in /public +//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); +app.use(logger('dev')); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); +app.use(cookieParser()); +<strong>app.use(express.static(path.join(__dirname, 'public')));</strong> +</pre> + +<p>Теперь, когда промежуточные библиотеки настроены, мы добавляем (импортированный ранее) код обработки путей в цепочку обработки запросов. Импортированный код будет задавать отдельные пути для разных частей сайта:</p> + +<pre class="brush: js notranslate">app.use('/', index); +app.use('/users', users); +</pre> + +<div class="note"> +<p><strong>Заметка:</strong> . пути, указанные выше ('/' и '<code>/users'</code>) рассматриваются как префиксы путей, определенных в импортированных файлах. Так, например, если импортированный модуль users определяет путь для /profile, для доступа следует указать /users/profile. Мы поговорим подробнее о путях в последующей статье.</p> +</div> + +<p>Последняя в файле промежуточная библиотека добавляет методы обработки ошибок и ответов 404 от HTTP.</p> + +<pre class="brush: js notranslate">// catch 404 and forward to error handler +app.use(function(req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +// error handler +app.use(function(err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); +</pre> + +<p>Объект app приложения Express теперь полностью настроен. Остался последний шаг - добавить его к экпортируемым элементам модуля (это позволит импортировать его в файле <strong>/bin/www</strong>).</p> + +<pre class="brush: js notranslate">module.exports = app;</pre> + +<h3 id="Пути_Routes">Пути (Routes)</h3> + +<p>Файл путей /routes/users.js приведен ниже (файлы путей имеют сходную структуру, поэтому нет необходимости приводить также index.js). Сначала загружается модуль Express, затем он используется для получения объекта express.Router. После этого для этого объекта задается путь, и, наконец, объект-роутер экспортируется из модуля (именно это позволяет импортировать файл в app.js):.</p> + +<pre class="brush: js notranslate">var express = require('express'); +var router = express.Router(); + +/* GET users listing. */ +<strong>router.get('/', function(req, res, next) { + res.send('respond with a resource'); +});</strong> + +module.exports = router; +</pre> + +<p>Путь определяет функцию обратного вызова (далее — callback-функцию), которая будет вызвана, когда обнаружится HTTP GET-запрос корректного вида. Образец для сопоставления пути задается при импорте модуля -- ('<code>/users</code>') плюс что-то, определяемое в этом файле ('<code>/</code>'). Иными словами, этот путь будет использован, когда получен URL-запрос <code>/users/</code>.</p> + +<div class="note"> +<p><strong>Совет:</strong> запустите сервер и задайте в браузере URL <a href="http://localhost:3000/users/">http://localhost:3000/users/</a>. Вы должны увидеть<strong> </strong>сообщение: 'respond with a resource'.</p> +</div> + +<p>Стоит отметить, что callback-функция имеет третий аргумент - '<code>next</code>', т. е. является не простой callback-функцией, а callback-функцией промежуточного модуля. Пока третий аргумент не используется, но будет полезен в дальнейшем, если мы захотим создать несколько обработчиков пути <code><font color="#333333"><font face="consolas, Liberation Mono, courier, monospace"><font size="3">'/'</font></font></font></code>.</p> + +<h3 id="Представления_шаблоны">Представления (шаблоны)</h3> + +<p>Файлы преставлений (шаблонов) хранятся в каталоге <strong><font color="#333333"><font face="Arial, x-locale-body, sans-serif"><font size="3">/views </font></font></font></strong><font color="#333333"><font face="Times New Roman, serif"><font size="3">(это указано в </font></font><font face="Courier New, monospace"><font size="3">app.js</font></font><font face="Times New Roman, serif"><font size="3">) и имеют расширение</font></font></font><strong><font color="#333333"><font face="Times New Roman, serif"><font size="3"> </font></font></font></strong><strong>.pug</strong>. Метод <code><a href="http://expressjs.com/en/4x/api.html#res.render">Response.render()</a></code> выполняет указанный шаблон, передавая объекту значение именованной переменной, и затем посылает результат как ответ. В коде из <strong>/routes/index.js</strong> (приводится ниже) можно увидеть, что роут отвечает, используя шаблон "index" с переданным значением переменной "title" из шаблона.</p> + +<pre class="brush: js notranslate">/* GET home page. */ +router.get('/', function(req, res) { + res.render('index', { title: 'Express' }); +}); +</pre> + +<p>Шаблон для пути '/' приведен ниже (файл <strong>index.pug</strong>). О синтаксисе мы поговорим позже. Сейчас важно знать, что переменная title со значением 'Express' помещена в определенное место шаблона.</p> + +<pre class="notranslate">extends layout + +block content + h1= title + p Welcome to #{title} +</pre> + +<h2 id="Мини-тест">Мини-тест</h2> + +<p>Создайте новый путь в <strong>/routes/users.js</strong>, чтобы выводить текст <strong>"</strong><em>You're so cool" </em>или<em> </em><em>"</em><em>Ну, вы крутой!</em><em>" </em>по URL<em> </em><code>/users/cool/</code><em>. </em>Проверьте его, запустив сервер и посетив в браузере <em><a href="http://localhost:3000/users/cool/">http://localhost:3000/users/cool/</a>.</em></p> + +<ul> +</ul> + +<h2 id="Итоги">Итоги</h2> + + + +<p>Сейчас создан каркас проекта <a>Local Library</a>. Мы проверили, что он запускается с использованием Node. Но главное, что вы поняли структуру проекта, и знаете, где и как добавить пути и представления для нашей локальной библиотеки.</p> + +<p lang="ru-RU">Далее мы изменим каркас, чтобы он работал как библиотечный вебсайт</p> + +<h2 id="Смотри_также">Смотри также</h2> + +<ul> + <li><a href="https://expressjs.com/en/starter/generator.html">Express application generator</a> (документация Express)</li> + <li><a href="https://expressjs.com/en/guide/using-template-engines.html">Using template engi nes with Express</a> (документация Express) </li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}</p> diff --git a/files/ru/learn/server-side/express_nodejs/учебник_сайт_local_library/index.html b/files/ru/learn/server-side/express_nodejs/учебник_сайт_local_library/index.html new file mode 100644 index 0000000000..c7e821248e --- /dev/null +++ b/files/ru/learn/server-side/express_nodejs/учебник_сайт_local_library/index.html @@ -0,0 +1,73 @@ +--- +title: 'Учебник Express: сайт Local Library' +slug: Learn/Server-side/Express_Nodejs/Учебник_сайт_local_library +tags: + - Express + - Node + - nodejs + - Введение + - Для начинающих + - Серверная часть + - Учебник +translation_of: Learn/Server-side/Express_Nodejs/Tutorial_local_library_website +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">Первая статья в нашей серии практических уроков объясняет, что вы будете изучать, и предоставит обзор сайта "локальной библиотеки" ("local library"), над которым мы будем работать и развивать в последующих статьях.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Прочтите <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Введение в Express</a>. Для следования статьям вам также надо будет <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">установить среду разработки Node</a>. </td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Представить пример приложения, используемого в этом учебнике, и позволить читателям понять, какие темы будут рассмотрены. </td> + </tr> + </tbody> +</table> + +<h2 id="Обзор">Обзор</h2> + +<p><span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_0">Добро пожаловать в учебник MDN «Local Library» Express (Node), в котором мы разрабатываем веб-сайт, который может использоваться для управления каталогом локальной библиотеки.</span></p> + +<div style="padding-bottom: 30px;"><span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_0">В этой серии обучающих статей вы будете:</span></div> + +<ul> + <li>Использовать инструмент <em>Express Application Generator</em> для создания веб-сайта и скелета приложения.</li> + <li>Запускать и останавливать веб сервер Node.</li> + <li>Использовать базу данных для хранения данных вашего приложения.</li> + <li>Создавать маршруты для запросов различной информации и шаблонов ("представлений") для рендеринга данных в виде HTML для отображения в браузере.</li> + <li>Работать с формами.</li> + <li>Развертывать ваше приложение в производство.</li> +</ul> + +<p>Вы уже имеете знания о некоторых из этих тем и кратко касались других. К концу серии уроков вы должны знать достаточно, чтобы разрабатывать простые приложения Express самостоятельно.</p> + +<h2 id="Сайт_LocalLibrary">Сайт LocalLibrary</h2> + +<p><em>LocalLibrary</em> это название сайта который мы будем создавать и развивать в ходе прохождения этого курса уроков. Как и следовало ожидать, цель сайта - предоставить онлайн-каталог для небольшой локальной библиотеки, где пользователи могут просматривать доступные книги и управлять своими учётными записями.</p> + +<p>Этот пример был тщательно подобран, потому что он может масштабироваться, чтобы отображать насколько можно много или мало записей, и может использоваться для демонстрации почти любой возможности Express. Что ещё более важно, это позволяет нам обеспечить <em>управляемый</em> путь через функциональность, которая вам понадобится на любом веб-сайте:</p> + +<ul> + <li><span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_0">В первых учебных статьях мы определим простую библиотеку, доступную <em>только для просмотра</em>, которую могут использовать члены библиотеки, чтобы узнать, какие книги доступны.</span> <span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_1">Это позволяет нам исследовать операции, общие для почти каждого сайта: чтение и отображение содержимого из базы данных</span>.</li> + <li><span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_0">По мере нашего развития, пример библиотеки, естественно, будет расширяться, чтобы продемонстрировать более продвинутые функции веб-сайта.</span> <span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_1">Например, мы можем расширить библиотеку, чтобы разрешить создание новых книг, и использовать это, чтобы продемонстрировать, как использовать формы, а также поддерживать аутентификацию пользователей</span>.</li> +</ul> + +<p>Несмотря на то, что это очень масштабируемый пример, он называется <em><strong>Local</strong>Library,</em> потому что мы надеемся показать минимальную информацию, которая поможет быстро начать работать с Express. В результате мы будем хранить информацию о книгах, копиях книг, авторов и другой ключевой информации. Однако, мы не будем хранить информацию о других предметах, которые может предоставить библиотека, или предоставить инфраструктуру, необходимую для поддержки нескольких сайтов библиотек или других функций "большой библиотеки".</p> + +<h2 id="Я_застрял_где_я_могу_посмотреть_код">Я застрял, где я могу посмотреть код?</h2> + +<p><span class="s3gt_translate_tooltip_variant" id="s3gt_translate_tooltip_variant_to_id_0">По мере того, как вы работаете над учебником, мы предоставим вам соответствующие фрагменты кода для копирования и вставки в каждой точке, а также будет другой код, который, мы надеемся, вы расширите самостоятельно (с некоторыми рекомендациями).</span></p> + +<p>Если вы застряли, вы можете найти полностью разработанную версию вебсайта <a href="https://github.com/mdn/express-locallibrary-tutorial">на Github</a>.</p> + +<h2 id="Резюме">Резюме</h2> + +<p>Теперь, когда вы знаете немного больше о сайте <em>LocalLIbrary</em> и о том, что мы будем изучать, пришло время приступить к созданию <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">скелета проекта</a>, который будет использован в нашем сайте.</p> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs")}}</p> diff --git a/files/ru/learn/server-side/first_steps/client-server_overview/index.html b/files/ru/learn/server-side/first_steps/client-server_overview/index.html new file mode 100644 index 0000000000..7961d46a24 --- /dev/null +++ b/files/ru/learn/server-side/first_steps/client-server_overview/index.html @@ -0,0 +1,325 @@ +--- +title: Клиент-сервер +slug: Learn/Server-side/First_steps/Client-Server_overview +tags: + - Вступление + - Вступление + - Начинающий + - Начинающий + - Программирование на стороне сервера + - Программирование на стороне сервера + - Руководство + - Руководство + - Сервер + - Сервер + - Учить + - Учить +translation_of: Learn/Server-side/First_steps/Client-Server_overview +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/First_steps/Introduction", "Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</div> + +<p class="summary">Теперь, когда вы знаете цель и потенциальные преимущества программирования на стороне сервера, мы подробно рассмотрим, что происходит, когда сервер получает «динамический запрос» от браузера. Поскольку большая часть серверного кода веб-сайта обрабатывает запросы и ответы аналогичным образом, это поможет вам понять, что нужно делать при написании большей части собственного кода.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Перед стартом:</th> + <td>Базовая компьютерная грамотность. Базовое понимание того, что такое веб-сервер.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Изучить взаимодействие между клиентом и сервером на динамическом веб-сайте и, в частности, узнать, какие действия нужно произвести в коде серверной части.</td> + </tr> + </tbody> +</table> + +<p>В обсуждении нет реального кода, поскольку мы ещё не выбрали, какой именно веб-фреймворк будем использовать для написания нашего кода! Тем не менее, это обсуждение всё ещё очень актуально, поскольку описанное поведение должно быть реализовано вашим серверным кодом независимо от того, какой язык программирования или веб-фреймворк вы выберите.</p> + +<h2 id="Веб-серверы_и_HTTP_для_начинающих">Веб-серверы и HTTP (для начинающих)</h2> + +<p>Веб-браузеры взаимодействуют с <a href="https://developer.mozilla.org/ru/docs/Learn/Common_questions/What_is_a_web_server">веб-серверами</a> при помощи протокола передачи гипертекста (<a href="https://wiki.developer.mozilla.org/ru/docs/Web/HTTP">HTTP</a>). Когда вы кликаете на ссылку на странице, заполняете форму или производите поиск, браузер отправляет на сервер <em>HTTP-запрос</em>.</p> + +<p>Этот запрос включает:</p> + +<ul> + <li>Путь (URL), который определяет целевой сервер и ресурс (например, HTML-файл, конкретная точка данных на сервере или запускаемый инструмент).</li> + <li>Метод, который определяет необходимое действие (например, получить файл, сохранить или обновить какие-либо данные). Различные методы/команды и связанные с ними действия перечислены ниже: + <ul style="list-style-type: circle;"> + <li><code>GET</code> – получить определённый ресурс (например, HTML-файл, содержащий информацию о товаре или список товаров).</li> + <li><code>POST</code> – создать новый ресурс (например, добавить новую статью на вики, добавить новый контакт в базу данных).</li> + <li><code>HEAD</code> – получить метаданные об определённом ресурсе без получения содержания, как это делает запрос <code>GET</code>. Например, вы можете использовать запрос <code>HEAD</code>, чтобы узнать, когда ресурс в последний раз обновлялся, и только потом использовать (более «затратный») запрос <code>GET</code>, чтобы загрузить сам ресурс, если он был изменён.</li> + <li><code>PUT</code> – обновить существующий ресурс (или создать новый, если таковой не существует).</li> + <li><code>DELETE</code> – удалить определённый ресурс.</li> + <li><code>TRACE</code>, <code>OPTIONS</code>, <code>CONNECT</code>, <code>PATCH</code> – эти команды используются для менее популярных/более сложных задач, поэтому пока мы не будем их рассматривать.</li> + </ul> + </li> + <li>Дополнительная информация может быть закодирована в запросе (например, данные HTML-формы). Информация может быть закодирована как: + <ul style="list-style-type: circle;"> + <li>URL-параметры: <code>GET</code> запросы зашифровывают данные в URL-адресе, который отправляется на сервер, путём добавления пар имя/значение в его конец, например, <code>http://mysite.com<strong>?name=Fred&age=11</strong></code>. В этом случае всегда ставится знак вопроса (<code>?</code>), отделяющий основную часть URL-адреса от URL-параметров, знак равно (=), отделяющий каждое имя от соответствующего ему значения, и амперсанд (&), разделяющий пары. URL-параметры, по своей сути, «небезопасны», так как могут быть изменены пользователями и затем отправлены повторно. В результате, URL-параметры /<code>GET</code> запросы не используются для запросов, которые обновляют данные на сервере.</li> + <li><code>POST</code> данные. <code>POST</code> запросы добавляют новые ресурсы, данные которых зашифрованы в теле самого запроса.</li> + <li>Куки-файлы клиентской части. Куки-файлы содержат данные сессий о клиенте, включая ключи, которые сервер может использовать для определения статуса его авторизации и разрешения/права доступа к ресурсам.</li> + </ul> + </li> +</ul> + +<p>Веб-серверы ожидают сообщений с запросами от клиентов, обрабатывают их, когда они приходят и отвечают веб-браузеру через сообщение с HTTP-ответом. Ответ содержит <a href="https://developer.mozilla.org/ru/docs/Web/HTTP/Status">Код статуса HTTP-ответа</a>, который показывает, был ли запрос успешным (например, «<code>200 OK</code>» означает успех, «<code>404 Not Found</code>» если ресурс не может быть найден, «<code>403 Forbidden</code>», если пользователь не имеет права просматривать ресурс, и т. д.). Тело успешного ответа на запрос <code>GET</code> будет содержать запрашиваемый ресурс.</p> + +<p>После того как HTML-страница возвращена, она отрисовывается браузером. Во время этого браузер может обнаружить ссылки на другие ресурсы (например, HTML-страница обычно ссылается на JavaScript и CSS-файлы) и послать отдельные HTTP-запросы для загрузки этих файлов.</p> + +<p>Как статические, так и динамические веб-сайты (речь о которых идёт в следующих разделах) используют точно такой же протокол/шаблоны обмена данными.</p> + +<h3 id="Пример_GET_запросаответа">Пример GET запроса/ответа</h3> + +<p>Вы можете сформировать простой <code>GET</code> запрос кликнув по ссылке или через поиск по сайту (такой как страница поисковой системы). Например, HTTP-запрос, отправленный во время выполнения запроса "client server overview" на сайте MDN, будет во многом похож на текст ниже (он не будет идентичным, потому что части сообщения зависят от вашего браузера/настроек).</p> + +<div class="note"> +<p>Формат HTTP сообщения определён в «веб-стандарте» (<a href="http://www.rfc-editor.org/rfc/rfc7230.txt">RFC7230</a>). Вам не нужно знать этот уровень детализации, но, по крайней мере, теперь вы знаете, откуда это появилось!</p> +</div> + +<h4 id="Запрос">Запрос</h4> + +<p>Каждая строка запроса содержит информацию о запросе. Первая часть называется <strong>заголовок</strong> и содержит важную информацию о запросе, точно так же, как <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_HTML/The_head_metadata_in_HTML">HTML head</a> содержит важную информацию о HTML-документе (но не содержимое документа, которое расположено внутри тэга "body"):</p> + +<pre class="notranslate">GET https://developer.mozilla.org/en-US/search?q=client+server+overview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev HTTP/1.1 +Host: developer.mozilla.org +Connection: keep-alive +Pragma: no-cache +Cache-Control: no-cache +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 +Referer: https://developer.mozilla.org/en-US/ +Accept-Encoding: gzip, deflate, sdch, br +Accept-Language: en-US,en;q=0.8,es;q=0.6 +Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _gat=1; _ga=GA1.2.1688886003.1471911953; ffo=true +</pre> + +<p>Первая и вторая строки содержат большую часть информации, о которой говорилось выше:</p> + +<ul> + <li>Тип запроса (<code>GET</code>).</li> + <li>URL целевого ресурса (<code>/en-US/search</code>).</li> + <li>URL-параметры (<code>q=client%2Bserver%2Boverview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev</code>).</li> + <li>Целевой/хост-вебсайт (developer.mozilla.org).</li> + <li>Конец первой строки также содержит короткую строку, идентифицирующую версию протокола (<code>HTTP/1.1</code>).</li> +</ul> + +<p>Последняя строка содержит информацию о клиентских куки — в данном случае можно увидеть куки, включающие id для управления сессиями (<code>Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; ...</code>).</p> + +<p>Оставшиеся строки содержат информацию об используемом браузере и о видах ответов, которые он может обработать. Например, здесь вы можете увидеть:</p> + +<ul> + <li>Мой браузер (<code>User-Agent</code>) — Mozilla Firefox (<code>Mozilla/5.0</code>).</li> + <li>Он может принимать информацию, упакованную в gzip (<code>Accept-Encoding: gzip</code>).</li> + <li>Он может принимать указанные кодировки (<code>Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7</code>) и языков (<code>Accept-Language: de,en;q=0.7,en-us;q=0.3</code>).</li> + <li>Строка <code>Referer</code> идентифицирует адрес веб-страницы, содержащей ссылку на этот ресурс (то есть источник оригинального запроса, <code>https://developer.mozilla.org/en-US/</code>).</li> +</ul> + +<p>HTTP-запрос может также содержать body, но в данном случае этого нет.</p> + +<h4 id="Ответ">Ответ</h4> + +<p>Первая часть ответа на запрос показана ниже. Заголовок содержит следующую информацию:</p> + +<ul> + <li>Первая строка содержит код ответа <code>200 OK</code>, говорящий о том, что запрос выполнен успешно.</li> + <li>Мы можем видеть, что ответ имеет <code>text/html</code> формат (<code>Content-Type</code>).</li> + <li>Также мы видим, что ответ использует кодировку UTF-8 (<code>Content-Type: text/html; charset=utf-8</code>).</li> + <li>Заголовок также содержит длину ответа (<code>Content-Length: 41823</code>).</li> +</ul> + +<p>В конце сообщения мы видим содержимое <strong>body, </strong>содержащее HTML-код возвращаемого ответа.</p> + +<pre class="brush: html notranslate">HTTP/1.1 200 OK +Server: Apache +X-Backend-Server: developer1.webapp.scl3.mozilla.com +Vary: Accept,Cookie, Accept-Encoding +Content-Type: text/html; charset=utf-8 +Date: Wed, 07 Sep 2016 00:11:31 GMT +Keep-Alive: timeout=5, max=999 +Connection: Keep-Alive +X-Frame-Options: DENY +Allow: GET +X-Cache-Info: caching +Content-Length: 41823 + + + +<!DOCTYPE html> +<html lang="en-US" dir="ltr" class="redesign no-js" data-ffo-opensanslight=false data-ffo-opensans=false > +<head prefix="og: http://ogp.me/ns#"> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=Edge"> + <script>(function(d) { d.className = d.className.replace(/\bno-js/, ''); })(document.documentElement);</script> + ... +</pre> + +<p>Остальная часть заголовка ответа содержит информацию об ответе (например, когда он был сгенерирован), сервере и о том, как он ожидает, что браузер обработает страницу (например, строка <code>X-Frame-Options: DENY</code> говорит браузеру не допускать внедрения этой страницы, если она будет внедрена в {{htmlelement ("iframe")}} на другом сайте).</p> + +<h3 id="Пример_POST_запросаответа">Пример POST запроса/ответа</h3> + +<p>HTTP <code>POST</code> создаётся, когда вы отправляете форму, содержащую информацию, которая должна быть сохранена на сервере.</p> + +<h4 id="Запрос_2">Запрос</h4> + +<p>В приведённом ниже тексте показан HTTP-запрос, сделанный когда пользователь загружает новые данные профиля на этом сайте. Формат запроса почти такой же, как пример запроса <code>GET</code>, показанный ранее, хотя первая строка идентифицирует этот запрос как <code>POST</code>.</p> + +<pre class="brush: html notranslate">POST https://developer.mozilla.org/en-US/profiles/hamishwillee/edit HTTP/1.1 +Host: developer.mozilla.org +Connection: keep-alive +Content-Length: 432 +Pragma: no-cache +Cache-Control: no-cache +Origin: https://developer.mozilla.org +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 +Content-Type: application/x-www-form-urlencoded +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 +Referer: https://developer.mozilla.org/en-US/profiles/hamishwillee/edit +Accept-Encoding: gzip, deflate, br +Accept-Language: en-US,en;q=0.8,es;q=0.6 +Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; _gat=1; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _ga=GA1.2.1688886003.1471911953; ffo=true + +csrfmiddlewaretoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT&user-username=hamishwillee&user-fullname=Hamish+Willee&user-title=&user-organization=&user-location=Australia&user-locale=en-US&user-timezone=Australia%2FMelbourne&user-irc_nickname=&user-interests=&user-expertise=&user-twitter_url=&user-stackoverflow_url=&user-linkedin_url=&user-mozillians_url=&user-facebook_url=</pre> + +<p>Основное различие заключается в том, что URL-адрес не имеет параметров. Как вы можете видеть, информация из формы закодирована в теле запроса (например, новое полное имя пользователя устанавливается с использованием: <code>&user-fullname=Hamish+Willee</code>).</p> + +<h4 id="Ответ_2">Ответ</h4> + +<p>Ответ от запроса показан ниже. Код состояния «<code>302 Found</code>» сообщает браузеру, что сообщение обработано, и что необходим второй HTTP-запрос для загрузки страницы, указанной в поле <code>Location</code>. В остальном информация аналогична информации для ответа на запрос <code>GET</code> .</p> + +<pre class="brush: html notranslate">HTTP/1.1 302 FOUND +Server: Apache +X-Backend-Server: developer3.webapp.scl3.mozilla.com +Vary: Cookie +Vary: Accept-Encoding +Content-Type: text/html; charset=utf-8 +Date: Wed, 07 Sep 2016 00:38:13 GMT +Location: https://developer.mozilla.org/en-US/profiles/hamishwillee +Keep-Alive: timeout=5, max=1000 +Connection: Keep-Alive +X-Frame-Options: DENY +X-Cache-Info: not cacheable; request wasn't a GET or HEAD +Content-Length: 0 +</pre> + +<div class="note"> +<p><strong>На заметку</strong>: HTTP-ответы и запросы, показанные в этих примерах, были захвачены с помощью приложения <a href="https://www.telerik.com/download/fiddler">Fiddler</a>, но вы можете получить аналогичную информацию с помощью веб-снифферов (например, <a href="http://web-sniffer.net/">http://web-sniffer.net/</a>) или с помощью расширений браузера, таких как HttpFox. Вы можете попробовать это сами. Воспользуйтесь любым из предложенных инструментов, а затем перейдите по сайту и отредактируйте информацию профиля, чтобы увидеть различные запросы и ответы. В большинстве современных браузеров также есть инструменты, которые отслеживают сетевые запросы (например, инструмент <a href="https://developer.mozilla.org/en-US/docs/Tools/Network_Monitor">Network Monitor</a> в Firefox).</p> +</div> + +<h2 id="Статические_сайты">Статические сайты</h2> + +<p><em>Статический сайт</em> — это тот, который возвращает тот же жёсткий кодированный контент с сервера всякий раз, когда запрашивается конкретный ресурс. Например, если у вас есть страница о товаре в <code>/static/myproduct1.html</code>, эта же страница будет возвращена каждому пользователю. Если вы добавите ещё один подобный товар на свой сайт, вам нужно будет добавить ещё одну страницу (например, <code>myproduct2.html</code>) и так далее. Это может стать действительно неэффективным — что происходит, когда вы попадаете на тысячи страниц товаров? Вы повторяли бы много кода на каждой странице (основной шаблон страницы, структуру и т. д.), И если бы вы захотели изменить что-либо в структуре страницы — например, добавить новый раздел «связанные товары» — тогда вам придётся менять каждую страницу отдельно.</p> + +<div class="note"> +<p><strong>На заметку</strong>: Статические сайты превосходны, когда у вас небольшое количество страниц и вы хотите отправить один и тот же контент каждому пользователю. Однако их обслуживание может потребовать значительных затрат по мере увеличения количества страниц.</p> +</div> + +<p>Давайте вспомним, как это работает, снова взглянув на диаграмму архитектуры статического сайта, на которую мы смотрели в последней статье.</p> + +<p><img alt="A simplified diagram of a static web server." src="https://mdn.mozillademos.org/files/13841/Basic%20Static%20App%20Server.png"></p> + +<p>Когда пользователь хочет перейти на страницу, браузер отправляет HTTP-запрос <code>GET</code> с указанием URL-адреса его HTML-страницы. Сервер извлекает запрошенный документ из своей файловой системы и возвращает HTTP-ответ, содержащий документ и код состояния <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status">HTTP Response status code</a> <code>200 OK</code> (успех). Сервер может вернуть другой код состояния, например, «<code>404 Not Found</code>», если файл отсутствует на сервере или «<code>301 Moved Permanently</code>», если файл существует, но был перемещён в другое место.</p> + +<p>Серверу для статического сайта нужно будет только обрабатывать GET-запросы, потому что сервер не сохраняет никаких модифицируемых данных. Он также не изменяет свои ответы на основе данных HTTP-запроса (например, URL-параметров или файлов cookie).</p> + +<p>Понимание того, как работают статические сайты, тем не менее полезно при изучении программирования на стороне сервера, поскольку динамические сайты точно так же обрабатывают запросы для статических файлов (CSS, JavaScript, статические изображения и т. д.).</p> + +<h2 id="Динамические_сайты">Динамические сайты</h2> + +<p><em>Динамический сайт</em> — это тот, который может генерировать и возвращать контент на основе конкретного URL-адреса запроса и данных (а не всегда возвращать один и тот же жёсткий код для определённого URL-адреса). Используя пример сайта товара, сервер будет хранить «данные» товара в базе данных, а не отдельные HTML-файлы. При получении <code>GET</code>-запроса для товара сервер определяет идентификатор товара, извлекает данные из базы данных и затем создаёт HTML-страницу для ответа, вставляя данные в HTML-шаблон. Это имеет большие преимущества перед статическим сайтом:</p> + +<p>Использование базы данных позволяет эффективно хранить информацию о товаре с помощью легко расширяемого, изменяемого и доступного для поиска способа.</p> + +<p>Использование HTML-шаблонов позволяет очень легко изменить структуру HTML, потому что это нужно делать только в одном месте, в одном шаблоне, а не через потенциально тысячи статических страниц.</p> + +<h3 id="Анатомия_динамического_запроса">Анатомия динамического запроса</h3> + +<p>В этом разделе представлен пошаговый обзор «динамического» цикла HTTP-запроса и ответа, основываясь на том, что мы рассмотрели в последней статье, с гораздо более подробной информацией. Чтобы не отдаляться от практики, мы будем использовать контекст веб-сайта менеджера спортивной команды, где тренер может выбрать имя своей команды и размер команды в HTML-форме и вернуться к предлагаемому «лучшему составу» для своей следующей игры.</p> + +<p>На приведённой ниже диаграмме показаны основные элементы веб-сайта «team coach», а также пронумерованные ярлыки для последовательности операций, когда тренер обращается к списку «лучших команд». Частями сайта, которые делают его динамичным, являются <em>веб-приложение</em> (так мы будем ссылаться на серверный код, обрабатывающий HTTP-запросы и возвращающие HTTP-ответы), <em>база данных</em>, которая содержит информацию об игроках, командах, тренерах и их отношениях, и <em>HTML-шаблоны</em>.</p> + +<p><img alt="This is a diagram of a simple web server with step numbers for each of step of the client-server interaction." src="https://mdn.mozillademos.org/files/13829/Web%20Application%20with%20HTML%20and%20Steps.png" style="height: 584px; width: 1226px;"></p> + +<p>После того, как тренер отправит форму с именем команды и количеством игроков, последовательность операций будет следующей:</p> + +<ol> + <li>Веб-браузер отправит HTTP-запрос <code>GET</code> на сервер с использованием базового URL-адреса ресурса (<code>/best</code>) и кодирования номера команды и игрока в форме URL-параметров (например, <code>/best?team=my_team_name&show=11)</code> или как часть URL-адреса (например, <code>/best/my_team_name/11/</code>). Запрос <code>GET</code> используется, потому что речь идёт только о запросе выборки данных (а не об их изменении).</li> + <li><em>Веб-сервер</em> определяет, что запрос является «динамическим» и пересылает его в <em>веб-приложение</em> для обработки (веб-сервер определяет, как обрабатывать разные URL-адреса на основе правил сопоставления шаблонов, определённых в его конфигурации).</li> + <li><em>Веб-приложение</em> определяет, что цель запроса состоит в том, чтобы получить «лучший список команд» на основе URL (<code>/best/</code>) и узнать имя команды и количество игроков из URL-адреса. Затем <em>веб-приложение</em> получает требуемую информацию из базы данных (используя дополнительные «внутренние» параметры, чтобы определить, какие игроки являются «лучшими», и, возможно, определяя личность зарегистрированного тренера из файла cookie на стороне клиента).</li> + <li><em>Веб-приложение</em> динамически создаёт HTML-страницу, помещая данные (из <em>базы данных</em>) в заполнители внутри HTML-шаблона.</li> + <li><em>Веб-приложение</em> возвращает сгенерированный HTML в веб-браузер (через <em>веб-сервер</em>) вместе с кодом состояния HTTP 200 («успех»). Если что-либо препятствует возврату HTML, <em>веб-приложение</em> вернёт другой код, например, «404», чтобы указать, что команда не существует.</li> + <li>Затем веб-браузер начнёт обрабатывать возвращённый HTML, отправив отдельные запросы, чтобы получить любые другие файлы CSS или JavaScript, на которые он ссылается (см. шаг 7).</li> + <li>Веб-сервер загружает статические файлы из файловой системы и возвращает их непосредственно в браузер (опять же, правильная обработка файлов основана на правилах конфигурации и сопоставлении шаблонов URL).</li> +</ol> + +<p>Операция по обновлению записи в базе данных будет обрабатываться аналогичным образом, за исключением того, что, как и любое обновление базы данных, HTTP-запрос из браузера должен быть закодирован как запрос <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">POST</span></font>.</p> + +<h3 id="Выполнение_другой_работы">Выполнение другой работы</h3> + +<p>Задача <em>веб-приложения</em> — получать HTTP-запросы и возвращать HTTP-ответы. Хотя взаимодействие с базой данных для получения или обновления информации является очень распространённой задачей, код может делать другие вещи одновременно или вообще не взаимодействовать с базой данных.</p> + +<p>Хорошим примером дополнительной задачи, которую может выполнять <em>веб-приложение</em>, является отправка электронной почты пользователям для подтверждения их регистрации на сайте. Сайт также может выполнять протоколирование или другие операции.</p> + +<h3 id="Возвращение_чего-то_другого_кроме_HTML">Возвращение чего-то другого, кроме HTML</h3> + +<p>Серверный код сайта может возвращать не только HTML-фрагменты и файлы в ответе. Он может динамически создавать и возвращать другие типы файлов (текст, PDF, CSV и т. д.) или даже данные (JSON, XML и т. д.).</p> + +<p>Идея вернуть данные в веб-браузер, чтобы он мог динамически обновлять свой собственный контент ({{glossary("AJAX")}}) существует довольно давно. Совсем недавно «Одностраничные приложения» стали популярными, где весь сайт написан с одним HTML-файлом, который динамически обновляется по мере необходимости. Веб-сайты, созданные с использованием приложений такого рода, переносят большие вычислительные затраты с сервера на веб-браузер и приводят к тому, что веб-сайты, ведут себя больше как нативные приложения (очень отзывчивые и т. д.).</p> + +<h2 id="Веб-фреймворки_упрощают_веб-программирование_на_стороне_сервера">Веб-фреймворки упрощают веб-программирование на стороне сервера</h2> + +<p>Веб-фреймворки на стороне сервера делают написание кода для обработки описанных выше операций намного проще.</p> + +<p>Одной из наиболее важных операций, которые они выполняют, является предоставление простых механизмов для сопоставления URL-адресов для разных ресурсов/страниц с конкретными функциями обработчика. Это упрощает сохранение кода, связанного с каждым типом ресурса, отдельно от остального. Это также имеет преимущества с точки зрения обслуживания, поскольку вы можете изменить URL-адрес, используемый для доставки определённой функции в одном месте, без необходимости изменять функцию обработчика.</p> + +<p>Для примера рассмотрим следующий код Django (Python), который связывает два URL-шаблона с двумя функциями просмотра. Первый шаблон проверяет, что HTTP-запрос с URL-адресом ресурса <code>/best</code> будет передан функции с именем <code>index()</code> в модуле <code>views</code>. Запрос, который имеет шаблон «<code>/best/junior</code>», вместо этого будет передан функции просмотра <code>junior()</code>.</p> + +<pre class="brush: python notranslate"># file: best/urls.py +# + +from django.conf.urls import url + +from . import views + +urlpatterns = [ + # example: /best/ + url(r'^$', views.index), + # example: /best/junior/ + url(r'^junior/$', views.junior), +]</pre> + +<div class="note"> +<p><strong>На заметку</strong>: Первые параметры в функциях <code>url()</code> могут выглядеть немного необычно (например, <code>r'^junior/$'</code>, потому что они используют метод сопоставления шаблонов под названием «регулярные выражения» (RegEx или RE). Вам не нужно знать, как работают регулярные выражения на этом этапе, кроме того, что они позволяют нам сопоставлять шаблоны в URL-адресе (а не жёстко закодированные значения выше) и использовать их в качестве параметров в наших функциях просмотра. В качестве примера, действительно простой RegEx может говорить «соответствовать одной заглавной букве, за которой следуют от 4 до 7 строчных букв».</p> +</div> + +<p>Веб-фреймворк также упрощает функцию просмотра для получения информации из базы данных. Структура наших данных определяется в моделях, которые являются классами Python, которые определяют поля, которые должны храниться в основной базе данных. Если у нас есть модель с именем <em>Team</em> с полем «<em>team_type</em>», мы можем использовать простой синтаксис запроса, чтобы получить все команды, имеющие определённый тип.</p> + +<p>В приведённом ниже примере представлен список всех команд, у которых есть точный (с учётом регистра) <code>team_type</code> «junior» («младший») — обратите внимание на формат: имя поля (<code>team_type</code>), за которым следует двойной знак подчёркивания, а затем тип соответствия для использования (в этом случае <code>exact</code> («точное»)). Существует много других типов соответствия, и мы можем объединить их. Мы также можем контролировать порядок и количество возвращаемых результатов.</p> + +<pre class="brush: python notranslate">#best/views.py + +from django.shortcuts import render + +from .models import Team + + +def junior(request): + list_teams = Team.objects.filter(team_type__exact="junior") + context = {'list': list_teams} + return render(request, 'best/index.html', context) +</pre> + +<p>После того, как функция <code>junior()</code> получает список младших команд, она вызывает функцию <code>render()</code>, передавая исходный <code>HttpRequest</code>, HTML-шаблон и объект «context», определяющий информацию, которая должна быть включена в шаблон. Функция <code>render()</code> — это функция удобства, которая генерирует HTML с использованием контекста и HTML-шаблона и возвращает его в объект <code>HttpResponse</code>.</p> + +<p>Очевидно, что веб-фреймворки могут помочь вам в решении многих других задач. В следующей статье мы обсудим намного больше преимуществ и некоторые популярные варианты веб-фреймворков.</p> + +<h2 id="Резюме">Резюме</h2> + +<p>На этом этапе вы должны хорошо ознакомиться с операциями, которые должен выполнять серверный код, и знать некоторые способы, с помощью которых веб-фреймворк на стороне сервера может сделать это проще.</p> + +<p>В следующем модуле мы поможем вам выбрать лучший веб-фреймворк для вашего первого сайта.</p> + +<p>{{PreviousMenuNext ("Learn/Server-side/First_steps/Introduction", "Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</p> diff --git a/files/ru/learn/server-side/first_steps/index.html b/files/ru/learn/server-side/first_steps/index.html new file mode 100644 index 0000000000..91512b5957 --- /dev/null +++ b/files/ru/learn/server-side/first_steps/index.html @@ -0,0 +1,49 @@ +--- +title: Первые шаги в программировании веб-сайтов на стороне сервера +slug: Learn/Server-side/First_steps +tags: + - Beginner + - CodingScripting + - Guide + - Intro + - Landing + - Learn + - NeedsTranslation + - Server-side programming + - TopicStub +translation_of: Learn/Server-side/First_steps +--- +<div>{{LearnSidebar}}</div> + +<p>В этом модуле, посвященном программированию на стороне сервера, мы ответим на несколько фундаментальных вопросов о программировании серверной части: «что это такое?», «чем оно отличается от программирования клиентской части?» и «почему оно так полезно?». Затем последует обзор некоторых самых популярных веб-фреймворков для серверной части и руководство по выбору наиболее подходящего фреймворка для создания вашего первого сайта. Наконец, мы завершим этот модуль вводной статьей о безопасности веб-сервера.</p> + +<h2 id="Прежде_чем_начать">Прежде чем начать</h2> + +<p>Для того, чтобы начать этот модуль, вам не нужно иметь никаких знаний о программировании серверной части или даже о любом виде программирования.</p> + +<p>Вам нужно понимать "как работает веб". Мы рекомендуем вам сперва прочесть следующие темы:</p> + +<ul> + <li><a href="/ru/docs/Learn/Common_questions/What_is_a_web_server">Что такое веб-сервер</a></li> + <li><a href="/ru/docs/Learn/Common_questions/What_software_do_I_need">Какое программное обеспечение мне нужно для создания сайта?</a></li> + <li><a href="/ru/docs/Learn/Common_questions/Upload_files_to_a_web_server">Как загружать файлы на веб-сервер?</a></li> +</ul> + +<p>С этими базовыми знаниями вы будете готовы работать с модулями этого раздела.</p> + +<h2 id="Руководства">Руководства</h2> + +<dl> + <dt><a href="/ru/docs/Learn/Server-side/First_steps/Introduction">Введение в серверную часть</a></dt> + <dd>Добро пожаловать на курс программирования серверной части MDN для начинающих! В этой первой статье мы посмотрим на программирование серверной части на высоком уровне, отвечая на вопросы такие как: "что это такое?", "чем оно отличается от программирования клиентской части?" и "почему это настолько востребовано?". После прочтения этой статьи вы будуте понимать всю дополнительную мощь, доступную веб-сайтам посредством программирования на стороне сервера.</dd> + <dt><a href="/ru/docs/Learn/Server-side/First_steps/Client-Server_overview">Обзор Клиент-Сервера</a></dt> + <dd>Теперь, когда вы познакомились с целью и потенциальными преимуществами программирования серверной части, мы собираемся узнать в подробностях, что случится, когда сервер получит "динамический запрос" от браузера. Так как большинство программ серверной части обрабатывает запросы и ответы практически одинаково, это поможет вам понять, что нужно делать при написании собственного кода.</dd> + <dt><a href="/ru/docs/Learn/Server-side/First_steps/Web_frameworks">Фреймворки серверной части</a></dt> + <dd>Последняя статья рассказывает о том, что нужно делать веб-приложению серверной стороны для ответа на запросы от веб-браузера. Мы покажем здесь, как веб-фреймворки могут упростить эти задачи и поможем вам подобрать подходящий фреймворк для вашего первого серверного веб-приложения.</dd> + <dt><a href="/ru/docs/Learn/Server-side/First_steps/Website_security">Безопасность веб-сайта</a></dt> + <dd>Безопасность веб-сайта требует бдительности на всех этапах проектирования сайта и его использования. Эта вводная статья не сделает из вас гуру безопасности сайтов, но поможет узнать, какие первые важные шаги вы можете предпринять для повышения устойчивости вашего веб-приложения против наиболее распространенных угроз.</dd> +</dl> + +<h2 id="Аттестация">Аттестация</h2> + +<p>Этот "обзорный" модуль не содержит никакой аттестации, поскольку мы даже не прилагаем здесь для вас никакого кода. Мы действительно надеемся, что на текущем этапе у вас сформировалось четкое понимание того, какие виды функционала вы можете предоставить, используя программирование на стороне сервера, и вы уже приняли решение по поводу фреймворка, который вы будете использовать для создания вашего первого сайта.</p> diff --git a/files/ru/learn/server-side/first_steps/introduction/index.html b/files/ru/learn/server-side/first_steps/introduction/index.html new file mode 100644 index 0000000000..967d1157a7 --- /dev/null +++ b/files/ru/learn/server-side/first_steps/introduction/index.html @@ -0,0 +1,217 @@ +--- +title: Введение в серверную часть +slug: Learn/Server-side/First_steps/Introduction +tags: + - Бэкенд + - Введение + - Начинающий + - Руководство + - Сервер + - Серверная часть +translation_of: Learn/Server-side/First_steps/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}</div> + +<p class="summary"><span class="seoSummary">Добро пожаловать на курс для начинающих по программированию серверной части сайта! В этой первой статье мы рассмотрим программирование на стороне сервера с высокого уровня, отвечая на такие вопросы, как «что это»?, «как это отличается от программирования на стороне клиента»? и «почему это так полезно»? После прочтения этой статьи вы поймёте дополнительные возможности, доступные веб-сайтам посредством программирования на стороне сервера. </span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Перед стартом:</th> + <td>Базовая компьютерная грамотность. Базовое понимание, что такое веб-сервер.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Ознакомиться с тем, что такое программирование серверной части, на что оно способно и чем отличается от программирования клиентской части.</td> + </tr> + </tbody> +</table> + +<p>Большинство крупных веб-сайтов используют программирование серверной части чтобы динамично отображать различные данные при необходимости, в основном взятые из базы данных, располагающейся на сервере и отправляемые клиенту для отображения через некоторый код (например, HTML и JavaScript).</p> + +<p>Возможно, самая значительная польза программирования серверной части в том, что оно позволяет формировать контент веб-сайта под конкретного пользователя. Динамические сайты могут выделять контент, который более актуален в зависимости от предпочтений и привычек пользователя. Это также может упростить использование сайтов за счёт сохранения личных предпочтений и информации, например, повторного использования сохранённых данных кредитной карты для оптимизации последующих платежей.</p> + +<p>Это также даёт возможность взаимодействовать с пользователем сайта, посылая уведомления и обновления по электронной почте или по другим каналам. Все эти возможности позволяют глубже взаимодействовать с пользователями.</p> + +<p>В современном мире веб-разработки настоятельно рекомендуется узнать о разработке на стороне сервера.</p> + +<h2 id="Что_такое_программирование_серверной_части_сайта">Что такое программирование серверной части сайта?</h2> + +<p>Веб-браузеры взаимодействуют с <a href="/ru/docs/Learn/Common_questions/What_is_a_web_server">веб-серверами</a> при помощи гипертекстового транспортного протокола ({{glossary("HTTP")}}). Когда вы нажимаете на ссылку на веб-странице, заполняете форму или запускаете поиск, <strong>HTTP-запрос </strong> отправляется из вашего браузера на целевой сервер.</p> + +<p>Запрос включает в себя URL, определяющий затронутый ресурс, метод, определяющий требуемое действие (например, получить, удалить или опубликовать ресурс) и может включать дополнительную информацию, закодированную в параметрах URL (пары поле-значение, оправленные как <a href="https://en.wikipedia.org/wiki/Query_string">строка запроса</a>), как POST запрос (данные, отправленные методом <a href="/en-US/docs/Web/HTTP/Methods/POST">HTTP POST</a>) или в {{glossary("Cookie", "куки-файлах")}}.</p> + +<p>Веб-серверы ожидают сообщений с клиентскими запросами, обрабатывают их по прибытию и отвечают веб-браузеру при помощи ответного HTTP сообщения (<strong>HTTP-ответ</strong>). Ответ содержит строку состояния, показывающую, был ли запрос успешным или нет (например, «HTTP/1.1 200 OK» в случае успеха).</p> + +<p>Тело успешного ответа на запрос может содержать запрашиваемые данные (например, новую HTML-страницу или изображение, и т. п.), который может отображаться через веб-браузер.</p> + +<h3 id="Статические_сайты">Статические сайты</h3> + +<p>Схема ниже показывает базовую архитектуру веб-сервера для <em>статического сайта</em> (статический сайт — это тот, который возвращает одно и то же жёстко закодированное содержимое с сервера всякий раз, когда запрашивается конкретный ресурс). Когда пользователь хочет перейти на страницу, браузер отправляет HTTP-запрос «GET» с указанием его URL. </p> + +<p>Сервер извлекает запрошенный документ из своей файловой системы и возвращает HTTP-ответ, содержащий документ и <a href="https://developer.mozilla.org/ru/docs/Web/HTTP/Status#Successful_responses">успешный статус</a> (обычно 200 OK). Если файл не может быть извлечён по каким-либо причинам, возвращается статус ошибки (смотри <a href="https://developer.mozilla.org/ru/docs/Web/HTTP/Status#Client_error_responses">ошибки клиента</a> и <a href="https://developer.mozilla.org/ru/docs/Web/HTTP/Status#Server_error_responses">ошибки сервера</a>).</p> + +<p><img alt="A simplified diagram of a static web server." src="https://mdn.mozillademos.org/files/13841/Basic%20Static%20App%20Server.png" style="height: 223px; width: 800px;"></p> + +<h3 id="Динамические_сайты">Динамические сайты</h3> + +<p>Динамический веб-сайт — это тот, где часть содержимого ответа генерируется динамически только при необходимости. На динамическом веб-сайте HTML-страницы обычно создаются путём вставки данных из базы данных в заполнители в HTML-шаблонах (это гораздо более эффективный способ хранения большого количества контента, чем использование статических сайтов).</p> + +<p>Динамический сайт может возвращать разные данные для URL-адреса на основе информации, предоставленной пользователем или сохранёнными настройками, и может выполнять другие операции, как часть возврата ответа (например, отправку уведомлений).</p> + +<p>Большая часть кода для поддержки динамического веб-сайта должна выполняться на сервере. Создание этого кода известно, как «<strong>программирование серверной части</strong>» (или иногда «<strong>программирование бэкенда</strong>»).</p> + +<p>Схема ниже показывает простую архитектуру <em>динамического сайта</em>. Как и на предыдущей схеме, браузеры отправляют HTTP-запросы на сервер, затем сервер обрабатывает запросы и возвращает соответствующие HTTP-ответы.</p> + +<p>Запросы статических ресурсов обрабатываются так же, как и для статических сайтов (статические ресурсы — это любые файлы, которые не меняются, обычно это: CSS, JavaScript, изображения, предварительно созданные PDF-файлы и прочее).</p> + +<p><img alt="A simplified diagram of a web server that uses server-side programming to get information from a database and construct HTML from templates. This is the same diagram as is in the Client-Server overview." src="https://mdn.mozillademos.org/files/13839/Web%20Application%20with%20HTML%20and%20Steps.png"></p> + +<p>Запросы динамических данных отправляются (2) в код серверной части (показано на диаграмме как <em>Веб-приложение</em>). Для «динамических запросов» сервер интерпретирует запрос, читает необходимую информацию из базы данных (3), комбинирует извлечённые данные с шаблонами HTML и возвращает ответ, содержащий сгенерированный HTML (5, 6).</p> + +<div> +<h2 id="Одинаково_ли_программирование_серверной_части_и_клиентской">Одинаково ли программирование серверной части и клиентской?</h2> +</div> + +<p>Теперь обратим внимание на код, задействованный в серверной части и клиентской части. В каждом случае код существенно различается:</p> + +<ul> + <li>Они имеют различные цели и назначение.</li> + <li>Как правило, они не используют одни и те же языки программирования (исключение составляет JavaScript, который можно использовать на стороне сервера и клиента).</li> + <li>Они выполняются в разных средах операционной системы.</li> +</ul> + +<p>Код, который выполняется в браузере, известный как <strong>код клиентской части</strong>, прежде всего связан с улучшением внешнего вида и поведения отображаемой веб-страницы. Это включает в себя выбор и стилизацию компонентов пользовательского интерфейса, создание макетов, навигацию, проверку форм и т. д. Напротив, программирование веб-сайта на стороне сервера в основном включает выбор содержимого, которое возвращается браузеру в ответ на запросы. Код на стороне сервера обрабатывает такие задачи, как проверка отправленных данных и запросов, использование баз данных для хранения и извлечения данных и отправка правильных данных клиенту по мере необходимости.</p> + +<p>Код клиентской части написан с использованием <a href="https://developer.mozilla.org/ru/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">HTML</a>, <a href="https://developer.mozilla.org/ru/docs/Learn/CSS">CSS</a> и <a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript">JavaScript</a> — он запускается в веб-браузере и практически не имеет доступа к базовой операционной системе (включая ограниченный доступ к файловой системе).</p> + +<p>Веб-разработчики не могут контролировать, какой браузер может использовать каждый пользователь для просмотра веб-сайта — браузеры обеспечивают противоречивые уровни совместимости с функциями кода на стороне клиента, и одной из задач программирования на стороне клиента является изящная обработка различий в поддержке браузера.</p> + +<p>Код серверной части может быть написан на любом количестве языков программирования — примеры популярных языков серверной части включают в себя PHP, Python, Ruby, C# и NodeJS (JavaScript). Код серверной части имеет полный доступ к операционной системе сервера, и разработчик может выбрать какой язык программирования (и какую версию) он хотел бы использовать.</p> + +<p>Разработчики обычно пишут свой код, используя <strong>веб-фреймворки</strong>. Веб-фреймворки — это наборы функций, объектов, правил и других конструкций кода, предназначенных для решения общих проблем, ускорения разработки и упрощения различных типов задач, стоящих в конкретной области.</p> + +<p>И снова, поскольку и клиентская и серверная части используют фреймворки, области очень разные и, следовательно, фреймворки тоже разные. Фреймворки клиентской части упрощают вёрстку и представление данных, тогда как фреймворки серверной части обеспечивают много «обычного» функционала веб-сервера, который вы, возможно, в противном случае, должны были осуществлять самостоятельно (например, поддержка сессий, поддержка пользователей и аутентификация, простой доступ к базе данных, шаблонам библиотек и т. д.).</p> + +<div class="note"> +<p><strong>На заметку</strong>: Фреймворки клиентской части часто используются для ускорения написания кода клиентской части, но вы также можете решить писать весь код руками; на самом деле, написание кода руками может быть более быстрым и эффективным, если вам нужен небольшой простой веб-сайт UI.</p> + +<p>И, наоборот, вы практически никогда не посмотрите в сторону написания кода серверной части веб-приложения без фреймворка: осуществление жизненно важной функции, такой как HTTP сервер действительно сложно сделать с нуля, скажем, на Python, но веб-фреймворки для Python, такие как Django, обеспечивают это из коробки наряду с другими полезными инструментами.</p> +</div> + +<div> +<h2 id="Что_можно_сделать_в_серверной_части">Что можно сделать в серверной части?</h2> + +<p>Программирование серверной части очень полезно поскольку позволяет <em>эффективно</em> доставлять информацию, составленную для индивидуальных пользователей и, таким образом, создавать намного лучший опыт использования.</p> + +<p>Компании, такие как Amazon, используют программирование серверной части для построения исследовательских результатов для товаров, формирования целевого предложения, основанного на предпочтениях клиента и предыдущих покупках, упрощения заказов и т. д. Банки используют программирование серверной части, чтобы хранить учётную информацию и позволять только авторизованным пользователям просматривать и совершать транзакции. Другие сервисы, такие как Facebook, Twitter, Instagram и Wikipedia используют бэкэнд, чтобы выделять, распространять и контролировать доступ к интересному контенту.</p> +</div> + +<p>Некоторые типичные применения и выгоды бэкэнда перечислены ниже. Вы заметите, что есть некоторое пересечение!</p> + +<h3 id="Эффективное_хранение_и_доставка_информации">Эффективное хранение и доставка информации</h3> + +<p>Представьте, сколько товаров доступно на Amazon, и представьте, сколько постов было написано на Facebook? Создание статической страницы для каждого товара или поста было бы абсолютно неэффективным.</p> + +<p>Программирование серверной части позволяет вместо этого хранить информацию в базе данных и динамически создавать и возвращать HTML и другие типы файлов (например, PDF, изображения, и т. д.). Также есть возможность просто вернуть данные ({{glossary("JSON")}}, {{glossary("XML")}}, и т. д.) для отображения, используя подходящий фреймворк клиентской части (это уменьшает загрузку процессора на сервере и количество передаваемых данных).</p> + +<p>Сервер не ограничен в отправке информации из баз данных и может вместо этого возвращать результат инструментов программного обеспечения или данные из сервисов коммуникации. Контент даже может быть целевым относительно устройства клиента, который его получает.</p> + +<p>Из-за того, что информация находится в базе данных, её также можно легко передать и обновить через другие бизнес системы (например, отслеживание).</p> + +<div class="note"> +<p><strong>На заметку:</strong> Вам не нужно сильно напрягать своё воображение, чтобы увидеть достоинства кода серверной части для эффективного хранения и передачи информации:</p> + +<ol> + <li>Зайдите на <a href="https://www.amazon.com/">Amazon</a> или в другой интернет-магазин.</li> + <li>Введите в поиск несколько ключевых слов и заметьте, как структура страницы не изменилась, тогда как результаты изменились.</li> + <li>Откройте два или три разных товара. Заметьте, что они имеют схожую структуру и внешний вид, но содержимое для разных товаров было вставлено из базы данных.</li> +</ol> + +<p>Для обычного поиска (например, «рыба») вы можете увидеть буквально миллионы найденных значений. Использование базы данных позволяет им храниться и передаваться эффективно, и это позволяет контролировать представление информации всего в одном месте.</p> +</div> + +<h3 id="Настраиваемый_пользовательский_опыт_взаимодействия">Настраиваемый пользовательский опыт взаимодействия</h3> + +<p>Серверы могут хранить и использовать информацию о клиентах чтобы поставлять удобный и сделанный индивидуально пользовательский опыт взаимодействия. Например, многие сайты хранят данные кредитных карт, чтобы не нужно было вводить их повторно. Сайты, наподобие Google Maps, могут использовать сохранённое и текущее местоположение для предоставления информации о маршруте, а также историю поиска или путешествий для выделения местных предприятий в результатах поиска.</p> + +<p>Более глубокий анализ привычек пользователя может быть использован для прогнозирования их интересов и дальнейших настроек ответов и уведомлений, например, предоставление списка ранее посещённых популярных мест, которые вы, возможно, захотите найти на карте.</p> + +<div class="note"> +<p><strong>На заметку:</strong> <a href="https://maps.google.com/">Google Maps</a> сохраняет вашу историю поиска и посещений. Часто посещаемые или часто вводимые в поиск локации выделяются больше, чем остальные.</p> + +<p>Результаты поиска Google оптимизируются на основе прыдыдущего поиска.</p> + +<ol> + <li> Перейдите в <a href="https://google.com/">поиск Google</a>.</li> + <li> Произведите поиск по слову «футбол».</li> + <li> Теперь попробуйте ввести «любимое» в поисковой строке и понаблюдайте, как работают подсказки автозаполнения поиска.</li> +</ol> + +<p>Стечение обстоятельств? Нет!</p> +</div> + +<h3 id="Контролируемый_доступ_к_контенту">Контролируемый доступ к контенту</h3> + +<p>Программирование серверной части позволяет сайтам ограничивать доступ авторизованным пользователям и предоставлять только ту информацию, которую пользователю разрешено видеть.</p> + +<p>Реальные примеры:</p> + +<ul> + <li>Социальные сети, такие как Facebook, позволяют пользователям полностью контролировать свои данные, но только своим друзьям разрешать просматривать или комментировать их. Пользователь определяет, кто может просматривать его данные и, более того, чьи данные появляются на его стене. Авторизация — центральная часть опыта взаимодействия.</li> + <li>Сайт, на котором вы находитесь прямо сейчас, контролирует доступ к контенту: статьи видны всем, но только авторизованные пользователи могут редактировать контент. Чтобы проверить это, нажмите на кнопку «Редактировать» в верхней части страницы, и, если вы авторизованы, вы увидите редакторский интерфейс, а если нет — вас перенаправит на страницу авторизации.</li> +</ul> + +<div class="note"> +<p><strong>На заметку:</strong> Рассмотрим другие реальные примеры, где доступ к контенту контролируется. Например, что вы можете увидеть, если зайдёте на сайт вашего банка? Авторизуйтесь через вашу учётную запись, и какую дополнительную информацию вы можете просматривать и редактировать? Что за информацию вы можете увидеть, которую может редактировать только банк?</p> +</div> + +<h3 id="Хранение_информации_о_сессиисостоянии">Хранение информации о сессии/состоянии</h3> + +<p>Программирование серверной части позволяет разработчикам использовать <strong>сессии</strong> – изначально это механизм, позволяющий серверу хранить информацию о текущем пользователе сайта и отправлять разные ответы, основанные на этой информации.</p> + +<p>Это позволяет, например, сайту знать, что пользователь был предварительно авторизован и выводить ссылки на его адрес электронной почты или историю заказов или, возможно, сохранить прогресс простой игры, так чтобы пользователь мог вернуться на сайт продолжить с того места, где он закончил.</p> + +<div class="note"> +<p><strong>На заметку:</strong> Посетите новостной сайт, у которого есть подписка и откройте ветку тегов (например, <a href="http://www.theage.com.au/">The Age</a>). Продолжайте посещать сайт в течение нескольких часов/дней. В итоге вас начнёт перенаправлять на страницы, объясняющие, как оформить платную подписку, а сами статьи станут вам недоступны. Эта информация является примером сессии, сохранённой в куки-файлах.</p> +</div> + +<h3 id="Уведомления_и_средства_связи">Уведомления и средства связи</h3> + +<p>Серверы могут отправлять общие или пользовательские уведомления непосредственно через сайт или по электронной почте, через смс, мгновенные сообщения, видеосвязь или другие средства связи.</p> + +<p>Вот несколько примеров:</p> + +<ul> + <li>Facebook или Twitter отправляет уведомления по электронной почте и смс-сообщения, чтобы уведомить вас о новых разговорах.</li> + <li>Amazon регулярно отправляет письма на электронную почту, предлагающие товары, похожие на те, которые уже были куплены или просматривались вами, которые могут вас заинтересовать.</li> + <li>Веб-сервер может посылать сообщения администратору сайта, предупреждая его о том, что на сервере заканчивается память или о подозрительной активности пользователя.</li> +</ul> + +<div class="note"> +<p><strong>На заметку</strong>: Самый распространённый вид уведомлений – это «подтверждение регистрации». Возьмите почти любой интересующий вас крупный сайт (Google, Amazon, Instagram и т. п.) и создайте новую учётную запись, используя ваш адрес электронной почты. Вскоре вы получите письмо, подтверждающее факт вашей регистрации или содержащее информацию о необходимости активировать вашу учётную запись.</p> +</div> + +<h3 id="Анализ_данных">Анализ данных</h3> + +<p>Веб-сайт может собирать много данных о своих пользователях: что они ищут, что они покупают, что они рекомендуют, как долго они остаются на каждой странице. Программирование серверной части может быть использовано, чтобы усовершенствовать ответы, основанные на анализе этих данных.</p> + +<p>Например, и Amazon, и Google рекламируют товары на основании предыдущих поисков (и покупок).</p> + +<div class="note"> +<p><strong>На заметку</strong>: Если вы пользуетесь Facebook, зайдите на вашу стену и посмотрите на ряд постов. Заметьте, что некоторые посты не идут по порядку: в частности, посты с большим количеством «лайков» часто находятся выше по списку, чем остальные. Также взгляните на рекламу, которую вам показывают, вы вероятно увидите рекламу товаров, которые искали на других сайтах. Алгоритм Facebook для выделения контента и рекламы может казаться мистикой, но очевидно, что он зависит от ваших лайков и запросов поиска!</p> +</div> + +<h2 id="Подведение_итогов">Подведение итогов</h2> + +<p>Поздравляем, вы дошли до конца первой статьи о программировании серверной части.</p> + +<p>Теперь вы узнали, что код серверной части выполняется на веб-сервере и его основная роль состоит в контролировании отправляемой пользователю информации (тогда как код клиентской части в основном определяет структуру и способ преподнесения информации пользователю). Вы должны также понимать, что это полезно, так как позволяет создавать веб-сайты, которые эффективно доставляют информацию, собранную для конкретных пользователей и иметь чёткое представление о некоторых вещах, которые вы сможете делать, когда станете разработчиком бэкенда.</p> + +<p>Наконец, вы должны понимать, что код серверной части может быть написан на разных языках программирования, и что вам следует использовать веб-фреймворк для упрощения процесса написания кода.</p> + +<p>В следующей статье мы поможем вам выбрать лучший фреймворк для вашего первого сайта; затем мы изучим несколько основных взаимодействий с клиентской частью более подробно.</p> + +<p>{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}</p> diff --git a/files/ru/learn/server-side/first_steps/web_frameworks/index.html b/files/ru/learn/server-side/first_steps/web_frameworks/index.html new file mode 100644 index 0000000000..af2b467d3f --- /dev/null +++ b/files/ru/learn/server-side/first_steps/web_frameworks/index.html @@ -0,0 +1,306 @@ +--- +title: Выполняемые на сервере веб фреймворки +slug: Learn/Server-side/First_steps/Web_frameworks +translation_of: Learn/Server-side/First_steps/Web_frameworks +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps/Website_security", "Learn/Server-side/First_steps")}}</div> + +<p class="summary">В предыдущей статье было показано, как выглядит общение между веб-клиентами и серверами, характер HTTP-запросов и ответов, а также то, что веб-приложение на стороне сервера должно выполнять, чтобы отвечать на запросы из веб-браузера. Благодаря этим знаниям настало время изучить, как веб-интерфейсы могут упростить эти задачи, и дать вам представление о том, как выбрать структуру для своего первого веб-приложения на стороне сервера.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td>Базовая компьютерная грамотность. Высокое понимание того, как серверный код обрабатывает и отвечает на HTTP-запросы (см. <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">Client-Server overview</a>).</td> + </tr> + <tr> + <th scope="row">Цели:</th> + <td>Понять, как веб-интерфейсы могут упростить разработку / обслуживание кода на стороне сервера и заставить читателей задуматься о выборе структуры для собственной разработки.</td> + </tr> + </tbody> +</table> + +<p>Следующие разделы иллюстрируют некоторые моменты, используя фрагменты кода, взятые из реальных веб-интерфейсов. Не беспокойтесь, если не всё сразу понятно; мы будем работать над кодом вместе в модулях, посвящённых отдельным фреймворкам.</p> + +<h2 id="Обзор">Обзор</h2> + +<p>Серверные веб-фреймворки (или «фреймворки веб-приложений») — это программные среды, которые упрощают создание, поддержку и масштабирование веб-приложений. Они предоставляют инструменты и библиотеки, которые упрощают общие задачи веб-разработки, включая маршрутизацию URL-адресов для соответствующих обработчиков, взаимодействие с базами данных, поддержку сеансов и авторизацию пользователей, форматирование вывода (например, HTML, JSON, XML) и улучшение защиты от веб-атак.</p> + +<p>В следующем разделе приводится более подробная информация о том, как веб-фреймворки могут облегчить разработку веб-приложений. Затем мы объясним некоторые критерии, которые вы можете использовать для выбора веб-фреймворка, а затем перечислим некоторые из ваших вариантов.</p> + +<h2 id="Что_может_сделать_веб-фреймворк_для_вас">Что может сделать веб-фреймворк для вас ?</h2> + +<p>Веб-фреймворки предоставляют инструменты и библиотеки для упрощения общих операций веб-разработки. Вы не обязаны использовать веб-фреймворк на стороне сервера, но это настоятельно рекомендуется — это сделает вашу жизнь намного проще.</p> + +<p>В этом разделе обсуждается различный функционал, который часто предоставляется веб-фреймворками (но не каждый фреймворк должен обязательно содержать весь описанный функционал!)</p> + +<h3 id="Работайте_напрямую_с_HTTP-запросами_и_ответами">Работайте напрямую с HTTP-запросами и ответами</h3> + +<p>Как мы видели в последней статье, веб-серверы и браузеры обмениваются данными по протоколу HTTP — серверы ожидают HTTP-запросы из браузера, а затем возвращают информацию в HTTP-ответах. Веб-фреймворки позволяют писать упрощённый синтаксис, который будет генерировать серверный код для работы с этими запросами и ответами. Это означает, что вам будет легче работать, взаимодействуя с более простым кодом более высокого уровня, а не с сетевыми примитивами более низкого уровня.</p> + +<p>Пример ниже показывает, как это работает в веб-фреймворке Django (Python). Каждая функция «view» (обработчик запроса) получает объект <code>HttpRequest</code>, содержащий информацию о запросе, и должна вернуть объект <code>HttpResponse</code> с форматированным выводом (в этом случае строка).</p> + +<pre class="brush: python notranslate"># Django view function +from django.http import HttpResponse + +def index(request): + # Get an HttpRequest (request) + # perform operations using information from the request. + # Return HttpResponse + return HttpResponse('Output string to return') +</pre> + +<h3 id="Запросы_маршрута_к_соответствующему_обработчику">Запросы маршрута к соответствующему обработчику</h3> + +<p>Большинство сайтов предоставляют несколько различных ресурсов, доступных через отдельные URL-адреса. Если работать с ними в одной функции, поддерживать будет трудно, поэтому веб-фреймворки предоставляют простые механизмы для сопоставления шаблонов URL-адресов с конкретными функциями обработчика. Этот подход также имеет преимущества с точки зрения обслуживания, потому что вы можете изменить URL-адрес, используемый для доставки определённой функции, без изменения базового кода.</p> + +<p>Различные фреймворки используют различные механизмы для сопоставления. Например, веб-фреймворк Flask (Python) добавляет маршруты для просмотра функций используя декораторы.</p> + +<pre class="brush: python notranslate">@app.route("/") +def hello(): + return "Hello World!"</pre> + +<p>Django ожидает, что разработчики определят список сопоставлений URL-адресов между шаблоном URL-адреса и функцией просмотра.</p> + +<pre class="brush: python notranslate">urlpatterns = [ + url(r'^$', views.index), + # example: /best/myteamname/5/ + url(r'^best/(?P<team_name>\w.+?)/(?P<team_number>[0-9]+)/$', views.best), +] +</pre> + +<h3 id="Упростите_доступ_к_данным_в_запросе">Упростите доступ к данным в запросе</h3> + +<p>Данные могут быть закодированы в HTTP-запросе разными способами. Для получения файлов или данных с сервера, HTTP-запрос <code>GET</code> может кодировать, какие данные требуются в URL-параметрах или в структуре URL. HTTP-запрос <code>POST</code> для обновления ресурса на сервере вместо этого будет включать обновлённую информацию как «POST данные» внутри тела запроса. HTTP-запрос может также включать информацию о текущей сессии или пользователе в cookie со стороны клиента.</p> + +<p><span class="tlid-translation translation" lang="ru">Веб-фреймворки предоставляют соответствующие языку программирования механизмы доступа к этой информации. Например, объект</span> <code>HttpRequest</code><span class="tlid-translation translation" lang="ru">, который Django передаёт каждой функции «view», содержит методы и свойства для доступа к целевому URL, типу запроса (например, HTTP</span> <code>GET</code><span class="tlid-translation translation" lang="ru">), параметрам</span> <code>GET</code> <span class="tlid-translation translation" lang="ru">или</span> <code>POST</code><span class="tlid-translation translation" lang="ru">, файлам cookie и данным сеанса и т. д. Django также может передавать информацию, закодированную в структуре URL, путём определения «шаблонов захвата» в преобразователе URL (см. последний фрагмент кода в разделе выше).</span></p> + +<h3 id="Абстрагируйте_и_упростите_доступ_к_базе_данных"><span class="tlid-translation translation" lang="ru">Абстрагируйте и упростите доступ к базе данных</span></h3> + +<p><span class="tlid-translation translation" lang="ru">Веб-сайты используют базы данных для хранения информации как для пользователей, так и о пользователях. Веб-фреймворки часто предоставляют слой базы данных, который абстрагирует операции чтения, записи, запроса и удаления базы данных. Этот уровень абстракции называется Object-Relational Mapper (ORM).</span></p> + +<p><span class="tlid-translation translation" lang="ru">Использование ORM имеет два преимущества:</span></p> + +<ul> + <li>Вы можете заменить лежащую в основе базу данных без необходимости изменять код, который её использует. Это позволяет разработчикам оптимизировать характеристики различных баз данных в зависимости от их использования.</li> + <li><span class="tlid-translation translation" lang="ru">Базовая проверка данных может быть реализована. Это позволяет легче и безопаснее проверить, что данные хранятся в правильном поле типа базы данных, имеют правильный формат (например, адрес электронной почты) и не являются вредоносными (взломщики могут использовать определённые шаблоны кода, чтобы сделать такие вещи, как удаление записей базы данных).</span></li> +</ul> + +<p><span class="tlid-translation translation" lang="ru">Например, веб-фреймворк Django предоставляет ORM и ссылается на объект, используемый для определения структуры записи в качестве модели. Модель задаёт типы полей, которые должны быть сохранены, что может обеспечить проверку на уровне поля того, какая информация может быть сохранена (например, поле электронной почты будет разрешать только действительные адреса электронной почты). В определениях полей также можно указать их максимальный размер, значения по умолчанию, параметры списка выбора, текст справки для документации, текст метки для форм и т. д. Модель не содержит никакой информации о базе данных, поскольку это параметр конфигурации, который может быть изменён отдельно от нашего кода.<br> + <br> + Первый фрагмент кода ниже показывает очень простую модель Django для объекта</span> <code>Team</code><span class="tlid-translation translation" lang="ru">. Это сохраняет название команды и уровень команды как символьные поля и определяет максимальное количество символов для каждой записи.</span> <code>team_level</code><span class="tlid-translation translation" lang="ru"> </span>—<span class="tlid-translation translation" lang="ru"> это поле выбора, поэтому здесь мы связываем варианты значений на выбор с сохраняемыми данными, а также значение по умолчанию.</span></p> + +<pre class="brush: python notranslate">#best/models.py + +from django.db import models + +class Team(models.Model): + team_name = models.CharField(max_length=40) + + TEAM_LEVELS = ( + ('U09', 'Under 09s'), + ('U10', 'Under 10s'), + ('U11, 'Under 11s'), + ... #list our other teams + ) + team_level = models.CharField(max_length=3,choices=TEAM_LEVELS,default='U11') +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Модель Django предоставляет простой API запросов для поиска в базе данных.</span> <span title="">Это может соответствовать нескольким полям одновременно, используя различные критерии (например, </span></span>exact<span class="tlid-translation translation" lang="ru"><span title=""> (точный), </span></span>case-insensitive (<span class="tlid-translation translation" lang="ru"><span title="">без учёта регистра), </span></span>greater than (<span class="tlid-translation translation" lang="ru"><span title="">больше чем) и т. п.), а также может поддерживать сложные операторы (например, вы можете указать поиск для команд U11, в которых есть команда</span> <span title="">имя, которое начинается с «Fr» или заканчивается на «al»).</span><br> + <br> + <span title="">Второй фрагмент кода показывает функцию представления (обработчик ресурсов) для отображения всех наших команд U09.</span> <span title="">В этом случае мы указываем, что мы хотим фильтровать для всех записей, где поле</span></span> <code>team_level</code> <span class="tlid-translation translation" lang="ru"><span title="">имеет в точности текст «U09» (обратите внимание ниже, как этот критерий передаётся функции</span></span> <code>filter()</code> <span class="tlid-translation translation" lang="ru"><span title="">в качестве аргумента с именем поля и типом соответствия, отделённым двойным</span> <span title="">подчёркиванием: <strong>team_level__exact</strong>).</span></span></p> + +<pre class="brush: python notranslate">#best/views.py + +from django.shortcuts import render +from .models import Team + +def youngest(request): + <strong>list_teams = Team.objects.filter(team_level__exact="U09")</strong> + context = {'youngest_teams': list_teams} + return render(request, 'best/index.html', context) +</pre> + +<dl> +</dl> + +<h3 id="Отрисовка_данных"><span class="tlid-translation translation" lang="ru"><span title="">Отрисовка данных</span></span></h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Веб-фреймворки часто предоставляют системы шаблонов.</span> <span title="">Они позволяют вам указать структуру выходного документа, используя заполнители для данных, которые будут добавлены при создании страницы.</span> <span title="">Шаблоны часто используются для создания HTML, но могут также создавать другие типы документов.</span><br> + <br> + <span title="">Веб-фреймворки часто предоставляют механизм, позволяющий легко создавать другие форматы из хранимых данных, включая {{glossary ("JSON")}} и {{glossary ("XML")}}.</span><br> + <br> + <span title="">Например, система шаблонов Django позволяет вам задавать переменные с использованием синтаксиса «двойных велосипедных рулей» (например,</span></span> <code>{</code><code>{ <em>имя_переменной</em> </code><code>}</code><code>}</code>),<span class="tlid-translation translation" lang="ru"><span title=""> которые будут заменены значениями, передаваемыми из функции «view» при отрисовке страницы.</span> <span title="">Система шаблонов также обеспечивает поддержку выражений (с синтаксисом:</span></span> <code>{% <em>выражение</em> %}</code>), <span class="tlid-translation translation" lang="ru"><span title="">которые позволяют шаблонам выполнять простые операции, такие как повторение значений списка, передаваемых в шаблон.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title=""><strong>На заметку</strong>. Многие другие системы шаблонов используют аналогичный синтаксис, например: Jinja2 (Python), </span></span> handlebars <span class="tlid-translation translation" lang="ru"><span title=""> (JavaScript), </span></span> moustache <span class="tlid-translation translation" lang="ru"><span title=""> (JavaScript) и т. п.</span></span></p> +</div> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Фрагмент кода ниже показывает, как это работает.</span> <span title="">Продолжая пример «самой молодой команды» из предыдущего раздела, HTML-шаблон передаёт представлению переменную списка</span></span> <code>youngest_teams</code><span class="tlid-translation translation" lang="ru"><span title="">.</span> <span title="">Внутри скелета HTML у нас есть выражение, которое сначала проверяет, существует ли переменная <code>youngest_teams</code>, а затем повторяет её в цикле <code>for</code>.</span> <span title="">На каждой итерации шаблон отображает значение <code>team_name</code> команды в элементе списка.</span></span></p> + +<pre class="brush: html notranslate">#best/templates/best/index.html + +<!DOCTYPE html> +<html lang="en"> +<body> + + {% if youngest_teams %} + <ul> + {% for team in youngest_teams %} + <li>\{\{ team.team_name \}\}</li> + {% endfor %} + </ul> +{% else %} + <p>No teams are available.</p> +{% endif %} + +</body> +</html> +</pre> + +<h2 id="Как_выбрать_веб-фреймворк"><span class="tlid-translation translation" lang="ru"><span title="">Как выбрать веб-фреймворк</span></span></h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Многочисленные веб-фреймворки существуют практически для каждого языка программирования, который вы, возможно, захотите использовать (мы перечислим несколько наиболее популярных фреймворков в следующем разделе).</span> <span title="">При таком большом количестве вариантов может оказаться затруднительным определить, какой фреймворк обеспечивает лучшую отправную точку для вашего нового веб-приложения.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Вот некоторые из факторов, которые могут повлиять на ваше решение:</span></span></p> + +<ul> + <li><span class="tlid-translation translation" lang="ru"><span title=""><strong>Усилия для изучения:</strong> усилия по изучению веб-фреймворка зависят от того, насколько вы знакомы с базовым языком программирования, последовательностью его API, качеством документации, а также размером и активностью поддерживающего его сообщества.</span> <span title="">Если вы начинаете без какого бы то ни было опыта программирования, подумайте о Django (это один из самых простых способов изучения на основе вышеуказанных критериев).</span> <span title="">Если вы являетесь частью команды разработчиков, которая уже имеет значительный опыт работы с определённым веб-фреймворком или языком программирования, то имеет смысл остановиться на используемом.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title=""><strong>Производительность:</strong> Производительность — это показатель того, насколько быстро вы можете создавать новые функции, когда вы знакомы с платформой, и включает в себя как усилия по написанию, так и по обслуживанию кода (поскольку вы не можете писать новые функции, пока старые не работают).</span> <span title="">Многие из факторов, влияющих на производительность, аналогичны тем, которые используются для «Усилий по обучению» — например,</span> <span title="">документация, сообщество, опыт программирования и т. д. — другие факторы включают в себя:</span></span> + <ul> + <li><span class="tlid-translation translation" lang="ru"><span title=""><em>Назначение / происхождение фреймворка: </em>Некоторые веб-фреймворки изначально создавались для решения определённых типов проблем и работают лучше при создании веб-приложений с аналогичными ограничениями.</span> <span title="">Например, Django был создан для поддержки разработки газетного веб-сайта, поэтому он хорош для блогов и других сайтов, связанных с публикацией материалов.</span> <span title="">Flask, напротив, является гораздо более лёгкой средой и отлично подходит для создания веб-приложений, работающих на встроенных устройствах.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title=""><em>Основанный на мнении сообщества против не имеющего мнения.</em> Фреймворк, основанный на мнении — это тот, в котором рекомендованы «лучшие» способы решения конкретной проблемы.</span> <span title="">Такие фреймворки, как правило, более продуктивны, когда вы пытаетесь решить общие проблемы, потому что они ведут вас в правильном направлении, однако иногда они менее гибки.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title=""><em>Всё включено против разбирайтесь сами</em>: некоторые веб-фреймворки включают в себя инструменты / библиотеки, которые решают каждую проблему, которую их разработчики могут считать «по умолчанию», в то время как более лёгкие фреймворки ожидают, что веб-разработчики будут выбирать решение проблем из отдельных библиотек (например, Django</span> <span title="">из первых, в то время как Flask является примером очень лёгкого каркаса).</span> Начать работу с <span title="">фреймворками, которые включают в себя всё, часто легче, потому что «из коробки» у вас уже есть всё, что вам нужно, и есть вероятность, что они хорошо интегрированы и хорошо документированы.</span> <span title="">Однако, если меньший фреймворк имеет всё, что вам (когда-либо) понадобится, он может работать в более стеснённых условиях и будет иметь меньший и более простой набор вещей для изучения.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title=""><em>Поощряет ли платформа хорошие практики разработки или нет: </em>например, фреймворк, который поощряет архитектуру Model-View-Controller, разделяющую код на логические функции, приведёт к более поддерживаемому коду, чем тот, который не ожидает этого от разработчиков.</span> <span title="">Аналогично дизайн фреймворка может оказать большое влияние на то, насколько легко тестировать и повторно использовать код.</span></span></li> + </ul> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title=""><strong>Производительность фреймворка / языка программирования:</strong> Обычно «скорость» не является самым значимым критерием при выборе, потому что даже относительно медленные среды выполнения, такие как Python, более чем «достаточно хороши» для сайтов среднего размера, работающих на умеренном оборудовании.</span> <span title="">Ожидаемым плюсам скорости другого языка, например</span> <span title="">C++ или JavaScript, могут быть противопоставлены минусы в виде затрат на его изучение и обслуживание. </span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title=""><strong>Поддержка кэширования:</strong> По мере того, как ваш сайт становится более успешным, вы можете столкнуться с тем, что он больше не справляется с количеством запросов, которые получает, когда пользователи им пользуются.</span> <span title="">На этом этапе вы можете рассмотреть возможность добавления поддержки кеширования.</span> <span title="">Кэширование — это оптимизация, при которой вы сохраняете весь веб-ответ или его часть так, чтобы его не нужно было пересчитывать при последующих запросах.</span> <span title="">Возврат кэшированного ответа гораздо быстрее, чем его вычисление.</span> <span title="">Кэширование может быть реализовано в вашем коде или на сервере (см. <a href="https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D1%8B%D0%B9_%D0%BF%D1%80%D0%BE%D0%BA%D1%81%D0%B8">обратный прокси</a>).</span> <span title="">Веб-фреймворки будут иметь разные уровни поддержки для определения того, какой контент можно кэшировать.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title=""><strong>Масштабируемость.</strong> Как только ваш веб-сайт станет фантастически успешным, вы исчерпаете преимущества кэширования и даже достигнете пределов <em>вертикального масштабирования</em> (запуска веб-приложения на более мощном оборудовании).</span> <span title="">На этом этапе вам может потребоваться <em>масштабировать горизонтально</em> (разделить нагрузку, распределяя ваш сайт между несколькими веб-серверами и базами данных) или масштабировать «географически», потому что некоторые из ваших клиентов находятся далеко от вашего сервера.</span> <span title="">Веб-фреймворк, который вы выберете, может существенно повлиять на то, насколько легко масштабировать ваш сайт.</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title=""><strong>Веб-безопасность.</strong> Некоторые веб-фреймворки предоставляют лучшую поддержку для обработки распространённых веб-атак.</span> <span title="">Например, Django очищает весь пользовательский ввод от HTML-шаблонов, чтобы введённый пользователем JavaScript не мог быть запущен.</span> <span title="">Другие платформы предоставляют аналогичную защиту, но она не всегда включена по умолчанию.</span></span></li> +</ul> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Существует также много других возможных влияющих факторов, включая вопросы лицензирования, зависимость от того, находится ли фреймворк в процессе активной разработки и т. д.</span><br> + <br> + <span title="">Если вы абсолютный новичок в программировании, вы, вероятно, выберете свою среду на основе «простоты обучения».</span> <span title="">В дополнение к «простоте использования» самого языка, ваши самые ценные ресурсы — это высококачественная документация / учебные пособия и активное сообщество, помогающее новым пользователям.</span> <span title="">Мы выбрали <a href="https://www.djangoproject.com/">Django</a> (Python) и <a href="http://expressjs.com/">Express</a> (Node/JavaScript) для написания наших примеров далее в курсе, главным образом потому, что они просты в освоении и имеют хорошую поддержку.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title=""><strong>На заметку:</strong> Давайте перейдём к основным веб-сайтам для <a href="https://www.djangoproject.com/">Django</a> (Python) и <a href="http://expressjs.com/">Express</a> (Node/JavaScript) и ознакомимся с их документацией и сообществом.</span></span></p> + +<ol> + <li><span class="tlid-translation translation" lang="ru"><span title="">Перейдите к основным сайтам (ссылки выше)</span></span> + + <ul> + <li><span class="tlid-translation translation" lang="ru"><span title="">Нажмите на ссылки меню «Документация» (такие вещи, как «Документация, Руководство, Справочник по API, Начало работы»).</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Можете ли вы увидеть темы, показывающие, как настроить маршрутизацию URL, шаблоны и базы данных / модели?</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Понятны ли эти документы?</span></span></li> + </ul> + </li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Перейдите к спискам рассылки для каждого сайта (доступно по ссылкам сообщества).</span></span> + <ul> + <li><span class="tlid-translation translation" lang="ru"><span title="">Сколько вопросов было опубликовано за последние несколько дней?</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">У скольких есть ответы?</span></span></li> + <li><span class="tlid-translation translation" lang="ru"><span title="">Есть ли у них активное сообщество?</span></span></li> + </ul> + </li> +</ol> +</div> + +<h2 id="Несколько_хороших_веб-фреймворков"><span class="tlid-translation translation" lang="ru"><span title="">Несколько хороших веб-фреймворков?</span></span></h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Давайте продолжим и обсудим несколько конкретных серверных веб-фреймворков.</span><br> + <br> + <span title="">Фреймворки на стороне сервера, представленные ниже, представляют собой несколько самых популярных из доступных на момент написания.</span> <span title="">Все они имеют всё, что вам нужно для продуктивной работы </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> они с открытым исходным кодом, находятся в процессе активной разработки, имеют полные энтузиазма сообщества, создающие документацию и помогающие пользователям на форумах, и используются на большом количестве выдающихся веб-сайтов.</span> <span title="">Существует также много других замечательных серверных фреймворков, которые вы можете найти с помощью обычного поиска в Интернете.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title=""><strong>На заметку:</strong> Описания взяты (частично) с веб-сайтов фреймворка!</span></span></p> +</div> + +<h3 id="Django_Python">Django (Python)</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title=""><a href="https://www.djangoproject.com/">Django</a> </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> это веб-фреймворк высокого уровня на языке Python, который способствует быстрой разработке и чистому, прагматичному дизайну.</span> <span title="">Созданный опытными разработчиками, он берёт на себя большую часть хлопот веб-разработки, поэтому вы можете сосредоточиться на написании своего приложения без необходимости заново изобретать велосипед.</span> <span title="">Он бесплатен для использования и имеет открытый исходный код.</span><br> + <br> + <span title="">Django следует философии «Всё включено» и предоставляет практически всё, что большинство разработчиков может пожелать «из коробки».</span> <span title="">Поскольку всё включено, всё работает вместе, следует последовательным принципам проектирования и имеет обширную и актуальную документацию.</span> <span title="">Он также быстр, безопасен и очень масштабируем.</span> <span title="">Основанный на Python, код Django легко читать и поддерживать.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Популярные сайты, использующие Django (с домашней страницы Django), включают в себя: Disqus, Instagram, Knight Foundation, MacArthur Foundation, Mozilla, National Geographic, Open Knowledge Foundation, Pinterest, Open Stack.</span></span></p> + +<h3 id="Flask_Python">Flask (Python)</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title=""><a href="http://flask.pocoo.org/">Flask</a> </span></span>—<span class="tlid-translation translation" lang="ru"><span title=""> это микрофреймворк для Python.</span><br> + <br> + <span title="">И хотя Flask минималистичен, он может создавать серьезные веб-сайты из коробки.</span> <span title="">Он содержит сервер разработки и отладчик, а также поддерживает шаблоны <a href="https://github.com/pallets/jinja">Jinja2</a>, безопасные файлы cookie, <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5">модульное тестирование</a> и диспетчеризацию запросов <a href="http://www.restapitutorial.com/lessons/restfulresourcenaming.html">RESTful</a>.</span> <span title="">У него хорошая документация и активное сообщество.</span></span></p> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Flask стал чрезвычайно популярным, особенно для разработчиков, которым необходимо предоставлять веб-сервисы в небольших системах с ограниченными ресурсами (например, запуск веб-сервера на <a href="https://www.raspberrypi.org/">Raspberry Pi</a>, <a href="https://www.raspberrypi.org/">контроллеры Drone</a> и т. п.)</span></span>.</p> + +<h3 id="Express_Node.jsJavaScript">Express (Node.js/JavaScript)</h3> + +<p><a href="http://expressjs.com/">Express</a> — быстрый, непринуждённый, гибкий и минималистский веб-фреймворк для <a href="https://nodejs.org/en/">Node.js</a> (node — это серверная среда для запуска JavaScript). Он обеспечивает надёжный набор функций для веб и мобильных приложений и предоставляет полезные HTTP-утилиты и <a href="/en-US/docs/Glossary/Middleware">middleware</a> (промежуточные интерфейсы).</p> + +<p><span class="tlid-translation translation" lang="ru">Express чрезвычайно популярен, частично потому, что он облегчает миграцию клиентских веб-программистов JavaScript в разработку на стороне сервера, а частично потому, что он ресурсоэффективен (базовая среда узлов использует легкую многозадачность в потоке, а не порождает отдельные процессы для каждого новый веб-запрос).<br> + <br> + Поскольку Express является минималистской веб-инфраструктурой, он не включает в себя все компоненты, которые вы, возможно, захотите использовать (например, доступ к базе данных и поддержка пользователей и сеансов предоставляются через независимые библиотеки). Есть много отличных независимых компонентов, но иногда бывает сложно решить, какой из них лучше всего подходит для конкретной цели!<br> + <br> + Многие популярные серверные и полные стеки (включая серверные и клиентские) основаны на Express, включая Feathers, ItemsAPI, KeystoneJS, Kraken, LEAN-STACK, LoopBack, MEAN и Sails.<br> + <br> + Многие крупные компании используют Express, в том числе: Uber, Accenture, IBM и т. Д. (Список приведен здесь).</span></p> + +<h3 id="Ruby_on_Rails_Ruby">Ruby on Rails (Ruby)</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Rails (обычно называемый «Ruby on Rails») - это веб-фреймворк, написанный для языка программирования Ruby.</span><br> + <br> + <span title="">Rails следует очень похожей философии дизайна на Django.</span> <span title="">Как и Django, он предоставляет стандартные механизмы для маршрутизации URL, доступа к данным из базы данных, генерации HTML из шаблонов и форматирования данных как {{glossary ("JSON")}} или {{glossary ("XML")}}.</span> <span title="">Точно так же поощряется использование шаблонов проектирования, таких как DRY («не повторяйте себя» - пишите код только один раз, если это возможно), MVC (модель-представление-контроллер) и ряд других.</span><br> + <br> + <span title="">Конечно, есть много различий, связанных с конкретными проектными решениями и характером языков.</span><br> + <br> + <span title="">Rails использовался для крупных сайтов, в том числе: Basecamp, GitHub, Shopify, Airbnb, Twitch, SoundCloud, Hulu, Zendesk, Square, Highrise.</span></span></p> + +<h3 id="ASP.NET">ASP.NET</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">ASP.NET - это веб-инфраструктура с открытым исходным кодом, разработанная Microsoft для создания современных веб-приложений и сервисов.</span> <span title="">С ASP.NET вы можете быстро создавать веб-сайты на основе HTML, CSS и JavaScript, масштабировать их для использования миллионами пользователей и легко добавлять более сложные возможности, такие как веб-API, формы поверх данных или коммуникации в режиме реального времени.</span><br> + <br> + <span title="">Одним из отличий для ASP.NET является то, что он построен на Common Language Runtime (CLR), что позволяет программистам писать код ASP.NET с использованием любого поддерживаемого языка .NET (C #, Visual Basic и т. д.).</span> <span title="">Как и многие продукты Microsoft, он обладает отличными инструментами (часто бесплатными), активным сообществом разработчиков и хорошо написанной документацией.</span><br> + <br> + <span title="">ASP.NET используется Microsoft, Xbox.com, Stack Overflow и многими другими.</span></span></p> + +<h3 id="Mojolicious_Perl">Mojolicious (Perl)</h3> + +<p><span class="tlid-translation translation" lang="ru">Mojolicious - это веб-фреймворк следующего поколения для языка программирования Perl.<br> + <br> + Еще в первые дни Интернета многие люди изучали Perl из-за замечательной библиотеки Perl под названием CGI. Это было достаточно просто, чтобы начать, не зная много о языке и достаточно мощный, чтобы держать вас в курсе. Mojolicious реализует эту идею, используя новейшие технологии.<br> + <br> + Некоторые из функций, предоставляемых Mojolicious: веб-инфраструктура в режиме реального времени, позволяющая легко превращать отдельные файловые прототипы в хорошо структурированные веб-приложения MVC; RESTful маршруты, плагины, команды, шаблоны Perl-ish, согласование контента, управление сеансами, проверка форм, структура тестирования, статический файловый сервер, обнаружение CGI / PSGI, поддержка Unicode первого класса; Реализация полного стека HTTP и WebSocket клиент / сервер с IPv6, TLS, SNI, IDNA, HTTP / SOCKS5 прокси, сокет домена UNIX, Comet (длинный опрос), поддержка активности, пул соединений, тайм-аут, cookie, поддержка нескольких частей и сжатия gzip; Парсеры и генераторы JSON и HTML / XML с поддержкой селекторов CSS; Очень чистый, портативный и объектно-ориентированный чистый Perl API без скрытой магии; Свежий код, основанный на многолетнем опыте, бесплатный и открытый исходный код.</span></p> + +<h2 id="Резюме"><span class="tlid-translation translation" lang="ru"><span title="">Резюме</span></span></h2> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Эта статья показала, что веб-фреймворки могут упростить разработку и поддержку кода на стороне сервера.</span> <span title="">Он также предоставил общий обзор нескольких популярных платформ и обсудил критерии выбора платформы веб-приложений.</span> <span title="">Теперь у вас должно быть хотя бы представление о том, как выбрать веб-фреймворк для собственной разработки на стороне сервера.</span> <span title="">Если нет, то не беспокойтесь - позже в курсе мы дадим вам подробные учебники по Django и Express, чтобы дать вам некоторый опыт работы с веб-фреймворком.</span> </span></p> + +<p>Для следующей статьи в этом модуле мы немного изменим направление и рассмотрим веб-безопасность.</p> + +<p>{{PreviousMenuNext("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps/Website_security", "Learn/Server-side/First_steps")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Introduction">Introduction to the server side</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">Client-Server overview</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Web_frameworks">Server-side web frameworks</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a></li> +</ul> + +<div id="gtx-anchor" style="position: absolute; left: 170px; top: 2836px; width: 297px; height: 17px;"></div> + +<div class="jfk-bubble gtx-bubble"> +<div class="jfk-bubble-content-id" id="bubble-18"> +<div id="gtx-host" style="max-width: 400px;"></div> +</div> + +<div class="jfk-bubble-closebtn-id jfk-bubble-closebtn"></div> + +<div class="jfk-bubble-arrow-id jfk-bubble-arrow jfk-bubble-arrowup" style="left: 128.5px;"> +<div class="jfk-bubble-arrowimplbefore"></div> + +<div class="jfk-bubble-arrowimplafter"></div> +</div> +</div> diff --git a/files/ru/learn/server-side/first_steps/веб_безопасность/index.html b/files/ru/learn/server-side/first_steps/веб_безопасность/index.html new file mode 100644 index 0000000000..6caa9b2aa2 --- /dev/null +++ b/files/ru/learn/server-side/first_steps/веб_безопасность/index.html @@ -0,0 +1,169 @@ +--- +title: Веб-безопасность +slug: Learn/Server-side/First_steps/Веб_Безопасность +translation_of: Learn/Server-side/First_steps/Website_security +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</div> + +<p class="summary">Безопасность сайта требует бдительности во всех аспектах дизайна и использования сайта. Эта вводная статья не сделает из вас гуру безопасности веб-сайта, но она поможет вам понять, откуда приходят угрозы, и что вы можете сделать, чтобы укрепить свое веб-приложение против наиболее распространенных атак.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Условия:</th> + <td>Элементарная компьютерная грамотность</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять самые распространенные угрозы безопасности веб-приложений. И что вы можете сделать, чтобы уменьшить риск взлома вашего сайта.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_безопасность_сайта">Что такое безопасность сайта?</h2> + +<p>Интернет опасное место! Мы регулярно слышим о том, что веб-сайты становятся недоступными из-за атак типа отказано в обслуживании, или отображение измененной (и часто поврежденной) информации на их страницах. В других случаях миллионы паролей, адресов электронной почты и данные кредитных карт становились общедоступными, подвергая пользователей веб-сайта личному смущению или к финансовым рискам.</p> + +<p>Цель веб-безопасности заключается в предотвращении этих (или других) видов атак. Более формальным определением веб-безопасности является: <em>способы защиты веб-сайтов от несанкционированного доступа, использования, изменения, уничтожения или нарушения работы.</em></p> + +<p>Для эффективной безопасности веб-сайта необходимо уделять особое внимание к разработке всего веб-сайта: к вашему веб-приложению, конфигурации веб-сервера, при написании политик создания и обновления паролей, а так же кода на стороне клиента. Хотя все это звучит очень зловеще, хорошая новость заключается в том, что если вы используете веб-фреймворк для серверной части, то он почти наверняка обеспечит «по умолчанию» надежные и продуманные механизмы защиты от ряда наиболее распространенных атак. Другие атаки можно смягчить с помощью конфигурации вашего веб-сервера, например, включив HTTPS. Наконец, есть общедоступные инструменты для сканирования уязвимостей, которые могут помочь вам определить, если вы допустили какие-либо очевидные ошибки.</p> + +<p>В оставшейся части этой статьи мы рассмотрим более подробную информацию о некоторых самых распространенных угрозах и о простых шагах, которые вы можете предпринять, чтобы защитить свой сайт.</p> + +<div class="note"> +<p><strong>Примечание: </strong>Это вводная статья, призванная помочь вам задуматься о безопасности веб-сайта, но она не является исчерпывающей.</p> +</div> + +<h2 id="Угрозы_бесопасности_сайта">Угрозы бесопасности сайта</h2> + +<p>В этом разделе перечислены лишь некоторые из наиболее распространенных угроз веб-сайта и способы их устранения. Читая, обратите внимание на то, насколько успешны угрозы, когда веб-приложение доверяет, либо <em>недостаточно параноидально</em> относится к данным, поступающим из браузера.</p> + +<h3 id="Межсайтовый_скриптинг_XSS">Межсайтовый скриптинг (XSS)</h3> + +<p>XSS (<em>Cross-Site Scripting</em> - Межсайтовый скриптинг) это термин, используемый для описания типа атак, которые позволяют злоумышленнику внедрять вредоносный код <em>через</em> веб-сайт в браузеры других пользователей. Поскольку внедренный код поступает в браузер с сайта, он является <em>доверенным</em> и может выполнять такие действия, как отправка авторизационного файла <em>cookie</em>пользователя злоумышленнику. Когда у злоумышленника есть файл <em>cookie</em>, он может войти на сайт, как если бы он был пользователем, и сделать все, что может пользователь, например, получить доступ к данным кредитной карты, просмотреть контактные данные или изменить пароли.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Уязвимости XSS исторически встречались чаще, чем любые другие виды угроз безопасности.</p> +</div> + +<p>Уязвимости XSS делятся на <em>отраженные</em> и <em>хранимые</em>, в зависимости от того, как сайт возвращает внедренный код в браузер.</p> + +<ul> + <li><em>Отраженная </em>XSS-уязвимость возникает, когда пользовательский контент, который передается на сервер, <em>немедленно</em> и <em>без изменений</em> возвращается для отображения в браузере. Любой скрипт в исходном пользовательском контенте запустится при загрузке новой страницы. Например, рассмотрим строку поиска по сайту, в которой поисковые слова закодированы как параметры URL, и эти слова отображаются вместе с результатами. Злоумышленник может создать поисковую ссылку, которая будет содержать вредоносный скрипт в качестве параметра (например: <code>http://mysite.com?q=beer<script%20src="http://evilsite.com/tricky.js"></script></code>) и перслать его другому пользователю по электронной почте. Если целевой пользователь кликнет по этой «интересной ссылке», то скрипт выполнится при отображении результатов поиска. Как мы уже говорили, злоумышленник таким образом получает всю информацию, необходимую ему для входа на сайт в качестве целевого пользователя, потенциального совершения покупок от имени пользователя или получения его контактной информации.</li> + <li> + <p><span class="tlid-translation translation" lang="ru">Постоянная уязвимость XSS возникает, когда вредоносный скрипт хранится на веб-сайте, а затем снова отображается без изменений, чтобы другие пользователи могли выполнять его невольно.<br> + Например, доска обсуждений, которая принимает комментарии, содержащие неизмененный HTML, может хранить вредоносный скрипт от злоумышленника. Когда комментарии отображаются, скрипт выполняется и может отправить злоумышленнику информацию, необходимую для доступа к учетной записи пользователя. Атака такого рода чрезвычайно популярна и мощна, потому что злоумышленник может даже не иметь прямого отношения к жертвам.<br> + <br> + Хотя данные из запросов POST или GET являются наиболее распространенным источником уязвимостей XSS, любые данные из браузера потенциально уязвимы, такие как данные cookie, отображаемые браузером, или пользовательские файлы, которые загружаются и отображаются.<br> + <br> + Наилучшей защитой от уязвимостей XSS является удаление или отключение любой разметки, которая потенциально может содержать инструкции по запуску кода. Для HTML это включает такие элементы, как <script>, <object>, <embed> и <link>.<br> + <br> + Процесс изменения пользовательских данных, чтобы их нельзя было использовать для запуска сценариев или иным образом влиять на выполнение серверного кода, называется очисткой ввода. Многие веб-фреймворки автоматически очищают пользовательский ввод от HTML-форм по умолчанию.</span></p> + </li> +</ul> + +<h3 id="SQL_injection">SQL injection</h3> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Уязвимости SQL-инъекций позволяют злоумышленникам выполнять произвольный код SQL в базе данных, позволяя получать, изменять или удалять данные независимо от разрешений пользователя.</span> <span title="">Успешная инъекционная атака может подделать удостоверения, создать новые удостоверения с правами администратора, получить доступ ко всем данным на сервере или уничтожить / изменить данные, чтобы сделать их непригодными для использования.</span><br> + <br> + <span title="">Типы внедрения SQL включают внедрение SQL на основе ошибок, внедрение SQL на основе логических ошибок и внедрение SQL на основе времени.</span><br> + <br> + <span title="">Эта уязвимость присутствует, если пользовательский ввод, который передается в базовый оператор SQL, может изменить смысл оператора.</span> <span title="">Например, следующий код предназначен для перечисления всех пользователей с определенным именем (userName), которое было предоставлено из формы HTML:</span></span></p> + +<pre class="brush: sql notranslate">statement = "SELECT * FROM users WHERE name = '" + <strong>userName</strong> + "';"</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Если пользователь указывает реальное имя, оператор будет работать так, как задумано.</span> <span title="">Однако злонамеренный пользователь может полностью изменить поведение этого оператора SQL на новый оператор в следующем примере, просто указав текст полужирным шрифтом для userName.</span></span></p> + +<pre class="brush: sql notranslate">SELECT * FROM users WHERE name = '<strong>a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't</strong>'; +</pre> + +<p><span class="tlid-translation translation" lang="ru"><span title="">Модифицированный оператор создает действительный оператор SQL, который удаляет таблицу пользователей и выбирает все данные из таблицы userinfo (которая раскрывает информацию о каждом пользователе).</span> <span title="">Это работает, потому что первая часть введенного текста (a ';) завершает исходное утверждение.</span><br> + <br> + <span title="">Чтобы избежать такого рода атак, вы должны убедиться, что любые пользовательские данные, которые передаются в запрос SQL, не могут изменить природу запроса.</span> <span title="">Один из способов сделать это - экранировать все символы пользовательского ввода, которые имеют особое значение в SQL.</span></span></p> + +<div class="note"> +<p><span class="tlid-translation translation" lang="ru"><span title="">Примечание. Инструкция SQL обрабатывает символ ' как начало и конец строкового литерала.</span> <span title="">Поместив обратную косую черту перед этим символом (\ '), мы экранируем символ и говорим SQL вместо этого трактовать его как символ (только часть строки).</span></span></p> +</div> + +<p>В следующей инструкции мы экранируем символ '. Теперь SQL будет интерпретировать имя как всю строку, выделенную жирным шрифтом (это действительно очень странное имя, но безопасное).</p> + +<pre class="brush: sql notranslate">SELECT * FROM users WHERE name = '<strong>a\';DROP TABLE users; SELECT * FROM userinfo WHERE \'t\' = \'t'</strong>; + +</pre> + +<p>Веб-фремворки будут часто заботиться о зарезервированных символах для вас. Django, например, гарантирует, что любые пользовательские данные, передаваемые в наборы запросов (модельные запросы), будут экранируются.</p> + +<div class="note"> +<p><strong>Примечание: </strong>этот раздел в значительной степени основан на информации из <a href="https://en.wikipedia.org/wiki/SQL_injection">Wikipedia</a>.</p> +</div> + +<h3 id="Подделка_межсайтовых_запросов_CSRF">Подделка межсайтовых запросов (CSRF)</h3> + +<p>CSRF-атаки позволяют злоумышленнику выполнять действия, используя учетные данные другого пользователя, без его ведома или согласия.</p> + +<p>Этот тип атаки лучше всего пояснить на примере. Джон - злоумышленник, который знает, что определенный сайт позволяет пользователям, вошедшим в систему, отправлять деньги на указанную учетную запись, используя HTTP-запрос <code>POST</code>, который включает имя учетной записи и сумму денег. Джон создает форму, которая включает в себя его банковские реквизиты и сумму денег в виде скрытых полей, и отправляет ее по электронной почте другим пользователям сайта (с кнопкой «Отправить», замаскированной под ссылку на сайт «быстрого обогащения»).</p> + +<p>Если пользователь нажимает кнопку отправки, на сервер будет отправлен HTTP-запрос <code>POST</code>, содержащий сведения о транзакции и любые файлы cookie на стороне клиента, которые браузер связал с сайтом (добавление связанных файлов cookie сайта в запросы является нормальным поведением браузера). Сервер проверит файлы cookie и использует их, чтобы определить, вошел ли пользователь в систему и имеет ли разрешение на совершение транзакции.</p> + +<p>В результате любой пользователь, который нажимает кнопку <em>Отправить</em> во время входа на торговый сайт, совершает транзакцию. Джон становится богатым.</p> + +<div class="note"> +<p><strong>Примечание: </strong>Уловка здесь в том, что Джону не нужен доступ к файлам cookie пользователя (или учетным данным). Браузер пользователя сохраняет эту информацию и автоматически включает ее во все запросы к соответствующему серверу.</p> +</div> + +<p>Один из способов предотвратить этот тип атаки - запросить сервером запросы <code>POST</code>, содержащие секрет, созданный пользователем для конкретного сайта. Секрет будет предоставлен сервером при отправке веб-формы, используемой для переводов. Такой подход не позволяет Джону создать свою собственную форму, потому что он должен знать секрет, который сервер предоставляет пользователю. Даже если он узнает секрет и создаст форму для конкретного пользователя, он больше не сможет использовать ту же форму для атаки на каждого пользователя.</p> + +<p>Веб-фреймворки часто включают такие механизмы предотвращения CSRF.</p> + +<h3 id="Прочие_угрозы">Прочие угрозы</h3> + +<p>Другие распространенные атаки / уязвимости включают:</p> + +<ul> + <li><a href="https://www.owasp.org/index.php/Clickjacking">Clickjacking</a>. В этой атаке злоумышленник перехватывает клики, предназначенные для видимого сайта верхнего уровня, и направляет их на скрытую ниже страницу. Этот метод можно использовать, например, для отображения законного сайта банка, но захвата учетных данных для входа в невидимый {{htmlelement("iframe")}} , контролируемый злоумышленником. Clickjacking также можно использовать для того, чтобы заставить пользователя нажать кнопку на видимом сайте, но при этом на самом деле невольно нажимать совершенно другую кнопку. В качестве защиты ваш сайт может предотвратить встраивание себя в iframe на другом сайте, установив соответствующие заголовки HTTP.</li> + <li><a href="/en-US/docs/Glossary/Distributed_Denial_of_Service">Denial of Service</a> (DoS). DoS обычно достигается за счет наводнения целевого сайта поддельными запросами, так что доступ к сайту нарушается для законных пользователей. Запросы могут быть просто многочисленными или по отдельности потреблять большие объемы ресурсов (например, медленное чтение или загрузка больших файлов). Защита от DoS обычно работает, выявляя и блокируя «плохой» трафик, пропуская при этом легитимные сообщения. Эти средства защиты обычно расположены перед веб-сервером или на нем (они не являются частью самого веб-приложения).</li> + <li><a href="https://en.wikipedia.org/wiki/Directory_traversal_attack">Directory Traversal</a> (Файл и раскрытие). В этой атаке злоумышленник пытается получить доступ к частям файловой системы веб-сервера, к которым у него не должно быть доступа. Эта уязвимость возникает, когда пользователь может передавать имена файлов, содержащие символы навигации файловой системы (например, <code>../../</code>). Решение состоит в том, чтобы очищать ввод перед его использованием.</li> + <li><a href="https://en.wikipedia.org/wiki/File_inclusion_vulnerability">File Inclusion</a>. В этой атаке пользователь может "случайно" указать файл для отображения или выполнения в данных, передаваемых на сервер. После загрузки этот файл может выполняться на веб-сервере или на стороне клиента (что приводит к XSS-атаке). Решение состоит в том, чтобы дезинфицировать ввод перед его использованием.</li> + <li><a href="https://www.owasp.org/index.php/Command_Injection">Внедрение команд</a>. Атаки с внедрением команд позволяют злоумышленнику выполнять произвольные системные команды в операционной системе хоста. Решение состоит в том, чтобы дезинфицировать вводимые пользователем данные до того, как их можно будет использовать в системных вызовах.</li> +</ul> + +<p>Полный список угроз безопасности веб-сайтов см. <a href="https://en.wikipedia.org/wiki/Category:Web_security_exploits">Category: Web security exploits</a> (Wikipedia) и <a href="https://www.owasp.org/index.php/Category:Attack">Category: Attack</a> (Open Web Application Security Project).</p> + +<h2 id="Несколько_ключевых_сообщений">Несколько ключевых сообщений</h2> + +<p>Почти все эксплойты безопасности, описанные в предыдущих разделах, успешны, когда веб-приложение доверяет данным из браузера. Что бы вы ни делали для повышения безопасности своего веб-сайта, вы должны дезинфицировать все данные, исходящие от пользователей, прежде чем они будут отображаться в браузере, использоваться в запросах SQL или передаваться в вызов операционной системы или файловой системы.</p> + +<div class="warning"> +<p>Внимание! Самый важный урок, который вы можете извлечь о безопасности веб-сайтов: <strong>никогда не доверяйте данным из браузера</strong>. Это включает, помимо прочего, данные в параметрах URL-адресов запросов <code>GET</code>, запросов <code>POST</code>, заголовков HTTP и файлов cookie, а также файлов, загруженных пользователем. Всегда проверяйте и дезинфицируйте все входящие данные. Всегда предполагайте худшее!</p> +</div> + +<p>Вы можете предпринять ряд других конкретных шагов:</p> + +<ul> + <li>Используйте более эффективное управление паролями. Поощряйте регулярную смену надежных паролей. Рассмотрите возможность двухфакторной аутентификации для вашего сайта, чтобы в дополнение к паролю пользователь должен был ввести другой код аутентификации (обычно тот, который доставляется через какое-то физическое оборудование, которое будет иметь только пользователь, например, код в SMS, отправленном на его телефон).</li> + <li>Настройте свой веб-сервер для использования <a href="/en-US/docs/Glossary/https">HTTPS</a> и <a href="/en-US/docs/Web/Security/HTTP_strict_transport_security">HTTP Strict Transport Security</a> (HSTS). HTTPS шифрует данные, передаваемые между вашим клиентом и сервером. Это гарантирует, что учетные данные для входа, файлы cookie, данные запросов <code>POST</code> и информация заголовка не будут легко доступны для злоумышленников.</li> + <li>Следите за наиболее популярными угрозами (<a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project">текущий список OWASP находится здесь</a>) и в первую очередь устраняйте наиболее распространенные уязвимости.</li> + <li>Используйте <a href="https://www.owasp.org/index.php/Category:Vulnerability_Scanning_Tools">инструменты сканирования уязвимостей</a>, чтобы выполнить автоматическое тестирование безопасности на вашем сайте. Позже ваш очень успешный веб-сайт может также обнаруживать ошибки, предлагая вознаграждение за обнаружение ошибок, как это <a href="https://www.mozilla.org/en-US/security/bug-bounty/faq-webapp/">делает здесь</a> Mozilla.</li> + <li>Храните и отображайте только те данные, которые вам нужны. Например, если ваши пользователи должны хранить конфиденциальную информацию, такую как данные кредитной карты, отображайте часть номера карты только для того, чтобы он мог быть идентифицирован пользователем, и недостаточно, чтобы его мог скопировать злоумышленник и использовать на другом сайте. Самый распространенный шаблон в настоящее время - отображение только последних 4 цифр номера кредитной карты.</li> +</ul> + +<p>Веб-фреймворки могут помочь смягчить многие из наиболее распространенных уязвимостей.</p> + +<h2 id="Резюме">Резюме</h2> + +<p>В этой статье объясняется концепция веб-безопасности и некоторые из наиболее распространенных угроз, от которых ваш веб-сайт должен пытаться защититься. Самое главное, вы должны понимать, что веб-приложение не может доверять никаким данным из веб-браузера. Все пользовательские данные должны быть очищены перед отображением или использованием в SQL-запросах и вызовах файловой системы.</p> + +<p>Этой статьей вы подошли к концу <a href="/en-US/docs/Learn/Server-side/First_steps">этого модуля</a>, охватывающего ваши первые шаги в программировании на стороне сервера. Мы надеемся, что вам понравилось изучать эти фундаментальные концепции, и теперь вы готовы выбрать веб-платформу и начать программировать.</p> + +<p>{{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Introduction">Введение в серверную часть</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">Обзор технологии клиент-сервер</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Web_frameworks">Серверные веб-фреймворки</a></li> + <li><a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Безопасность веб-сайта</a></li> +</ul> diff --git a/files/ru/learn/server-side/index.html b/files/ru/learn/server-side/index.html new file mode 100644 index 0000000000..306d52ad79 --- /dev/null +++ b/files/ru/learn/server-side/index.html @@ -0,0 +1,54 @@ +--- +title: Серверное программирование веб-сайтов +slug: Learn/Server-side +tags: + - Beginner + - CodingScripting + - Intro + - Landing + - Learn + - NeedsTranslation + - Server + - Server-side programming + - Topic + - TopicStub +translation_of: Learn/Server-side +--- +<div>{{LearnSidebar}}</div> + +<p class="summary"><strong>Тема<em> Динамические веб-сайты </em></strong>– <em><strong>серверное программирование</strong></em> состоит из ряда модулей, рассматривающих создание динамических веб-сайтов; сайтов, которые доставляют персонализированную информацию в ответ на HTTP запрос. Этот модуль предоставляет общее введение в серверное программирование, наряду со специальными руководствами начального уровня о том, как использовать Django (Python) и Express (Node.js/JavaScript) веб-фреймворки для создания простых приложений.</p> + +<p>Подавляющее большинство вебсайтов используют какую-либо из серверных технологий для динамического отображения различных требуемых данных. К примеру, вообразите себе сколь много товаров доступны на Amazon, и представьте как много постов расположено на Facebook? Отображение всех их посредством отдельных статических страниц было бы крайне неэффективно, вместо этого подобные сайты используют шаблоны (созданные из <a href="/ru/docs/Learn/HTML">HTML</a>, <a href="/ru/docs/Learn/CSS">CSS</a>, и <a href="/ru/docs/Learn/JavaScript">JavaScript</a>), и затем динамически обновляют данные, отображаемые внутри этих шаблонов, когда это необходимо , т.е. когда вы хотите увидеть другой товар на Amazon.</p> + +<p>В современном мире веб-разработки крайне рекомендуется изучить разработку на стороне сервера.</p> + +<h2 id="Программа_обучения">Программа обучения</h2> + +<p>Начинать с серверного программировния обычно легче, чем с разработки на стороне клиента, поскольку динамические веб-сайты склонны производить множество однообразных операций (извлекать данные из базы данных и помещать их на странице, подтверждать пользовательский ввод и сохранять его в базе данных, проверять пользовательские права и выполнение входа, и.т.д.) и сконструированы с использованием веб-фреймворков, которые выполняют эти и другие привычные веб-серверу операции с легкостью.</p> + +<p>Общее понимание концепций программирования (или определенного программного языка) будет полезным, но не обязательным. Сходным образом, опыт программирования на клиентской стороне не требуется, но базовое знание поможет вам успешнее взаимодействовать с разработчиками клиентской стороны веб-приложения - "фронтэнда".</p> + +<p>Вам потребуется понимать "как работает веб". Мы рекомендуем вам сначала ознакомиться с темами:</p> + +<ul> + <li><a href="/ru/docs/Learn/Что_такое_веб_сервер">Что такое веб-сервер</a></li> + <li><a href="/en-US/docs/Learn/Common_questions/What_software_do_I_need">Какое ПО мне нужно для построения веб-сайта?</a></li> + <li><a href="/en-US/docs/Learn/Common_questions/Upload_files_to_a_web_server">Как заливать файлы на веб-сервер?</a></li> +</ul> + +<p>С этим базовым набором знаний вы будете готовы освоить модули в этой секции.</p> + +<h2 id="Модули">Модули</h2> + +<p>Эта тема состоит из следующих модулей. Начинайте с самого первого модуля, а затем переходите на выбор к любому из двух следующих, рассматривающих работу с парой популярных серверных языков с использованием соответствующих веб-фреймворков. </p> + +<dl> + <dt><a href="/ru/docs/Learn/Server-side/First_steps">Первые шаги в программировании веб-сайтов на стороне сервера</a></dt> + <dd>Этот модуль посвящен информации о технологиях программирования веб-сайтов на стороне сервера, попутно отвечая и на фундаментальные вопросы о серверном программировании — "что это такое", "чем оно отличается от программирования на стороне клиента", и "почему оно так востребовано" — и обозревая некоторые из наиболее популярных серверных веб-фреймворков, а также объясняя как выбрать подходящий для вашего сайта. Напоследок мы организуем вводный раздел о безопасности веб-сервера.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django">Веб-фреймворк Django (Python)</a></dt> + <dd>Django является чрезвычайно популярным и полнофункциональным серверным веб-фреймворком, написанным на Python. Этот модуль объяснит почему Django настолько хороший серверный веб-фреймворк, как установить среду разработки и как с его помощью можно выполнять привычные задачи.</dd> + <dt><a href="/ru/docs/Learn/Server-side/Express_Nodejs">Веб-фреймворк Express (Node.js/JavaScript)</a></dt> + <dd>Express - популярный веб-фреймворк, написанный на JavaScript и размещенный в среде окружения node.js. Модуль объясняет некоторые из ключевых преимуществ этой структуры, как настроить среду разработки и как выполнять общие задачи для веб-разработки и развертывания.</dd> + <dt><a href="https://developer.mozilla.org/ru/docs/Learn/Server-side/Node_server_without_framework">Сервер на Node без фреймворков</a></dt> + <dd>В этой статье представлен простой статический файловый сервер, построенный с использованием чистого Node.js, для тех из вас, кто не хочет использовать фреймворк.</dd> +</dl> diff --git a/files/ru/learn/server-side/node_server_without_framework/index.html b/files/ru/learn/server-side/node_server_without_framework/index.html new file mode 100644 index 0000000000..087627c20a --- /dev/null +++ b/files/ru/learn/server-side/node_server_without_framework/index.html @@ -0,0 +1,84 @@ +--- +title: Node.js server without a framework +slug: Learn/Server-side/Node_server_without_framework +translation_of: Learn/Server-side/Node_server_without_framework +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Здесь вы найдете описание простого статического сервера, который построен сугубо на Node.js без использования какого-либо фреймворка .</p> + +<p><a href="https://nodejs.org/en/">Node.js</a> может использовать множество фреймворков, которые могут помочь создать сервер</p> + +<p>Наиболее популярные:</p> + +<ul> + <li><a href="http://expressjs.com/">Express</a>: Один из наиболее популярных фреймворков.</li> + <li><a href="https://hapijs.com/">Hapi.js</a>: Набирающий популярность фреймворк для построения приложений и сервисов</li> + <li><a href="https://www.totaljs.com/">Total</a>: Этот фреймворк имеет богатый функционал и не требует каких-либо дополнительных фреймворков или библиотек.</li> +</ul> + +<p>Конечно-же эти фреймворки могут и не подойти для каждого конкретного случая. Именно поэтому нужно знать как все работает изнутри, чтобы быть готовым сделать свой собственный сервер без каких-либо дополнительных зависимостей.</p> + +<h2 id="Пример">Пример</h2> + +<p>Вот так выглядит статический сервер на Node.js:</p> + +<pre class="brush: js">var http = require('http'); +var fs = require('fs'); +var path = require('path'); + +http.createServer(function (request, response) { + console.log('request ', request.url); + + var filePath = '.' + request.url; + if (filePath == './') { + filePath = './index.html'; + } + + var extname = String(path.extname(filePath)).toLowerCase(); + var contentType = 'text/html'; + var mimeTypes = { + '.html': 'text/html', + '.js': 'text/javascript', + '.css': 'text/css', + '.json': 'application/json', + '.png': 'image/png', + '.jpg': 'image/jpg', + '.gif': 'image/gif', + '.wav': 'audio/wav', + '.mp4': 'video/mp4', + '.woff': 'application/font-woff', + '.ttf': 'application/font-ttf', + '.eot': 'application/vnd.ms-fontobject', + '.otf': 'application/font-otf', + '.svg': 'application/image/svg+xml' + }; + + contentType = mimeTypes[extname] || 'application/octet-stream'; + + fs.readFile(filePath, function(error, content) { + if (error) { + if(error.code == 'ENOENT'){ + fs.readFile('./404.html', function(error, content) { + response.writeHead(200, { 'Content-Type': contentType }); + response.end(content, 'utf-8'); + }); + } + else { + response.writeHead(500); + response.end('Sorry, check with the site admin for error: '+error.code+' ..\n'); + response.end(); + } + } + else { + response.writeHead(200, { 'Content-Type': contentType }); + response.end(content, 'utf-8'); + } + }); + +}).listen(8125); +console.log('Server running at http://127.0.0.1:8125/');</pre> + +<h2 id="Задание">Задание</h2> + +<p>Попробуйте добавить в этот код описание как работает этот код. Как вариант еще можно добавить функционал динамических запросов.</p> diff --git a/files/ru/learn/tools_and_testing/cross_browser_testing/feature_detection/index.html b/files/ru/learn/tools_and_testing/cross_browser_testing/feature_detection/index.html new file mode 100644 index 0000000000..8ddb3ea207 --- /dev/null +++ b/files/ru/learn/tools_and_testing/cross_browser_testing/feature_detection/index.html @@ -0,0 +1,344 @@ +--- +title: Реализация функции обнаружения +slug: Learn/Tools_and_testing/Cross_browser_testing/Feature_detection +translation_of: Learn/Tools_and_testing/Cross_browser_testing/Feature_detection +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Accessibility","Learn/Tools_and_testing/Cross_browser_testing/Automated_testing", "Learn/Tools_and_testing/Cross_browser_testing")}}</div> + +<p class="summary">Обнаружение функций включает определение того, поддерживает ли браузер определенный блок кода, и выполнение другого кода в зависимости от того, поддерживает ли он или нет, так что браузер всегда может обеспечить работу, а не сбой / ошибку в некоторых браузерах. В этой статье подробно описывается, как написать собственное простое обнаружение функций, как использовать библиотеку для ускорения реализации, а также встроенные функции для обнаружения функций, такие как <code>@supports</code>.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предусловия:</th> + <td>Знакомство с основными языками <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, и <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>; идея высокого уровня <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">принципов кросс-браузерного тестирования.</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Понять, что такое концепция выявления функций, и уметь внедрять подходящие решения в CSS и JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Концепция_обнаружения_функций.">Концепция обнаружения функций.</h2> + +<p>Идея обнаружения функции заключается в том, что вы можете запустить тест, чтобы определить, поддерживается ли функция в текущем браузере, а затем условно запустить код, чтобы обеспечить приемлемый опыт как в браузерах, которые поддерживают функцию, так и в браузере, который не поддерживает. Если вы этого не сделаете, браузеры, которые не поддерживают функции, которые вы используете в своем коде, не будут отображать ваши сайты должным образом и просто не сработают, создавая плохой опыт пользователя.</p> + +<p>Давайте подведем итоги и посмотрим на пример, который мы затронули в нашем документе <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#Feature_detection">Решение самых распространненых проблем JavaScript</a>— <a href="/en-US/docs/Web/API/Geolocation/Using_geolocation">Использование геолокации</a> (который предоставляет доступные данные о местоположении для устройства, на котором работает веб-браузер) есть основная точка входа для его использования, свойство <code>geolocation,</code> доступное на глобальном объекте <a href="/en-US/docs/Web/API/Navigator">Navigator</a>. Следовательно, вы можете определить, поддерживает ли браузер геолокацию или нет, используя что-то вроде следующего:</p> + +<pre class="language-js"><span class="keyword token">if </span><span class="punctuation token">(</span><span class="string token">"geolocation"</span> <span class="keyword token">in</span> navigator<span class="punctuation token">)</span> <span class="punctuation token">{</span> + navigator<span class="punctuation token">.</span>geolocation<span class="punctuation token">.</span><span class="function token">getCurrentPosition</span><span class="punctuation token">(</span><span class="keyword token">function</span><span class="punctuation token">(</span>position<span class="punctuation token">)</span> <span class="punctuation token">{</span> + // show the location on a map, perhaps using the Google Maps API + <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">; +}</span> <span class="keyword token">else</span> <span class="punctuation token">{</span> + // Give the user a choice of static maps instead perhaps +<span class="punctuation token">}</span></pre> + +<p>Однако, вероятно, лучше использовать установленную библиотеку обнаружения объектов, а не писать свою собственную все время. Modernizr - это отраслевой стандарт для тестирования функций, и мы рассмотрим это позже.</p> + +<p>Прежде чем мы продолжим, мы хотели бы сразу сказать одну вещь - не путайте обнаружение функций с <strong>перехватом браузера</strong> (обнаружение того, какой конкретный браузер обращается к сайту) - это ужасная практика, от которой следует отказаться любой ценой. См. <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#Using_bad_browser_sniffing_code">Использование плохого кода перехвата браузера</a> для дополнительной информации.</p> + +<h2 id="Написание_ваших_собственных_тестов_обнаружения_функций">Написание ваших собственных тестов обнаружения функций</h2> + +<p>В этом разделе мы рассмотрим реализацию ваших собственных тестов обнаружения функций как в CSS, так и в JavaScript.</p> + +<h3 id="CSS">CSS</h3> + +<p>Вы можете написать тесты для функций CSS, протестировав существование <em><a href="/en-US/docs/Web/API/HTMLElement/style">element.style.property</a></em> (например, <code>paragraph.style.transform</code>) в JavaScript.</p> + +<p>Классическим примером может быть проверка поддержки <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a> в браузере; для браузеров, которые поддерживают новейшие спецификации Flexbox, мы могли бы использовать гибкую и надежную гибкую компоновку. Для браузеров, которые этого не делают, мы могли бы использовать плавающий макет, который работает нормально, хотя он немного более хрупкий и хакерский, и не такой привлекательный.</p> + +<p>Давайте реализуем что-то, что демонстрирует это, хотя мы пока оставим это простым.</p> + +<ol> + <li>Начните с создания локальных копий наших файлов <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/css-feature-detect.html">css-feature-detect.html</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/flex-layout.css">flex-layout.css</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/float-layout.css">float-layout-css</a></code>, и <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/basic-styling.css">basic-styling.css</a></code>. Сохраните их в новой дирекции.</li> + <li>Мы добавим HTML5 Shiv и в наш пример, чтобы семантические элементы HTML5 правильно стилизовались в старых версиях IE. Загрузите последнюю версию (См. <a href="https://github.com/aFarkas/html5shiv#manual-installation">Ручная установка</a>), разархивируйте ZIP, скопируйте файлы <code>html5shiv-printshiv.min.js</code> и <code>html5shiv.min.js</code> в ваш пример дирекции и создайте ссылку на один из файлов, поместив следующее в свой {{htmlelement("title")}} элемент: + <pre><script src="html5shiv.min.js"></script></pre> + </li> + <li>Посмотрите ваши примеры CSS-файлов - вы увидите, что <code>basic-styling.css</code> обрабатывает все стили, которые мы хотим дать каждому браузеру, тогда как два других CSS-файла содержат CSS, который мы хотим выборочно применять к браузеру в зависимости от их уровни поддержки. Вы можете посмотреть на различные эффекты этих двух файлов, вручную изменив CSS-файл, на который ссылается второй элемент {{htmlelement("link")}}, но давайте вместо этого реализуем некоторый JavaScript, чтобы автоматически заменять их при необходимости.</li> + <li>Сначала удалите содержимое атрибута <code>href</code> второго элемента <code><link></code> . Мы будем заполнять это динамически позже.</li> + <li>Затем добавьте элемент <code><script></script></code> внизу вашего контекста (непосредственно перед закрывающим тегом <code></body></code>).</li> + <li>Дайте ему следующее содержание: + <pre class="brush: js">const conditional = document.querySelector('.conditional'); +const testElem = document.createElement('div'); +if (testElem.style.flex !== undefined && testElem.style.flexFlow !== undefined) { + conditional.setAttribute('href', 'flex-layout.css'); +} else { + conditional.setAttribute('href', 'float-layout.css'); +}</pre> + </li> +</ol> + +<p>Здесь мы берем ссылку на второй элемент <code><link></code> и создаем элемент <code><div></code> как часть нашего теста. В нашем условном выражении мы проверяем, что свойства {{cssxref ("flex")}} и {{cssxref ("flex-flow")}} существуют в браузере. Обратите внимание, что представления JavaScript этих свойств, которые хранятся внутри объекта {{domxref ("HTMLElement.style")}}, используют нижний горбатый регистр, а не дефисы, для разделения слов.</p> + +<div class="note"> +<p><strong>Примечание: </strong>Если у вас возникли проблемы с выполнением этого, вы можете сравнить его с нашим кодом <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/css-feature-detect-finished.html">css-feature-detect-finished.html</a> (см. Также <a href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/feature-detection/css-feature-detect-finished.html">живую версию</a>).</p> +</div> + +<p>Когда вы сохраните все и опробуете свой пример, вы должны увидеть макет flexbox, примененный к странице, если браузер поддерживает современный flexbox, и макет float, если нет.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Часто такой подход является излишним из-за незначительной проблемы с обнаружением функций - вы часто можете обойтись без использования префиксов нескольких поставщиков и свойств резервирования, как описано в разделе <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS#CSS_fallback_behaviour">Поведение CSS-откат</a> и <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS#Handling_CSS_prefixes">Обработка префиксов CSS</a>.</p> +</div> + +<h4 id="supports">@supports</h4> + +<p>Недавно, в CSS появился собственный механизм обнаружения собственных функций — {{cssxref("@supports")}} at-rule. Это работает аналогично <a href="/en-US/docs/Web/CSS/Media_Queries">медиазапросам</a> (см. Также <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS#Responsive_design_problems">Адаптивные проблемы дизайна</a>) — за исключением того, что вместо выборочного применения CSS в зависимости от медиа-функции, такой как разрешение, ширина экрана или соотношение сторон, выборочно применяется CSS в зависимости от того, поддерживается ли функция CSS.</p> + +<p>Например, мы могли бы переписать наш предыдущий пример для использования <code>@supports</code> — см. <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/supports-feature-detect.html">supports-feature-detect.html</a></code> и <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/supports-styling.css">supports-styling.css</a></code>. Если вы посмотрите на последнее, вы увидите пару блоков <code>@supports</code> например:</p> + +<pre class="brush: css">@supports (flex-flow: row) and (flex: 1) { + + main { + display: flex; + } + + main div { + padding-right: 4%; + flex: 1; + } + + main div:last-child { + padding-right: 0; + } + +}</pre> + +<p>Этот блок at-rule применяет правило CSS только в том случае, если текущий браузер поддерживает объявления как <code>flex-flow: row</code> так и <code>flex: 1</code>. Чтобы каждое условие работало, вам необходимо включить полное объявление (а не просто имя свойства) и НЕ включать точку с запятой в конце.</p> + +<p><code>@supports</code> также имеет логику <code>OR</code> и <code>NOT</code> — другой блок применяет разметку с плавающей запятой, если свойства flexbox недоступны:</p> + +<pre class="brush: css">@supports not (flex-flow: row) and (flex: 1) { + + /* rules in here */ + +}</pre> + +<p>Это может выглядеть намного удобнее, чем в предыдущем примере - мы можем выполнять все наши функции обнаружения в CSS, JavaScript не требуется, и мы можем обрабатывать всю логику в одном файле CSS, сокращая HTTP-запросы. Проблема здесь в поддержке браузера — <code>@supports</code> вообще не поддерживается в IE, а поддерживается только в самых последних версиях Safari / iOS WebKit (9 + / 9.2 +), тогда как версия JavaScript должна работать в гораздо более старых браузерах (вероятно, назад до IE8 или 9, хотя в более старых версиях IE будут возникать дополнительные проблемы, такие как отсутствие поддержки {{domxref ("Document.querySelector")}} и наличие испорченной блочной модели).</p> + +<h3 id="JavaScript">JavaScript</h3> + +<p>Мы уже видели пример теста на обнаружение функций JavaScript ранее. Как правило, такие тесты выполняются по одному из следующих общих шаблонов:</p> + +<table class="standard-table"> + <caption>Краткое изложение методов обнаружения функций JavaScript</caption> + <thead> + <tr> + <th scope="col">Тип обнаружения функции</th> + <th scope="col">Объяснение</th> + <th scope="col">Пример</th> + </tr> + </thead> + <tbody> + <tr> + <td><em>Если член в объекте</em></td> + <td>Проверьте, существует ли определенный метод или свойство (обычно точка входа в использование API или другой функции, которую вы обнаруживаете) в его родительском объекте.</td> + <td> + <p><code>if("geolocation" in navigator) { ... }</code></p> + </td> + </tr> + <tr> + <td><em>Свойство на элементе</em></td> + <td>Создайте элемент в памяти, используя {{domxref ("Document.createElement()")}}, а затем проверьте, существует ли свойство для него. Показанный пример является способом определения поддержки <a href="/en-US/docs/Web/API/Canvas_API">HTML5 Canvas</a>.</td> + <td><code>function supports_canvas() {<br> + return !!document.createElement('canvas').getContext;<br> + }<br> + <br> + if(supports_canvas()) { ... }</code></td> + </tr> + <tr> + <td><em>Метод на возвращаемое значение элемента</em></td> + <td>Создайте элемент в памяти, используя {{domxref ("Document.createElement()")}}, а затем проверьте, существует ли метод для него. Если это так, проверьте, какое значение он возвращает.</td> + <td>См. <a href="http://diveinto.html5doctor.com/detect.html#video-formats">Dive Into HTML5 Video Formats detection</a>.</td> + </tr> + <tr> + <td><em>Свойство на сохраняемое значение элемента</em></td> + <td>Создайте элемент в памяти, используя {{domxref ("Document.createElement()")}}, установите для свойства определенное значение, затем проверьте, сохраняется ли значение.</td> + <td>См. <a href="http://diveinto.html5doctor.com/detect.html#input-types">Dive into HTML5 <code><input></code> types detection</a>.</td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Примечание:</strong> Двойное <code>NOT</code> в приведенном выше примере (<code>!!</code>) это способ заставить возвращаемое значение стать «правильным» логическим значением, а не {{glossary("Truthy")}}/{{glossary("Falsy")}} значение, которое может исказить результаты.</p> +</div> + +<p>Страница <a href="http://diveinto.html5doctor.com/detect.html">Погружение в HTML5 Обнаружение функций HTML5</a> содержит гораздо больше полезных тестов для обнаружения функций, помимо перечисленных выше, и вы можете найти тест обнаружения функций для большинства вещей, выполнив поиск «обнаружение поддержки для ВАШИ-ФУНКЦИИ-ЗДЕСЬ» в своей любимой поисковой системе. Имейте в виду, однако, что некоторые функции, как известно, не обнаруживаются - см. список Modernizr <a href="https://github.com/Modernizr/Modernizr/wiki/Undetectables">Необнаруживаемые</a>.</p> + +<h4 id="matchMedia">matchMedia</h4> + +<p>Мы также хотели упомянуть функцию JavaScript {{domxref("Window.matchMedia")}} на этом этапе. Это свойство, которое позволяет вам запускать тесты медиа-запросов внутри JavaScript. Это выглядит так:</p> + +<pre class="brush: js">if (window.matchMedia("(max-width: 480px)").matches) { + // run JavaScript in here. +}</pre> + +<p>В качестве примера, наша демо версия <a href="https://github.com/chrisdavidmills/snapshot">Snapshot</a> использует ее для выборочного применения библиотеки Brick JavaScript и ее использования для обработки макета пользовательского интерфейса, но только для небольшого экрана (шириной 480 пикселей или меньше). Сначала мы используем атрибут <code>media</code>,чтобы применить CSS-код Brick к странице, только если ширина страницы составляет 480px или меньше:</p> + +<pre class="brush: css"><<span class="pl-ent">link</span> <span class="pl-e">href</span>=<span class="pl-s"><span class="pl-pds">"</span>dist/brick.css<span class="pl-pds">"</span></span> <span class="pl-e">type</span>=<span class="pl-s"><span class="pl-pds">"</span>text/css<span class="pl-pds">"</span></span> <span class="pl-e">rel</span>=<span class="pl-s"><span class="pl-pds">"</span>stylesheet<span class="pl-pds">"</span></span> <span class="pl-e">media</span>=<span class="pl-s"><span class="pl-pds">"</span>all and (max-width: 480px)<span class="pl-pds">"</span></span>></pre> + +<p>Затем мы используем <code>matchMedia()</code> в JavaScript несколько раз, чтобы запускать функции навигации Brick только в том случае, если мы на маленьком экране (в более широких экранах все можно увидеть сразу, поэтому нам не нужно переходить между различными изображениями).</p> + +<pre class="brush: js">if (window.matchMedia("(max-width: 480px)").matches) { + deck.shuffleTo(1); +}</pre> + +<h2 id="Использование_Modernizr_для_реализации_обнаружения_функций">Использование Modernizr для реализации обнаружения функций</h2> + +<p>Можно реализовать свои собственные тесты обнаружения функций, используя методы, подобные тем, которые подробно описаны выше. Вы можете также использовать специальную библиотеку обнаружения функций, так как она всё упрощает. Основой всех библиотек обнаружения функций является <a href="https://modernizr.com/">Modernizr</a>, и он может обнаружить практически все, что вам когда-либо понадобится. Давайте посмотрим, как его использовать.</p> + +<p>Когда вы экспериментируете с Modernizr, вы также можете использовать сборку разработки, которая включает в себя все возможные тесты обнаружения функций. Скачать:</p> + +<ol> + <li>Нажав на ссылку <a href="https://modernizr.com/download?do_not_use_in_production">Сборка разработки</a>.</li> + <li>Нажав на большую розовую кнопку <em>Build</em> на появившейся странице.</li> + <li>Нажав на верхнюю ссылку <em>Download</em> в появившемся диалоговом окне.</li> +</ol> + +<p>Сохраните его где-нибудь разумно, например, в директории, для которой вы создавали другие примеры в этой статье.</p> + +<p>Когда вы используете Modernizr в рабочей среде, вы можете перейти на <a href="https://modernizr.com/download">Страницу скачивания</a> которую вы уже посетили, и нажимать кнопки плюс только для тех функций, которые вам нужны. Затем, когда вы нажмете кнопку <em>Build</em> вы загрузите пользовательскую сборку, содержащую только те функции, которые обнаружены, что позволит значительно уменьшить размер файла.</p> + +<h3 id="CSS_2">CSS</h3> + +<p>Давайте посмотрим, как Modernizr работает с точки зрения избирательного применения CSS.</p> + +<ol> + <li>Во-первых, создайте копию <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/supports-feature-detect.html">supports-feature-detect.html</a></code> и <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/supports-styling.css">supports-styling.css</a></code>. Сохраните их как <code>modernizr-css.html</code> и <code>modernizr-css.css</code>.</li> + <li>Обновите ваш элемент {{htmlelement ("link")}} в своем HTML-коде, чтобы он указывал на правильный файл CSS (также следует обновить элемент {{htmlelement ("title")}} на что-то более подходящее!): + <pre class="brush: html"><link href="modernizr-css.css" rel="stylesheet"></pre> + </li> + <li>Над этим элементом <code><link></code> добавьте элемент {{htmlelement ("script")}}, чтобы применить библиотеку Modernizr к странице, как показано ниже. Это должно быть применено к странице перед любым CSS (или JavaScript), который может ее использовать. + <pre class="brush: html"><script src="modernizr-custom.js"></script></pre> + </li> + <li>Теперь отредактируйте открывающий тег <code><html></code>, чтобы он выглядел так: + <pre class="brush: html"><html class="no-js"></pre> + </li> +</ol> + +<p>На этом этапе попробуйте загрузить свою страницу, и вы получите представление о том, как Modernizr работает с функциями CSS. Если вы посмотрите на инспектор DOM инструментов разработчика вашего браузера, вы увидите, что Modernizr обновил значение вашего <code><html></code> <code>class</code> следующим образом:</p> + +<pre><html class="js no-htmlimports sizes flash transferables applicationcache blobconstructor +blob-constructor cookies cors ...AND LOADS MORE VALUES!></pre> + +<p>Теперь он содержит большое количество классов, которые указывают на состояние поддержки различных функций. Например, если браузер вообще не поддерживает flexbox, <code><html></code> будет присвоено имя класса <code>no-flexbox</code>. Если бы он поддерживал современный flexbox, он получил бы имя класса <code>flexbox</code>. Если вы выполните поиск в списке классов, вы также увидите другие, относящиеся к flexbox, например:</p> + +<ul> + <li><code>flexboxlegacy</code> для старой спецификации flexbox (2009).</li> + <li><code>flexboxtweener</code> для промежуточного синтаксиса 2011 года, поддерживаемого IE10.</li> + <li><code>flexwrap</code> для свойства {{cssxref ("flex-wrap")}}, которого нет в некоторых реализациях.</li> +</ul> + +<div class="note"> +<p><strong>Примечание:</strong> Вы можете найти список того, что означают все имена классов — см. <a href="https://modernizr.com/docs#features">Функции, обнаруженные Modernizr</a>.</p> +</div> + +<p>Далее, давайте обновим наш CSS, чтобы использовать Modernizr вместо <code>@supports</code>. Перейдите в <code>modernizr-css.css</code>, и замените два блока <code>@supports</code> следующим:</p> + +<pre class="brush: css">/* Properties for browsers with modern flexbox */ + +.flexbox main { + display: flex; +} + +.flexbox main div { + padding-right: 4%; + flex: 1; +} + +.flexbox main div:last-child { + padding-right: 0; +} + +/* Fallbacks for browsers that don't support modern flexbox */ + +.no-flexbox main div { + width: 22%; + float: left; + padding-right: 4%; +} + +.no-flexbox main div:last-child { + padding-right: 0; +} + +.no-flexbox footer { + clear: left; +}</pre> + +<p>Так как же это работает? Поскольку все эти имена классов были помещены в элемент <code><html></code> вы можете настроить таргетинг на браузеры, которые поддерживают или не поддерживают функцию, используя определенные селекторы-потомки. Поэтому здесь мы применяем верхний набор правил только для браузеров, которые поддерживают flexbox, а нижний набор правил - только для браузеров, которые не поддерживают (<code>no-flexbox</code>).</p> + +<div class="note"> +<p><strong>Примечание:</strong> Имейте в виду, что все тесты функций HTML и JavaScript Modernizr также представлены в этих именах классов, так что вы можете свободно применять CSS выборочно в зависимости от того, поддерживает ли браузер функции HTML или JavaScript, если это необходимо.</p> +</div> + +<div class="note"> +<p><strong>Примечание:</strong> Если у вас возникли проблемы с выполнением этого, проверьте ваш код по файлам <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/modernizr-css.html">modernizr-css.html</a></code> и <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/modernizr-css.css">modernizr-css.css</a></code> (см. Также этот запуск в реальном времени).</p> +</div> + +<h3 id="JavaScript_2">JavaScript</h3> + +<p>Modernizr также одинаково хорошо подготовлен для реализации функций обнаружения JavaScript. Это достигается за счет того, что глобальный объект <code>Modernizr</code> становится доступным для страницы, к которой он применяется, и содержит результаты функции, определяемой как свойства <code>true</code>/<code>false</code>.</p> + +<p>Например, загрузите наш пример <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/modernizr-css.html">modernizr-css.html</a></code> в своем браузере, затем попробуйте перейти на консоль JavaScript и набрать <code>Modernizr.</code>, а после некоторые из этих имен классов (они тоже здесь одинаковы). Например:</p> + +<pre>Modernizr.flexbox +Modernizr.websqldatabase +Modernizr.xhr2 +Modernizr.fetch</pre> + +<p>Консоль вернет значения <code>true</code>/<code>false</code>, чтобы указать, поддерживает ли ваш браузер эти функции или нет.</p> + +<p>Давайте посмотрим на пример, чтобы показать, как вы бы пользовали эти свойства.</p> + +<ol> + <li>Прежде всего, сделайте локальную копию файла примера <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/modernizr-js.html">modernizr-js.html</a></code>.</li> + <li>Присоедините библиотеку Modernizr к HTML, используя элемент <code><script></code> , как мы делали в предыдущих демонстрациях. Поместите его над существующим элементом <code><script></code> который прикрепляет API Google Maps к странице.</li> + <li>Затем заполните текст-заполнитель <code>YOUR-API-KEY</code> во втором элементе <code><script></code> (как он есть сейчас) действительным ключом API Google Maps. Чтобы получить ключ, войдите в учетную запись Google, перейдите на страницу <a href="https://developers.google.com/maps/documentation/javascript/get-api-key">Получить ключ / Аутентификация</a> затем нажмите синюю кнопку <em>Get a Key</em> и следуйте инструкциям.</li> + <li>Наконец, добавьте еще один элемент <code><script></code> внизу тела HTML (непосредственно перед тегом <code></body></code> ) и поместите следующий скрипт в теги: + <pre class="brush: js">if (Modernizr.geolocation) { + + navigator.geolocation.getCurrentPosition(function(position) { + + let latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude); + let myOptions = { + zoom: 8, + center: latlng, + mapTypeId: google.maps.MapTypeId.TERRAIN, + disableDefaultUI: true + } + let map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); + }); + +} else { + const para = document.createElement('p'); + para.textContent = 'Argh, no geolocation!'; + document.body.appendChild(para); +}</pre> + </li> +</ol> + +<p>Опробуйте свой пример! Здесь мы используем тест <code>Modernizr.geolocation</code>, чтобы проверить, поддерживается ли геолокация текущим браузером. Если это так, мы запускаем некоторый код, который получает текущее местоположение вашего устройства и отображает его на карте Google.</p> + +<h2 id="Подведение_итогов">Подведение итогов</h2> + +<p>В этой статье было рассмотрено обнаружение функций с достаточным количеством подробностей, рассмотрены основные концепции и показано, как реализовать свои собственные тесты обнаружения функций и использовать библиотеку Modernizr для более легкой реализации тестов.</p> + +<p>Далее мы начнем изучать автоматизированное тестирование.</p> + +<p>{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Accessibility","Learn/Tools_and_testing/Cross_browser_testing/Automated_testing", "Learn/Tools_and_testing/Cross_browser_testing")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">Введение в кросс-браузерное тестирование</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies">Стратегии проведения тестирования</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS">Решение распространенных проблем HTML и CSS</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Решение распространенных проблем JavaScript</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility">Решение распространенных проблем доступности</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">Реализация функции обнаружения</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Automated_testing">Введение в автоматизированное тестирование</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Настройка собственной среды автоматизации тестирования</a></li> +</ul> diff --git a/files/ru/learn/tools_and_testing/cross_browser_testing/html_and_css/index.html b/files/ru/learn/tools_and_testing/cross_browser_testing/html_and_css/index.html new file mode 100644 index 0000000000..64ff9cafcc --- /dev/null +++ b/files/ru/learn/tools_and_testing/cross_browser_testing/html_and_css/index.html @@ -0,0 +1,487 @@ +--- +title: Handling common HTML and CSS problems +slug: Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS +translation_of: Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies","Learn/Tools_and_testing/Cross_browser_testing/JavaScript", "Learn/Tools_and_testing/Cross_browser_testing")}}</div> + +<p class="summary">With the scene set, we'll now look specifically at the common cross-browser problems you will come across in HTML and CSS code, and what tools can be used to prevent problems from happening, or fix problems that occur. This includes linting code, handling CSS prefixes, using browser dev tools to track down problems, using polyfills to add support into browsers, tackling responsive design problems, and more.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Пререквизиты:</th> + <td>Знакомство с основами <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, и <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>; идея высокого уровня <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">кросс-браузерного тестирования</a></td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Иметь возможность находить распространенные кросс-браузерные проблемы HTML и CSS, использовать нужные инструменты и методы для их устранения</td> + </tr> + </tbody> +</table> + +<h2 id="The_trouble_with_HTML_and_CSS">The trouble with HTML and CSS</h2> + +<p>Some of the trouble with HTML and CSS lies with the fact that both languages are fairly simple, and often developers don't take them seriously, in terms of making sure the code is well-crafted, efficient, and semantically describes the purpose of the features on the page. In the worst cases, JavaScript is used to generate the entire web page content and style, which makes your pages inaccessible, and less performant (generating DOM elements is expensive). In other cases, nascent features are not supported consistently across browsers, which can make some features and styles not work for some users. Responsive design problems are also common — a site that looks good in a desktop browser might provide a terrible experience on a mobile device, because the content is too small to read, or perhaps the site is slow because of expensive animations.</p> + +<p>Let's go forth and look at how we can reduce cross browser errors that result from HTML/CSS.</p> + +<h2 id="First_things_first_fixing_general_problems">First things first: fixing general problems</h2> + +<p>We said in the <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction#Testingdiscovery">first article of this series</a> that a good strategy to begin with is to test in a couple of modern browsers on desktop/mobile, to make sure your code is working generally, before going on to concentrate on the cross browser issues.</p> + +<p>In our <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a> and <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Debugging_CSS">Debugging CSS</a> articles, we provided some really basic guidance on debugging HTML/CSS — if you are not familiar with the basics, you should definitely study these articles before carrying on.</p> + +<p>Basically, it is a matter of checking whether your HTML and CSS code is well formed and doesn't contain any syntax errors.</p> + +<div class="note"> +<p><strong>Note</strong>: One common problem with CSS and HTML arises when different CSS rules begin to conflict with one another. This can be especially problematic when you are using third party code. For example, you might use a CSS framework and find that one of the class names it uses clashes with one you've already used for a different purpose. Or you might find that HTML generated by some kind of third party API (generating ad banners, for example) includes a class name or ID that you are already using for a different purpose. To ensure this doesn't happen, you need to research the tools you are using first and design your code around them. It is also worth "namespacing" CSS, e.g. if you have a widget, make sure it has a distinct class, and then start the selectors that select elements inside the widget with this class, so conflicts are less likely. For example <code>.audio-player ul a</code>.</p> +</div> + +<h3 id="Validation">Validation</h3> + +<p>For HTML, validation involves making sure all your tags are properly closed and nested, you are using a DOCTYPE, and you are using tags for their correct purpose. A good strategy is to validate your code regularly. One service that can do this is the W3C <a class="external external-icon" href="https://validator.w3.org/">Markup Validation Service</a>, which allows you to point to your code, and returns a list of errors:</p> + +<p><img alt="The HTML validator homepage" src="https://mdn.mozillademos.org/files/12441/validator.png" style="display: block; margin: 0px auto;"></p> + +<p>CSS has a similar story — you need to check that your property names are spelled correctly, property values are spelled correctly and are valid for the properties they are used on, you are not missing any curly braces, and so on. The W3C has a <a class="external external-icon" href="http://jigsaw.w3.org/css-validator/">CSS Validator</a> available too, for this purpose.</p> + +<h3 id="Linters">Linters</h3> + +<p>Another good option to choose is a so-called Linter application, which not only points out errors, but can also flag up warnings about bad practices in your CSS, and other points besides. Linters can generally be customized to be stricter or more relaxed in their error/warning reporting.</p> + +<p>There are many online linter applications, the best of which are probably <a href="https://www.dirtymarkup.com/">Dirty Markup</a> (HTML, CSS, JavaScript), and <a href="http://csslint.net/">CSS Lint</a> (CSS only). These allows you to paste your code into a window, and it will flag up any errors with crosses, which can then be hovered to get an error message informing you what the problem is. Dirty Markup also allows you to make fixes to your markup using the <em>Clean</em> button.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14113/dirty-markup.png" style="border-style: solid; border-width: 1px; display: block; height: 203px; margin: 0px auto; width: 1204px;"></p> + +<p>However, it is not very convenient to have to copy and paste your code over to a web page to check its validity several times. What you really want is a linter that will fit into your standard workflow with the minimum of hassle.</p> + +<p>Many code editors have linter plugins. Github's <a href="https://atom.io/">Atom</a> code editor for example has a rich plugin ecosystem available, with many linting options. To show you an example of how such plugins generally work:</p> + +<ol> + <li>Install Atom (if you haven't got an up-to-date version already installed) — download it from the Atom page linked above.</li> + <li>Go to Atom's <em>Preferences...</em> dialog (e.g. by Choosing <em>Atom > Preferences...</em> on Mac, or <em>File > Preferences...</em> on Windows/Linux) and choose the <em>Install</em> option in the left hand menu.</li> + <li>In the <em>Search packages</em> text field, type "lint" and press Enter/Return to search for linting-related packages.</li> + <li>You should see a package called <strong>lint</strong> at the top of the list. Install this first (using the <em>Install</em> button), as other linters rely on it to work. After that, install the <strong>linter-csslint</strong> plugin for linting CSS, and the <strong>linter-tidy</strong> plugin for linting HTML.</li> + <li>After the packages have finished installing, try loading up an HTML file and a CSS file: you'll see any issues highlighted with green (for warnings) and red (for errors) circles next to the line numbers, and a separate panel at the bottom provides line numbers, error messages, and sometimes suggested values or other fixes.</li> +</ol> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14109/atom-htmltidy.png" style="display: block; margin: 0 auto;"><img alt="" src="https://mdn.mozillademos.org/files/14107/atom-csslint.png" style="display: block; height: 516px; margin: 0px auto; width: 700px;"></p> + +<p>Other popular editors have similar linting packages available. For example, see:</p> + +<ul> + <li><a href="www.sublimelinter.com/">SublimeLinter</a> for Sublime Text</li> + <li><a href="https://sourceforge.net/projects/notepad-linter/">Notepad++ linter</a></li> +</ul> + +<h3 id="Browser_developer_tools">Browser developer tools</h3> + +<p>The developer tools built into most browsers also feature useful tools for hunting down errors, mainly for CSS.</p> + +<div class="note"> +<p><strong>Note</strong>: HTML errors don't tend to show up so easily in dev tools, as the browser will try to correct badly-formed markup automatically; the W3C validator is the best way to get HTML errors — see {{anch("Validation")}} above.</p> +</div> + +<p>As an example, in Firefox the CSS inspector will show CSS declarations that aren't applied crossed out, with a warning triangle. Hovering the warning triangle will provide a descriptive error message:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14111/css-message-devtools.png" style="display: block; height: 311px; margin: 0px auto; width: 451px;"></p> + +<p>Other browser devtools have similar features.</p> + +<h2 id="Common_cross_browser_problems">Common cross browser problems</h2> + +<p>Now let's move on to look at some of the most common cross browser HTML and CSS problems. The main areas we'll look at are lack of support for modern features, and layout issues.</p> + +<h3 id="Older_browsers_not_supporting_modern_features">Older browsers not supporting modern features</h3> + +<p>This is a common problem, especially when you need to support old browsers (such as old IE versions) or you are using features that are implemented using CSS prefixes. In general, most core HTML and CSS functionality (such as basic HTML elements, CSS basic colors and text styling) works across most browsers you'll want to support; more problems are uncovered when you start wanting to use newer features such as <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a>, or <a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery">HTML5 video/audio</a>, or even more nascent, <a href="/en-US/docs/Learn/CSS/CSS_layout/Grids#Native_CSS_Grids_with_Grid_Layout">CSS Grids</a> or <a href="/en-US/docs/Learn/CSS/Styling_boxes/Advanced_box_effects#-webkit-background-clip_text">-webkit-background-clip: text</a>.</p> + +<p>Once you've identified a list of potential problem technologies you will be using, it is a good idea to research what browsers they are supported in, and what related techniques are useful. See {{anch("Finding help")}} below.</p> + +<h4 id="HTML_fallback_behaviour">HTML fallback behaviour</h4> + +<p>Some problems can be solved by just taking advantage of the natural way in which HTML/CSS work.</p> + +<p>Unrecognised HTML elements are treated by the browser as anonymous inline elements (effectively inline elements with no semantic value, similar to {{htmlelement("span")}} elements). You can still refer to them by their names, and style them with CSS, for example — you just need to make sure they are behaving as you want them to, for example setting <code>display: block;</code> on all of the new semantic elements (such as {{htmlelement("article")}}, {{htmlelement("aside")}}, etc.), but only in old versions of IE that don't recognise them (so, IE 8 and lower). This way new browsers can just use the code as normal, but older IE versions will be able to style these elements too.</p> + +<div class="note"> +<p><strong>Note</strong>: See {{anch("IE conditional comments")}} for the best way to do this.</p> +</div> + +<p>More complex elements like HTML <code><a href="/en-US/docs/Web/HTML/Element/video"><video></a></code>, <code><a href="/en-US/docs/Web/HTML/Element/audio"><audio></a></code>, and <code><a href="/en-US/docs/Web/HTML/Element/canvas"><canvas></a></code> (and other features besides) have natural mechanisms for fallbacks to be added, which work on the same principle as described above. You can add fallback content in between the opening and closing tags, and non-supporting browsers will effectively ignore the outer element and run the nested content.</p> + +<p>For example:</p> + +<pre class="brush: html"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>video</span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>video<span class="punctuation token">"</span></span> <span class="attr-name token">controls</span> <span class="attr-name token">preload</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>metadata<span class="punctuation token">"</span></span> <span class="attr-name token">poster</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>img/poster.jpg<span class="punctuation token">"</span></span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>source</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>video/tears-of-steel-battle-clip-medium.mp4<span class="punctuation token">"</span></span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>video/mp4<span class="punctuation token">"</span></span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"> <</span>source</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>video/tears-of-steel-battle-clip-medium.webm<span class="punctuation token">"</span></span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>video/webm<span class="punctuation token">"</span></span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>source</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>video/tears-of-steel-battle-clip-medium.ogg<span class="punctuation token">"</span></span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>video/ogg<span class="punctuation token">"</span></span><span class="punctuation token">></span></span> + <span class="comment token"><!-- Flash fallback --></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>object</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>application/x-shockwave-flash<span class="punctuation token">"</span></span> <span class="attr-name token">data</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>flash-player.swf?videoUrl<span class="punctuation token">=</span>video/tears-of-steel-battle-clip-medium.mp4<span class="punctuation token">"</span></span> <span class="attr-name token">width</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>1024<span class="punctuation token">"</span></span> <span class="attr-name token">height</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>576<span class="punctuation token">"</span></span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>param</span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>movie<span class="punctuation token">"</span></span> <span class="attr-name token">value</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>flash-player.swf?videoUrl<span class="punctuation token">=</span>video/tears-of-steel-battle-clip-medium.mp4<span class="punctuation token">"</span></span> <span class="punctuation token">/></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>param</span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>allowfullscreen<span class="punctuation token">"</span></span> <span class="attr-name token">value</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>true<span class="punctuation token">"</span></span> <span class="punctuation token">/></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>param</span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>wmode<span class="punctuation token">"</span></span> <span class="attr-name token">value</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>transparent<span class="punctuation token">"</span></span> <span class="punctuation token">/></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>param</span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>flashvars<span class="punctuation token">"</span></span> <span class="attr-name token">value</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>controlbar<span class="punctuation token">=</span>over&amp;image<span class="punctuation token">=</span>img/poster.jpg&amp;file<span class="punctuation token">=</span>flash-player.swf?videoUrl<span class="punctuation token">=</span>video/tears-of-steel-battle-clip-medium.mp4<span class="punctuation token">"</span></span> <span class="punctuation token">/></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>img</span> <span class="attr-name token">alt</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>Tears of Steel poster image<span class="punctuation token">"</span></span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>img/poster.jpg<span class="punctuation token">"</span></span> <span class="attr-name token">width</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>1024<span class="punctuation token">"</span></span> <span class="attr-name token">height</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>428<span class="punctuation token">"</span></span> <span class="attr-name token">title</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>No video playback possible, please download the video from the link below<span class="punctuation token">"</span></span> <span class="punctuation token">/></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"></</span>object</span><span class="punctuation token">></span></span> + <span class="comment token"><!-- Offer download --></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>a</span> <span class="attr-name token">href</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>video/tears-of-steel-battle-clip-medium.mp4<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>Download MP4<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>a</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>video</span><span class="punctuation token">></span></span></code></pre> + +<p>This example (taken from <a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery/cross_browser_video_player">Creating a cross-browser video player</a>) includes not only a Flash video fallback for older IE versions, but also a simple link allowing you to download the video if even the Flash player doesn't work, so at least the user can still access the video.</p> + +<div class="note"> +<p><strong>Note</strong>: 3rd party libraries like <a href="http://videojs.com/">Video.js</a> and <a href="https://www.jwplayer.com/">JW Player</a> use such fallback mechanisms to provide cross-browser support.</p> +</div> + +<p>HTML5 form elements also exhibit fallback qualities — HTML5 introduced some special <code><a href="/en-US/docs/Web/HTML/Element/input"><input></a></code> types for inputting specific information into forms, such as times, dates, colors, numbers, etc. These are very useful, particularly on mobile platforms, where providing a pain-free way of entering data is very important for the user experience. Supporting platforms provide special UI widgets when these input types are used, such as a calendar widget for entering dates.</p> + +<p>The following example shows date and time inputs:</p> + +<pre class="brush: html"><form> + <div> + <label for="date">Enter a date:</label> + <input id="date" type="date"> + </div> + <div> + <label for="time">Enter a time:</label> + <input id="time" type="time"> + </div> +</form></pre> + +<p>The output of this code is as follows:</p> + +<div class="hidden"> +<h6 id="Hidden_example">Hidden example</h6> + +<pre class="brush: css">label { + float: left; + width: 30%; + text-align: right; + } + + input { + float: right; + width: 65%; + } + + label, input { + margin-bottom: 20px; + } + + div { + clear: both; + margin: 10px; + } + + body { + width: 400px; + margin: 0 auto; + }</pre> + +<p> </p> + +<pre class="brush: html"><form> + <div> + <label for="date">Enter a date:</label> + <input id="date" type="date"> + </div> + <div> + <label for="time">Enter a time:</label> + <input id="time" type="time"> + </div> + </form></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_example', '100%', 150) }}</p> + +<div class="note"> +<p><strong>Note</strong>: You can also see this running live as <a href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/html-css/forms-test.html">forms-test.html</a> on GitHub (see the <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/html-css/forms-test.html">source code</a> also).</p> +</div> + +<p>If you view the example on a supporting browser like desktop/Android Chrome or iOS Safari, you'll see the special widgets/features in action as you try to input data. On a non-supporting platform such as Firefox or Internet Explorer, the inputs will just fallback to normal text inputs, so at least the user can still enter some information.</p> + +<p>Note: Of course, this may not be a great solution for your project's needs — the difference in visual presentation is not great, plus it is harder to guarantee the data will be entered in the format you want it in. For cross browser forms, It is probably better to rely on simple form elements, or selectively using advanced form elements only in supporting browsers, or using a library that provides decent cross browser form widgets, such as <a href="http://jqueryui.com/">jQuery UI</a> or <a href="https://bootstrap-datepicker.readthedocs.io/en/latest/">Bootstrap datepicker</a>.</p> + +<h4 id="CSS_fallback_behaviour">CSS fallback behaviour</h4> + +<p>CSS is arguably better at fallbacks than HTML. If a browser encounters a declaration or rule it doesn't understand, it just skips it completely without applying it or throwing an error. This might be frustrating for you and your users if such a mistake slips through to production code, but at least it means the whole site doesn't come crashing down because of one error, and if used cleverly you can use it to your advantage.</p> + +<p>Let's look at an example — a simple box styled with CSS, which has some styling provided by various CSS3 features:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14141/blingy-button.png" style="display: block; margin: 0 auto;"></p> + +<div class="note"> +<p><strong>Note</strong>: You can also see this example running live on GitHub as <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/html-css/button-with-fallback.html">button-with-fallback.html</a> (also see the <a href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/html-css/button-with-fallback.html">source code</a>).</p> +</div> + +<p>The button has a number of declarations that style, but the two we are most interested in are as follows:</p> + +<pre class="brush: css">button { + ... + + background-color: #ff0000; + background-color: rgba(255,0,0,1); + box-shadow: inset 1px 1px 3px rgba(255,255,255,0.4), + inset -1px -1px 3px rgba(0,0,0,0.4); +} + +button:hover { + background-color: rgba(255,0,0,0.5); +} + +button:active { + box-shadow: inset 1px 1px 3px rgba(0,0,0,0.4), + inset -1px -1px 3px rgba(255,255,255,0.4); +}</pre> + +<p>Here we are providing an <a href="/en-US/docs/Web/CSS/color_value#rgba()">RGBA</a> {{cssxref("background-color")}} that changes opacity on hover to give the user a hint that the button is interactive, and some semi-transparent inset {{cssxref("box-shadow")}} shades to give the button a bit of texture and depth. The trouble is that RGBA colors and box shadows don't work in IE versions older than 9 — in older versions the background just wouldn't show up at all so the text would be unreadable, no good at all!</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14135/unreadable-button.png" style="display: block; margin: 0 auto;"></p> + +<p>To sort this out, we have added a second <code>background-color</code> declaration, which just specifies a hex color — this is supported way back in really old browsers, and acts as a fallback if the modern shiny features don't work. What happens is a browser visiting this page first applies the first <code>background-color</code> value; when it gets to the second <code>background-color</code> declaration, it will override the initial value with this value if it supports RGBA colors. If not, it will just ignore the entire declaration and move on.</p> + +<div class="note"> +<p><strong>Note</strong>: The same is true for other CSS features like <a href="/en-US/docs/Web/CSS/Media_Queries/Using_media_queries">media queries</a>, <code><a href="/en-US/docs/Web/CSS/@font-face">@font-face</a></code> and <code><a href="/en-US/docs/Web/CSS/@supports">@supports</a></code> blocks — if they are not supported, the browser just ignores them.</p> +</div> + +<h4 id="IE_conditional_comments">IE conditional comments</h4> + +<p>IE conditional comments are a modified proprietary HTML comment syntax, which can be used to selectively apply HTML code to different versions of IE. This has proven to be a very effective mechanism for fixing cross browser bugs. The syntax looks like this:</p> + +<pre class="brush: html"><span class="c"><!--[if lte IE 8]> + <script src="ie-fix.js"></script></span> + <link href="ie-fix.css" rel="stylesheet" type="text/css"> +<span class="c"><![endif]--></span></pre> + +<p>This block will apply the IE-specific CSS and JavaScript only if the browser viewing the page is IE 8 or older. <code>lte</code> means "less than or equal to", but you can also use lt, gt, gte, <code>!</code> for NOT, and other logical syntax.</p> + +<div class="note"> +<p><strong>Note</strong>: Sitepoint's <span class="l-d-i l-pa2 t-bg-white"><a href="https://www.sitepoint.com/web-foundations/internet-explorer-conditional-comments/">Internet Explorer Conditional Comments</a> provides a useful beginner's tutorial/reference that explains the conditional comment syntax in detail.</span></p> +</div> + +<p>As you can see, this is especially useful for applying code fixes to old versions of IE. The use case we mentioned earlier (making modern semantic elements styleable in old versions of IE) can be achieved easily using conditional comments, for example you could put something like this in your IE stylesheet:</p> + +<pre class="brush: css">aside, main, article, section, nav, figure, figcaption { + display: block; +}</pre> + +<p>It isn't that simple, however — you also need to create a copy of each element you want to style in the DOM via JavaScript, for them to be styleable; this is a strange quirk, and we won't bore you with the details here. For example:</p> + +<pre class="brush: js">var asideElem = document.createElement('aside'); + ...</pre> + +<p>This sounds like a pain to deal with, but fortunately there is a {{glossary("polyfill")}} available that does the necessary fixes for you, and more besides — see <a href="https://github.com/aFarkas/html5shiv">HTML5Shiv</a> for all the details (see <a href="https://github.com/aFarkas/html5shiv#installation">manual installation</a> for the simplest usage).</p> + +<h4 id="Selector_support">Selector support</h4> + +<p>Of course, no CSS features will apply at all if you don't use the right <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors">selectors</a> to select the element you want to style! If you just write a selector incorrectly so the styling isn't as expected in any browser, you'll just need to troubleshoot and work out what is wrong with your selector. We find that it is helpful to inspect the element you are trying to style using your browser's dev tools, then look at the DOM tree breadcrumb trail that DOM inspectors tend to provide to see if your selector makes sense compared to it.</p> + +<p>For example, in the Firefox dev tools, you get this kind of output at the bottom of the DOM inspector:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14139/dom-breadcrumb-trail.png" style="display: block; height: 24px; margin: 0px auto; width: 448px;"></p> + +<p>If for example you were trying to use this selector, you'd be able to see that it wouldn't select the input element as desired:</p> + +<pre class="brush: css">form > #date</pre> + +<p>(The <code>date</code> form input isn't directly inside the <code><form></code>; you'd be better off using a general descendant selector instead of a child selector).</p> + +<p>However, another issue that appears in versions of IE older than 9 is that none of the newer selectors (mainly pseudo-classes and pseudo-elements like <code><a href="/en-US/docs/Web/CSS/:nth-of-type">:nth-of-type</a></code>, <code><a href="/en-US/docs/Web/CSS/:not">:not</a></code>, <code><a href="/en-US/docs/Web/CSS/::selection">::selection</a></code>, etc.) work. If you want to use these in your CSS and you need to support older IE versions, a good move is to use Keith Clark's <a href="http://selectivizr.com/">Selectivizr</a> library — this is a small JavaScript library that works on top of an existing JavaScript library like <a href="http://jquery.com/">jQuery</a> or <a href="http://mootools.net/">MooTools</a>.</p> + +<ol> + <li>To try this example, make a local copy of <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/html-css/selectivizr-example-start.html">selectivizr-example-start.html</a>. If you look at this running live, you'll see that it contains two paragraphs, one of which is styled. We've selected the paragraph with <code>p:first-child</code>, which won't work in old versions of IE.</li> + <li>Now download <a href="http://mootools.net/">MooTools</a> and <a href="http://selectivizr.com/">Selectivizr</a>, and save them in the same directory as your sample HTML.</li> + <li>Put the following code into the head of your HTML document, just before the opening <code><style></code> tag: + <pre class="brush: html"><script type="text/javascript" src="MooTools-Core-1.6.0.js"></script> + <!--[if (gte IE 6)&(lte IE 8)]> + <script type="text/javascript" src="selectivizr-min.js"></script> + <![endif]--></pre> + </li> +</ol> + +<p>If you try running this in an old version of IE, it should work fine.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14137/new-selector-ie7.png" style="border-style: solid; border-width: 1px; display: block; height: 516px; margin: 0px auto; width: 771px;"></p> + +<h4 id="Handling_CSS_prefixes">Handling CSS prefixes</h4> + +<p>Another set of problems comes with CSS prefixes — these are a mechanism orignally used to allow browser vendors to implement their own version of a CSS (or JavaScript) feature while the technology is in an experimental state, so they can play with it and get it right without conflicting with other browser's implementations, or the final unprefixed implementations. So for example:</p> + +<ul> + <li>Mozilla uses <code>-moz-</code></li> + <li>Chrome/Opera/Safari use <code>-webkit-</code></li> + <li>Microsoft uses <code>-ms-</code></li> +</ul> + +<p>Here's some examples:</p> + +<pre class="brush: css">-webkit-transform: rotate(90deg); + +background-image: -moz-linear-gradient(left,green,yellow); +background-image: -webkit-gradient(linear,left center,right center,from(green),to(yellow)); +background-image: linear-gradient(to right,green,yellow); +</pre> + +<p>The first line shows a {{cssxref("transform")}} property with a <code>-webkit-</code> prefix — this was needed to make transforms work in Chrome, etc. until the feature was finalized and such browsers added a prefix-free version of the property (at the time of writing, Chrome supported both versions).</p> + +<p>The last three lines show three different versions of the <code><a href="/en-US/docs/Web/CSS/linear-gradient">linear-gradient()</a></code> function, which is used to generate a linear gradient in the background of an element:</p> + +<ol> + <li>The first one has a <code>-moz-</code> prefix, and shows a slightly older version of the syntax (Firefox)</li> + <li>The second one has a <code>-webkit-</code> prefix, and shows an even older, proprietary version of the syntax (this is actually from a really old version of the WebKit engine).</li> + <li>The third one has no prefix, and shows the final version of the syntax (included in the <a href="https://drafts.csswg.org/css-images-3/#linear-gradients">CSS Image Values and Replaced Content Module Level 3 spec</a>, which defines this feature).</li> +</ol> + +<p>Prefixed features were never supposed to be used in production websites — they are subject to change or removal without warning, and cause cross browser issues. This is particularly a problem when developers decide to only use say, the <code>-webkit- </code>version of a property — meaning that the site won't work in other browsers. This actually happens so much that other browsers have started to implement <code>-webkit-</code> prefixed versions of various CSS properties, so they will work with such code. Usage of prefixes by browser vendors has declined recently precisely because of these types of problems, but there are still some that need attention.</p> + +<p>If you insist on using prefixed features, make sure you use the right ones. You can look up what browsers require prefixes on MDN reference pages, and sites like <a href="http://caniuse.com/">caniuse.com</a>. If you are unsure, you can also find out by doing some testing directly in browsers.</p> + +<p>Try this simple example:</p> + +<ol> + <li>Open up google.com, or another site that has a prominent heading or other block level element.</li> + <li>Right/Cmd + click on the element in question and choose Inspect/Inspect element (or whatever the option is in your browser) — this should open up the dev tools in your browser, with the element highlighted in the DOM inspector.</li> + <li>Look for a feature you can use to select that element. For example, at the time of writing, the main Google logo had an ID of <code>hplogo</code>.</li> + <li>Store a reference to this element in a variable, for example: + <pre class="brush: js">var test = document.getElementById('hplogo');</pre> + </li> + <li>Now try to set a new value for the CSS property you are interested in on that element; you can do this using the <a href="/en-US/docs/Web/API/HTMLElement/style">style</a> property of the element, for example try typing these into the JavaScript console: + <pre class="brush: js">test.style.transform = 'rotate(90deg)' +test.style.webkitTransform = 'rotate(90deg)'</pre> + </li> +</ol> + +<p>As you start to type the property name representation after the second dot (note that in JavaScript, CSS property names are written in lower camel case, not hyphenated), the JavaScript console should begin to autocomplete the names of the properties that exist in the browser and match what you've written so far. This is useful for finding out what versions of the property are implemented in that browser.</p> + +<p>At the time of writing, both Firefox and Chrome implemented <code>-webkit-</code> prefixed and non-prefixed versions of {{cssxref("transform")}}!</p> + +<p>Once you've found out which prefixes you need to support, you should write them all out in your CSS, for example:</p> + +<pre class="brush: css">-ms-transform: rotate(90deg); +-webkit-transform: rotate(90deg); +transform: rotate(90deg);</pre> + +<p>This ensures that all browsers that support any of the above forms of the property can make the feature work. It is worth putting the non-prefixed version last, because that will be the most up-to-date version, which you'll want browsers to use if possible. If for example a browser implements both the <code>-webkit-</code> version and the non-prefixed version, it will first apply the <code>-webkit-</code> version, then override it with the non-prefixed version. You want it to happen this way round, not the other way round.</p> + +<p>Of course, doing this for lots of different CSS rules can get really tedious. It is better to use an automation tool to do it for you. And such tools exist:</p> + +<p>The <a href="http://leaverou.github.io/prefixfree/">prefix-free JavaScript library</a> can be attached to a page, and will automatically detect what capabilities are possessed by browsers viewing the page and add prefixes as appropriate. It is really easy and convenient to use, although it does have some downsides (see the link above for details), and it is arguable that parsing every stylesheet in your site and add prefixes at run time can be a drain on the computer's processing power for a large site.</p> + +<p>Another solution is to add prefixes automatically during development, and this (and other things besides) can be done using tools like <a href="https://github.com/postcss/autoprefixer">Autoprefixer</a> and <a href="http://postcss.org/">PostCSS</a>. These tools can be used in a variety of ways, for example Autoprefixer has an <a href="http://autoprefixer.github.io/">online version</a> that allows you to enter your non-prefixed CSS on the left, and gives you a prefix-added version on the right. You can choose which browsers you want to make sure you support using the notation outlined in <a href="https://github.com/postcss/autoprefixer#options">Autoprefixer options</a>; also see <a href="https://github.com/ai/browserslist#queries">Browserslist queries</a>, which this is based on, for more detail. As an example, the following query will select the last 2 versions of all major browsers and versions of IE above 9.</p> + +<pre>last 2 versions, ie > 9</pre> + +<p>Autoprefixer can also be used in other, more convenient ways — see <a href="https://github.com/postcss/autoprefixer#usage">Autoprefixer usage</a>. For example you can use it with a task runner/build tool such as <a href="http://gulpjs.com/">Gulp</a> or <a href="https://webpack.github.io/">Webpack</a> to automatically add prefixes once development has been done. (Explaining how these work is somewhat beyond the scope of this article.)</p> + +<p>You can also use a plugin for a text editor such as Atom or Sublime text. For example, in Atom:</p> + +<ol> + <li>You can install it by going to <em>Preferences > Install</em>, searching for <em>Autoprefixer</em>, then hitting install.</li> + <li>You can set a browser query by pressing the Autoprefixer <em>Settings</em> button and entering the query in the text field in the <em>Settings</em> section on the page.</li> + <li>In your code, you can select sections of CSS you want to add prefixes to, open the command pallette (<em>Cmd/Ctrl + Shift + P</em>), then type in Autoprefixer and select the Autoprefixer result that autocompletes.</li> +</ol> + +<p>As an example, we entered the following code:</p> + +<pre class="brush: css">body { + display: flex; +}</pre> + +<p>We highlighted it and ran the Autoprefixer command, and it replaced it with this:</p> + +<pre class="brush: css">body { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +}</pre> + +<h3 id="Layout_issues">Layout issues</h3> + +<p>Another problem that might come up is differences in layouts between browsers. Historically this used to be much more of a problem, but recently, with modern browsers tending to support CSS more consistently, layout issues tend to be more commonly associated with:</p> + +<ul> + <li>Lack of (or differences in) support for modern layout features.</li> + <li>Layouts not looking good in mobile browsers (i.e. responsive design problems).</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: Historically web developers used to use CSS files called resets, which removed all the default browser styling applied to HTML, and then applied their own styles for everything over the top — this was done to make styling on a project more consistent, and reduce possible cross browser issues, especially for things like layout. However, it has more recently been seen as overkill. The best equivalent we have in modern times is <a href="https://necolas.github.io/normalize.css/">normalize.css</a>, a neat bit of CSS that builds slightly on the default browser styling to make things more consistent and fix some layout issues. You are advised to apply normalize.css to all your HTML pages.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: When trying to track down a tricky layout issue, a good technique is to add a brightly colored {{cssxref("outline")}} to the offending element, or all the elements nearby. This makes it a lot easier to see where everything is placed. See <a href="http://www.otsukare.info/2016/10/05/debugging-css" rel="bookmark" title="Permalink to Debug your CSS with outline visualizations.">Debug your CSS with outline visualizations</a> for more details.</p> +</div> + +<h4 id="Support_for_new_layout_features">Support for new layout features</h4> + +<p>Much of the layout work on the web today is done using <a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">floats</a> — this is because floats are well-supported (way back to IE4, albeit with a number of bugs that would also need to be investigated if you were to try to support IE that far back). However, they are not really meant for layout purposes — using floats the way we do is really a hack — and they do have some serious limitations (e.g. see <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox#Why_Flexbox">Why Flexbox?</a>)</p> + +<p>More recently, dedicated layout mechanisms have appeared, like <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a> and <a href="/en-US/docs/Learn/CSS/CSS_layout/Grids#Native_CSS_Grids_with_Grid_Layout">CSS Grids</a>, which make common layout tasks far easier and remove such shortcomings. These however are not as well-supported in browsers:</p> + +<ul> + <li>CSS grids are very new; at the time of writing, they were only <a href="http://gridbyexample.com/browsers/">supported</a> in the very newest versions of modern browsers.</li> + <li>Flexbox is <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox#Cross_browser_compatibility">well-supported</a> in modern browsers, but provides problems in older browsers. IE 9 doesn't support it at all, and IE 10 and old versions of iOS/desktop Safari respectively support incompatible old versions of the flexbox spec. This results in some interesting browser prefix juggling if you want to try to use flexbox across all these browsers (see <a href="https://dev.opera.com/articles/advanced-cross-browser-flexbox/">Advanced Cross-Browser Flexbox</a> to get an idea).</li> +</ul> + +<p>Layout features aren't as easy to provide graceful fallbacks for than simple colors, shadows, or gradients. If layout properties are ignored, your entire design will likely fall to pieces. Because of this, you need to use feature detection to detect whether visiting browsers support those layout features, and selectively apply different layouts depending on the result (we will cover feature detection in detail in a later article).</p> + +<p>For example, you could apply a flexbox layout to modern browsers, then instead apply a floated layout to older browsers that don't support flexbox.</p> + +<div class="note"> +<p><strong>Note</strong>: There is a fairly new feature in CSS called <code><a href="/en-US/docs/Web/CSS/@supports">@supports</a></code>, which allows you to implement native feature detection tests.</p> +</div> + +<h4 id="Responsive_design_problems">Responsive design problems</h4> + +<p>Responsive design is the practice of creating web layouts that change to suit different device form factors — for example different screen widths, orientations (portrait or landscape), or resolutions. A desktop layout for example will look terrible when viewed on a mobile device, so you need to provide a suitable mobile layout using <a href="/en-US/docs/Web/CSS/Media_Queries">media queries</a>, and make sure it is applied correctly using <a href="/en-US/docs/Mozilla/Mobile/Viewport_meta_tag">viewport</a>. You can find a detailed account of such practices in <a href="/en-US/docs/Web/Apps/Progressive/Responsive/responsive_design_building_blocks">The building blocks of responsive design</a>.</p> + +<p>Resolution is a big issue too — for example, mobile devices are less likely to need big heavy images than desktop computers, and are more likely to have slower internet connections and possibly even expensive data plans that make wasted bandwidth more of a problem. In addition, different devices can have a range of different resolutions, meaning that smaller images could appear pixellated. There are a number of techniques that allow you to work around such problems, from simple <a href="/en-US/Apps/Progressive/Responsive/Mobile_first">mobile first media queries</a>, to more complex <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#Resolution_switching_Different_sizes">responsive image techniques</a>.</p> + +<p>Another difficulty that can present problems is browser support for the features that make the above techniques possible. media queries are not supported in IE 8 or less, so if you want to use a mobile first layout and have the desktop layout then apply to old IE versions, you'll have to apply a media query {{glossary("polyfill")}} to your page, like <a href="https://code.google.com/archive/p/css3-mediaqueries-js/">css3-mediaqueries-js</a>, or <a href="https://github.com/scottjehl/Respond">Respond.js</a>.</p> + +<h2 id="Finding_help">Finding help</h2> + +<p>There are many other issues you'll encounter with HTML and CSS; the most important thing to know really is how to find answers online.</p> + +<p>Among the best sources of support information are the Mozilla Developer Network (that's where you are now!), <a href="http://stackoverflow.com/">stackoverflow.com</a>, and <a href="http://caniuse.com/">caniuse.com</a>.</p> + +<p>To use the Mozilla Developer Network (MDN), most people do a search engine search of the technology they are trying to find information on, plus the term "mdn", for example "mdn HTML5 video". MDN contains several useful types of content:</p> + +<ul> + <li>Reference material with browser support information for client-side web technologies, e.g. the <a href="/en-US/docs/Web/HTML/Element/video"><video> reference page</a>.</li> + <li>Other supporting reference material, e.g. <a href="/en-US/docs/Web/HTML/Supported_media_formats">Media formats supported by the HTML audio and video elements</a>.</li> + <li>Useful tutorials that solve specific problems, for example <a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery/cross_browser_video_player">Creating a cross-browser video player</a>.</li> +</ul> + +<p><a href="http://caniuse.com/">caniuse.com</a> provides support information, along with a few useful external resource links. For example, see <a href="http://caniuse.com/#search=video">http://caniuse.com/#search=video</a> (you just have to enter the feature you are searching for into the text box).</p> + +<p><a href="http://stackoverflow.com/">stackoverflow.com</a> (SO) is a forum site where you can ask questions and have fellow developers share their solutions, look up previous posts, and help other developers. You are advised to look and see if there is an answer to your question already, before posting a new question. For example, we searched for "cross browser html5 video" on SO, and very quickly came up with <a class="question-hyperlink" href="http://stackoverflow.com/questions/16212510/html5-video-with-full-cross-browser-compatibility">HTML5 Video with full cross browser compatibility</a>.</p> + +<p>Aside from that, try searching your favourite search engine for an answer to your problem. It is often useful to search for specific error messages if you have them — other developers will be likely to have had the same problems as you.</p> + +<h2 id="Summary">Summary</h2> + +<p>Now you should be familiar with the main types of cross browser HTML and CSS problems that you'll meet in web development, and how to go about fixing them.</p> + +<p>{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies","Learn/Tools_and_testing/Cross_browser_testing/JavaScript", "Learn/Tools_and_testing/Cross_browser_testing")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">Introduction to cross browser testing</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies">Strategies for carrying out testing</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS">Handling common HTML and CSS problems</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Handling common JavaScript problems</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility">Handling common accessibility problems</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">Implementing feature detection</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Automated_testing">Introduction to automated testing</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Setting up your own test automation environment</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/tools_and_testing/cross_browser_testing/index.html b/files/ru/learn/tools_and_testing/cross_browser_testing/index.html new file mode 100644 index 0000000000..bdb268acb6 --- /dev/null +++ b/files/ru/learn/tools_and_testing/cross_browser_testing/index.html @@ -0,0 +1,34 @@ +--- +title: Кросс-браузерное тестирование +slug: Learn/Tools_and_testing/Cross_browser_testing +translation_of: Learn/Tools_and_testing/Cross_browser_testing +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Этот модуль фокусируется на тестировании веб-проектов в разных браузерах. Мы рассматриваем идентификацию вашей целевой аудитории (например о каких пользователях, браузерах и устройствах вам больше всего нужно беспокоиться?), Как пройти тестирование, основные проблемы, с которыми вам придется столкнуться с разными типами кода и способы смягчения их, какие инструменты наиболее полезны для помощи в тестировании и устранении проблем, а также о том, как использовать автоматизацию для ускорения тестирования.</p> + +<h2 id="Предпосылки">Предпосылки</h2> + +<p>Сначала вы должны изучить основы <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>,<a href="/en-US/docs/Learn/JavaScript">JavaScript</a> языков прежде чем пытаться использовать инструменты, описанные здесь.</p> + +<h2 id="Руководства">Руководства</h2> + +<dl> + <dt><a href="/ru/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">Введение в кросс-браузерное тестирование</a></dt> + <dd>Этот модуль начинается с обзора темы кросс-браузерного тестирования и отвечает на такие вопросы, как «что такое кросс-браузерное тестирование?», «с какими наиболее распространенными типами проблем вы столкнетесь?» и «каковы основные подходы к тестированию, выявлению и устранению проблем?"</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies">Стратегии проведения тестирования</a></dt> + <dd>Затем мы углубимся в тестирование, рассматривая целевую аудиторию (например какие браузеры, устройства и другие сегменты должны проверяться), стратегии тестирования низкого уровня (получить себе множество устройств и некоторых виртуальных машин и делать специальные тесты, когда это необходимо), стратегии более высоких технологий (автоматизация, использование специальных тестовых приложений) и тестирование с помощью групп пользователей.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS">Рассмотрим общие проблемы HTML и CSS</a></dt> + <dd>С набором сценариев, мы теперь рассмотрим общие кроссбраузерные проблемы, которые вы найдете в коде HTML и CSS, и какие инструменты можно использовать для предотвращения возникновения проблем или устранения возникающих проблем. Это включает в себя листинг кода, передачу префиксов CSS, использование инструментов браузера dev tools для устранения проблем, использование полифилов для добавления поддержки в браузеры, решение проблем с отзывчивым дизайном и многое другое.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Рассмотрим общие проблемы JavaScript</a></dt> + <dd>Теперь мы рассмотрим общие проблемы JavaScript в браузере и как их исправить. Это включает в себя информацию об использовании инструментов браузера для отслеживания и устранения неполадок, используя полифилы и библиотеки для решения проблем, получения современных функций JavaScript, работающих в старых браузерах, и многое другое.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility">Рассмотрим общие проблемы доступности</a></dt> + <dd>Затем мы обращаем наше внимание на доступность, предоставляя информацию о распространенных проблемах, как сделать простое тестирование, и как использовать инструменты аудита/автоматизации для поиска проблем доступности.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">Внедрение свойства обнаружения</a></dt> + <dd>Свойство выявления включает в себя разработку того, поддерживает ли браузер определенный блок кода, и работает ли другой код, зависящий от того, делает он (или нет), чтобы браузер всегда мог обеспечить рабочую силу, а также сбои / ошибки в некоторых браузерах. В этой статье описывается, как написать собственную простую функцию выявления, как использовать библиотеку для ускорения реализации и встроенные функции для обнаружения функций, такие как <code>@supports</code>.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Automated_testing">Введение в автоматизированное тестирование</a></dt> + <dd>Введение в автоматизированное тестирование<br> + Вручную запускать тесты на нескольких браузерах и устройствах, несколько раз в день, может стать утомительным и трудоемким. Чтобы эффективно справляться с этим, вы должны ознакомиться с инструментами автоматизации. В этой статье мы рассмотрим, что доступно, как использовать задачи, а также основы использования коммерческих приложений для автоматизации тестирования браузера, таких как Sauce Labs и Browser Stack.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Настройка собственной среды автоматизации тестирования</a></dt> + <dd>В этой статье мы научим вас, как установить свою собственную среду автоматизации и запустить собственные тесты с помощью Selenium / WebDriver и библиотеки тестирования, такой как selenium-webdriver для Node. Мы также рассмотрим, как интегрировать локальную тестовую среду с коммерческими приложениями, такими как те, которые обсуждались в предыдущей статье.</dd> +</dl> diff --git a/files/ru/learn/tools_and_testing/cross_browser_testing/introduction/index.html b/files/ru/learn/tools_and_testing/cross_browser_testing/introduction/index.html new file mode 100644 index 0000000000..96d31f156c --- /dev/null +++ b/files/ru/learn/tools_and_testing/cross_browser_testing/introduction/index.html @@ -0,0 +1,203 @@ +--- +title: Введение в кросс-браузерное тестирование +slug: Learn/Tools_and_testing/Cross_browser_testing/Introduction +tags: + - тестирование +translation_of: Learn/Tools_and_testing/Cross_browser_testing/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies", "Learn/Tools_and_testing/Cross_browser_testing")}}</div> + +<p class="summary">Эта статья начинает модуль с обзора темы кросс-браузерного тестирования, отвечая на такие вопросы как "что такое кросс-браузерное тестирование?", "с какими распространенными проблемами можно столкнуться?" и "какие основные подходы для тестирования, обнаружения и исправления проблем существуют?"</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые условия:</th> + <td>Знакомство с основами <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, и <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Улучшить понимание идей кроссбраузерного тестирования.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_кросс-браузерное_тестирование">Что такое кросс-браузерное тестирование?</h2> + +<p>Кросс-браузерное тестирование - это практика обеспечения уверенности в том, что веб-сайты и веб-приложения, которые вы создаете, работают в приемлемом количестве браузеров. Обязанность веб-разработчика быть уверенным, что проект работает не только у вас, а у всех ваших пользователей, независимо от браузера, устройства, или других вспомогательных инструментов, которые они используют. Вы должны думать о:</p> + +<ul> + <li>Других браузерах. Не тех нескольких, которые вы регулярно используете, а о довольно старых, которые некоторые люди могут использовать до сих пор, и которые не поддерживают современные возможности CSS и JavaScript.</li> + <li>Разных устройствах с разными возможностями, начиная от последних лучших планшетов, смартфонов и "умных" телевизоров, до дешевых устройств и самых старых смартфонов, в которых браузеры могут работать с ограниченными возможностями.</li> + <li>Людях с инвалидностью, которые используют Web с помощью вспомогательных технологий, таких как скринридеры, или не используют мышь (некоторые используют только клавиатуру).</li> +</ul> + +<p>Поймите, что вы - не ваши пользователи — если ваш сайт работает на Macbook Pro или Galaxy Nexus, это не значит, что он будет работать так для всех пользователей — нужно сделать много тестов!</p> + +<div class="note"> +<p><strong>Примечание</strong>: Статья <a href="https://hacks.mozilla.org/2016/07/make-the-web-work-for-everyone/">сделаем веб доступным для всех</a> предоставляет более полезную информацию о различных браузерах, которые используют люди, их доле рынка и связанных с этим проблемах совместимости браузеров.</p> +</div> + +<p>Мы должны поговорить немного о терминологии. Для начала, когда мы говорим о сайтах, "работающих кросс-браузерно", на самом деле мы говорим о том, что они должны обеспечивать приемлимое удобство использования в разных браузерах. Это нормально, если сайт выглядит немного по-разному в разных браузерах, главное он должен обеспечивать полную функциональность.В современных браузерах вы можете сделать что-то анимированным или использовать 3D, тогда как в старых браузерах вы можете лишь показать плоскую картинку, предоставляющую ту же информацию. Если владелец сайта доволен, вы сделали свое дело.</p> + +<p>С другой стороны, плохо, когда сайт полноценно работает для обычных людей, но может быть совершенно недоступен для людей, имеющих проблемы со зрением, т.к. их приложения для чтения экрана не могут распознать информацию на сайте.</p> + +<p>Когда мы говорим "приемлимое количество браузеров", мы не говорим, что это должно быть 100% всех браузеров в мире — это почти невозможно. Вы можете собрать информацию о том, какими браузеры и устройства используют ваши пользователи (это мы обсудим во второй статье — см. <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies#Gotta_test_%27em_all">Gotta test 'em all?</a>), но это ничего не гарантирует. Как веб-разработчик, вы должны определить для себя несколько браузеров и устройств, на которых код должен работать полностью, но кроме этого, вы должны писать код так, чтобы и другие браузеры были способны максимально использовать ваш сайт (defensive coding). Это одна из самых больших проблем веб-разработки.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Мы разберем defensive coding позже в этом модуле.</p> +</div> + +<h2 id="Почему_возникают_кросс-браузерные_проблемы">Почему возникают кросс-браузерные проблемы?</h2> + +<p>Есть множество причин, почему возникают кросс-браузерные проблемы, и, заметьте, что сейчас мы говорим о проблемах, при которых некоторые вещи ведут себя по-разномув разных браузерах / устройствах / настройках просмотра. Прежде чем вы столкнетесь с проблемами браузера, вы должны исправить все ошибки в коде (см. <a href="/ru/docs/Learn/HTML/Введение_в_HTML/Debugging_HTML">Отладка HTML</a>, <a href="/ru/docs/Learn/CSS/Introduction_to_CSS/Отладка_CSS">Отладка CSS</a>, and <a href="/ru/docs/Learn/JavaScript/Первые_шаги/Что_пошло_не_так">Что пошло не так? Устранение ошибок JavaScript</a> из предыдущего раздела).</p> + +<p>Кросс-браузерные проблемы возникают потому-что:</p> + +<ul> + <li>иногда браузеры содержат баги, или реализуют возможности по-разному. В настоящее время это не такая частая проблема, но когда IE4 и Netscape 4 конкурировали за право быть доминирующим браузером в 90-е, компании-разработчики браузеров умышленно реализовывали возможности по-своему в попытке получить конкурентное преимущество, что делало жизнь веб-разработчикам адом. Сейчас же браузеры гораздо жестче соблюдают стандарты, но различия и баги все же иногда возникают.</li> + <li>браузеры имеют разную степень поддержи современных технологий. Это неизбежно, когда вы имеете дело с новейшими функциями, которые браузеры только начинают осваивать, или если вы вынуждены поддерживать очень старые браузеры, которые более не дорабатываются или которые могли быть заморожены (то есть в них не добавляют новый функционал) задолго до того, как придумали новые возможности. Например, если вы хотите использовать передовые возможности JavaScript на вашем сайте, то они могут не работать в старых браузерах. Если вам нужна поддержка старых браузеров, вы можете конвертировать ваш код под старый синтаксис, используя специальные компиляторы.</li> + <li>некоторые устройства могут иметь ограничения, из-за которых сайт работает медленно или отображается неверно. Например, если сайт был спроектирован для просмотра на десктопных устройствах, он возможно будет выглядеть мелко и трудночитаемо на мобильных устройствах. Если ваш сайт содержит множество больших анимаций, это может быть хорошо на высокопроизводительных планшетах, но может быть вялым или резким на устройствах меньшей производительности.</li> +</ul> + +<p>а также другие причины.</p> + +<p>В статьях далее, мы выясним основные проблемы кросс-браузерности и посмотрим на их решения.</p> + +<h2 id="Инструменты_для_кросс-браузерного_тестирования">Инструменты для кросс-браузерного тестирования</h2> + +<p>Может показаться, что тестирование - это затратно и страшно, но это важно — вы должны спланировать и убедиться, что вы делаете тесты в нужных местах, чтобы не было неожиданных проблем. Если вы работаете над большим проектом, вы должны тестировать его регулярно, чтобы убеждаться, что новые возможности работают корректно для вашей целевой аудитории, и что новый код не ломает старый функционал.</p> + +<p>Если вы будете тестировать в конце проекта, любые не обнаруженные баги будут гораздо более затратными по времени для исправления, если бы вы их тестировали и обнаруживали своевременно.</p> + +<p>Рабочий процесс над тестированием и исправлением ошибок может быть разбит на следующие четыре фазы (очень грубое разделение - у разных людей этот процесс может очень сильно отличаться):</p> + +<p><strong>Начальное планирование > Разработка > Тестирование > Исправление ошибок</strong></p> + +<p>Шаги 2-4 будут повторяться до тех пор, пока не будут реализованы все возможности. Мы рассмотрим различные элементы процесса тестирования более детально в следующих статьях, но пока давайте соберем то, что может происходить на каждом этапе.</p> + +<h3 id="Начальное_планирование">Начальное планирование</h3> + +<p>На этом этапе у вас, возможно, будет несколько встреч с владельцем/заказчиком сайта (это может быть ваш босс или кто-то из другой компании, для кого вы пишете сайт), чтобы точно определить, каким должен быть сайт - какой контент и функционал должен быть на сайте, как сайт должен выглядеть и т.д. На этом этапе вы также хотите знать сколько времени у вас есть на разработку и цену работы. Не хочется углубляться в детали, но такое планирование оказывает большое влияние на кросс-браузерное тестирование.</p> + +<p>Once you've got an idea of the required featureset, and what technologies you will likely build these features with, you should start exploring the target audience — what browsers, devices, etc. will the target audience for this site be using? The client might already have data about this from previous research they've done, e.g. from other web sites they own, or from previous versions of the web site you are now working on. If not, you will be able to get a good idea by looking at other sources, such as usage stats for competitors, or countries the site will be serving. You can also use a bit of intuition.</p> + +<p>So for example, you might be building an e-commerce site that serves customers in North America. The site should work entirely in the last few versions of the most popular desktop and mobile (iOS, Android, Windows phone) browsers — this should include Chrome (and Opera as it is based on the same rendering engine as Chrome), Firefox, IE/Edge, and Safari. It should also provide an acceptable experience on IE 8 and 9, and be accessible with WCAG AA compliance.</p> + +<p>Now you know your target testing platforms, you should go back and review the required featureset and what technologies you are going to use. For example, if the e-commerce site owner wants a WebGL-powered 3D tour of each product built into the product pages, they will need to accept that this just won't work in IE versions before 11. You'd have to agree to provide a version of the site without this feature to users of older IE versions.</p> + +<p>You should compile a list of the potential problem areas.</p> + +<div class="note"> +<p><strong>Note</strong>: You can find browser support information for technologies by looking up the different features on MDN — the site you're on! You should also consult <a href="http://caniuse.com/">caniuse.com</a>, for some further useful details.</p> +</div> + +<p>Once you've agreed on these details, you can go ahead and start developing the site.</p> + +<h3 id="Development">Development</h3> + +<p>Now on to the development of the site. You should split the different parts of the development into modules, for example you might split the different site areas up — home page, product page, shopping cart, payment workflow, etc. You might then further subdivide these — implement common site header and footer, implement product page detail view, implement persistent shopping cart widget, etc.</p> + +<p>There are multiple general strategies to cross browser development, for example:</p> + +<ul> + <li>Get all the functionality working as closely as possible in all target browsers. This may involve writing different code paths that reproduce functionality in different ways aimed at different browsers, or using a {{glossary("Polyfill")}} to mimic any missing support using JavaScript or other technologies, or using a library that allows you to write a single bit of code and then does different things in the background depending on what the browser supports.</li> + <li>Accept that some things aren't going to work the same on all browsers, and provide different (acceptable) solutions in browsers that don't support the full functionality. Sometimes this is inevitable due to device constraints — a cinema widescreen isn't going to give the same visual experience as a 4" mobile screen, regardless of how you program your site.</li> + <li>Accept that your site just isn't going to work in some older browsers, and move on. This is OK, provided your client/userbase is OK with it.</li> +</ul> + +<p>Normally your development will involve a combination of the above three approaches. The most important thing is that you test each small part before committing it — don't leave all the testing till the end!</p> + +<h3 id="Testingdiscovery">Testing/discovery</h3> + +<p>After each implementation phase, you will need to test the new functionality. To start with, you should make sure there are no general issues with your code that are stopping your feature from working:</p> + +<ol> + <li>Test it in a couple of stable browsers on your system, like Firefox, Safari, Chrome, or IE/Edge.</li> + <li>Do some low fi accessibility testing, such as trying to use your site with only the keyboard, or using your site via a screen reader to see if it is navigable.</li> + <li>Test on a mobile platform, such as Android or iOS.</li> +</ol> + +<p>At this point, fix any problems you find with your new code.</p> + +<p>Next, you should try expanding your list of test browsers to a full list of target audience browsers and start concentrating on weeding out cross browser issues (see the next article for more information on <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies#Gotta_test_%27em_all">determining your target browsers</a>). For example:</p> + +<ul> + <li>Try to test the latest change on all the modern desktop browsers you can — including Firefox, Chrome, Opera, IE, Edge, and Safari on desktop (Mac, Windows, and Linux, ideally).</li> + <li>Test it in common phone and tablet browsers (e.g. iOS Safari on iPhone/iPad, Chrome and Firefox on iPhone/iPad/Android),</li> + <li>Also do tests in any other browsers you have included inside your target list.</li> +</ul> + +<p>The most low fi option is to just do all the testing you can by yourself (pulling in team mates to help out if you are working in a team). You should try to test it on real physical devices where possible.</p> + +<p>If you haven't got the means to test all those different browser, operating system, and device combinations on physical hardware, you can also make use of emulators (emulate a device using software on your desktop computer) and virtual machines (software that allows you to emulate multiple operating system/software combinations on your desktop computer). This is a very popular choice, especially in some circumstances — for example, Windows doesn't let you have multiple versions of Windows installed simulataneously on the same machine, so using multiple virtual machines is often the only option here.</p> + +<p>Another option is user groups — using a group of people outside your development team to test your site. This could be a group of friends or family, a group of other employees, a class at a local university, or a professional user testing setup, where people are paid to test out your site and provide results.</p> + +<p>Finally, you can get smarter with your testing using auditing or automation tools; this is a sensible choice as your projects get bigger, as doing all this testing by hand can start to take a really long time. You can set up your own testing automation system (<a href="http://www.seleniumhq.org/">Selenium</a> being the popular app of choice) that could for example load your site in a number of different browsers, and:</p> + +<ul> + <li>see if a button click causes something to happen successfully (like for example, a map displaying), displaying the results once the tests are completed</li> + <li>take a screenshot of each, allowing you to see if a layout is consistent across the different browsers.</li> +</ul> + +<p>You can also go further than this, if wished. There are commercial tools available such as <a href="https://saucelabs.com/">Sauce Labs</a>, <a href="https://www.browserstack.com/">Browser Stack</a>, <a href="https://www.lambdatest.com/">LambdaTest</a>, <a href="https://testingbot.com">TestingBot</a>, and <a href="https://crossbrowsertesting.com">CrossBrowserTesting</a> that do this kind of thing for you, without you having to worry about the setup, if you wish to invest some money in your testing. It is also possible to set up an environment that automatically runs tests for you, and then only lets you check in your changes to the central code repository if the tests still pass.</p> + +<h4 id="Testing_on_prerelease_browsers">Testing on prerelease browsers</h4> + +<p>It is often a good idea to test on prerelease versions of browsers; see the following links:</p> + +<ul> + <li><a href="https://www.mozilla.org/en-US/firefox/developer/">Firefox Developer Edition</a></li> + <li><a href="https://insider.windows.com/">Edge Insider Preview</a></li> + <li><a href="https://developer.apple.com/safari/technology-preview/">Safari Technology Preview</a></li> + <li><a href="https://www.google.com/chrome/browser/canary.html">Chrome Canary</a></li> + <li><a href="http://www.opera.com/computer/beta">Opera Developer</a></li> +</ul> + +<p>This is especially prevalent if you are using very new technologies in your site, and you want to test against the latest implementations, or if you are coming across a bug in the latest release version of a browser, and you want to see if the browser's developers have fixed the bug in a newer version.</p> + +<h3 id="Fixesiteration">Fixes/iteration</h3> + +<p>Once you've discovered a bug, you need to try to fix it.</p> + +<p>The first thing to do is to narrow down where the bug occurs as much as possible. Get as much information as you can from the person reporting the bug — what platform(s), device(s), browser version(s), etc. Try it on similar configurations (e.g. the same browser version on different desktop platforms, or a few different versions of the same browser on the same platform) to see how widely the bug persists.</p> + +<p>It might not be your fault — if a bug exists in a browser, then hopefully the vendor will rapidly fix it. It might have already been fixed — for example if a bug is present in Firefox release 49, but it is no longer there in Firefox Nightly (version 52), then they have fixed it. If it is not fixed, then you may want to file a bug (see {{anch("Reporting bugs")}}, below).</p> + +<p>If it is your fault, you need to fix it! Finding out the cause of the bug involves the same strategy as any web development bug (again, see <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a>, <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Debugging_CSS">Debugging CSS</a>, and <a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a>). Once you've discovered what is causing your bug, you need to decide how to work around it in the particular browser it is causing problems in — you can't just change the problem code outright, as this may break the code in other browsers. The general approach is usually to fork the code in some way, for example use JavaScript feature detection code to detect situations in which a problem feature doesn't work, and run some different code in those cases that does work.</p> + +<p>Once a fix has been made, you'll want to repeat your testing process to make sure your fix is working OK, and hasn't caused the site to break in other places or in other browsers.</p> + +<h2 id="Reporting_bugs">Reporting bugs</h2> + +<p>Just to reiterate on what was said above, if you discover bugs in browsers, you should report them:</p> + +<ul> + <li><a href="https://bugzilla.mozilla.org/">Firefox Bugzilla</a></li> + <li><a href="https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/">EdgeHTML issue tracker</a></li> + <li><a href="https://bugs.webkit.org/">Safari</a></li> + <li><a href="https://bugs.chromium.org/p/chromium/issues/list">Chrome</a></li> + <li><a href="https://bugs.opera.com/wizard/desktop">Opera</a></li> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>This article should have given you a high-level understanding of the most important concepts you need to know about cross browser testing. Armed with this knowledge, you are now ready to move on and start learning about Cross browser testing strategies.</p> + +<p>{{NextMenu("Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies", "Learn/Tools_and_testing/Cross_browser_testing")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">Introduction to cross browser testing</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies">Strategies for carrying out testing</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS">Handling common HTML and CSS problems</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Handling common JavaScript problems</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility">Handling common accessibility problems</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">Implementing feature detection</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Automated_testing">Introduction to automated testing</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Setting up your own test automation environment</a></li> +</ul> diff --git a/files/ru/learn/tools_and_testing/index.html b/files/ru/learn/tools_and_testing/index.html new file mode 100644 index 0000000000..a032697166 --- /dev/null +++ b/files/ru/learn/tools_and_testing/index.html @@ -0,0 +1,48 @@ +--- +title: Tools and testing +slug: Learn/Tools_and_testing +tags: + - Accessibility + - Automation + - Beginner + - CSS + - CodingScripting + - HTML + - JavaScript + - Landing + - Learn + - NeedsTranslation + - Testing + - Tools + - Topic + - TopicStub + - cross browser + - user testing +translation_of: Learn/Tools_and_testing +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Once you've started to become comfortable programming with core web technologies (like HTML, CSS, and JavaScript), and you start to get more experience, read more resources, and learn more tips and tricks, you'll start to come across all kind of tools, from ready-rolled CSS and JavaScript, to testing and automation apps, and more besides. As your web projects become larger and more complex, you'll want to start taking advantage of some of these tools, and working out reliable testing plans for your code. This part of the learning area aims to give you what you need get started and make informed choices.</p> + +<p>The web industry is an exciting place to work, but it is not without its complications. The core technologies we use to build web sites are fairly stable now, but new features are being added all the time, and new tools — that facilitate working with, and are built on top of these technologies — are constantly appearing. On top of that, we still need to keep cross-browser support in the forefront of our minds, and make sure that our code follows best practices that allow our projects to work across different browsers and devices that our users are using to browse the Web, and be usable by people with disabilities.</p> + +<p>Working out what tools you should be using can be a difficult process, so we have written this set of articles to inform you of what types of tool are available, what they can do for you, and how to make use of the current industry favourites.</p> + +<div class="note"> +<p><strong>Note</strong>: Because new tools appear and old ones go out of fashion all the time, we have deliberately written this material to be as neutral as possible — we want to focus first and foremost on the general types of tasks these tools will help you accomplish, and keep prescribing specific tools to a minimum. We obviously need to show tool usage to demonstrate specific techniques, but be clear that we do not necessarily recommend these tools as the best or only way to do things — in most cases there are other ways, but we want to provide you with a clear methodology that works.</p> +</div> + +<h2 id="Learning_pathway">Learning pathway</h2> + +<p>You should really learn the basics of the core <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, and <a href="/en-US/docs/Learn/JavaScript">JavaScript</a> languages first before attempting to use the tools detailed here. For example, you'll need to know the fundamentals of these languages before you start debugging problems in complex web code, or making effective use of JavaScript libraries, or writing tests and running them against your code using test runners, etc.</p> + +<p>You need a solid foundation first.</p> + +<h2 id="Modules">Modules</h2> + +<dl> + <dt>Real world web development tools (TBD)</dt> + <dd>In this module, we explore the different kinds of web development tools available. This includes reviewing the most common kinds of tasks you may be called on to solve, how they can fit together in a workflow, and the best tools currently avaiable for carrying out those tasks.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing">Cross browser testing</a></dt> + <dd>This module looks specifically at the area of testing web projects across different browsers. Here we look identifying your target audience (e.g. what users, browsers and devices do you most need to worry about?), how to go about doing testing, the main issues that you'll face with different types of code and how to fix/mitigate those, what tools are most useful in helping you test and fix problems, and how to use automation to speed up testing.</dd> +</dl> diff --git a/files/ru/learn/tools_and_testing/гитхаб/index.html b/files/ru/learn/tools_and_testing/гитхаб/index.html new file mode 100644 index 0000000000..f78ac2a27c --- /dev/null +++ b/files/ru/learn/tools_and_testing/гитхаб/index.html @@ -0,0 +1,84 @@ +--- +title: Гит и ГитХаб +slug: Learn/Tools_and_testing/ГитХаб +tags: + - Веб + - Начинающий + - гит +translation_of: Learn/Tools_and_testing/GitHub +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Все разработчики используют ту или иную <strong>систему контроля версий (СКВ, VCS)</strong>, инструмент, позволяющий им взаимодействовать с другими разработчиками на проекте без угрозы того, что кто-то перезапишет чужую работу, а также вернуться к предыдущим версиям кода при обнаружении проблем позднее.</p> + +<p class="summary">Самая популярная СКВ (по крайней мере, среди веб-разработчиков) являюся <strong>Гит (Git)</strong>, а также <strong>ГитХаб (GItHub) </strong>- сайт, обеспечивающий размещение ваших репозиториев и включащий инструменты для работы с ними. Цели этого модуля - дать вам необходимые знания о каждой из упомянутых СКВ.</p> + +<h2 id="Обзор">Обзор</h2> + +<p>СКВ являются основой для разработки программного обеспечения:</p> + +<ul> + <li>Редко, когда вы работаете с проектом полностью самостоятельно. Как только вы начинаете работать с другими людьми, возникает риск конфликта. Речь идет о ситуации, когда несколько человек пытается в одно и то же время обновить одну и ту же часть кода. Нужен определенный механизм, позволяющий управлять событиями и тем самым избежать потери результатов общей работы.</li> + <li>Работая с проектому в одиночку или с другими, вы захотите иметь возможность иметь резервную копию кода на случай поломки вашего компьютера.</li> + <li>Также у вас может возникнуть необходимость откатить изменения к более ранним версиям, если проблема обнаружена позднее. Конечно, это начать делать самостоятельно, сохраняя различные версии одного и того же файла, например <code>myCode.js</code>, <code>myCode_v2.js</code>, <code>myCode_v3.js</code>, <code>myCode_final.js</code>, <code>myCode_really_really_final.js</code>, и так далее, но это на самом деле ненадежный и порождающий ошибки способ.</li> + <li>Различные члены команды могут захотеть создать собственные версии кода (в Гит такие версии именуются <strong>ветками</strong>), работать над новой фичей в этой версии, а затем контролируемо объединить эту версию (в ГитХабе используются <strong>пул реквесты</strong> - запросы на принятие изменений) с главной версией.</li> +</ul> + +<p>СКВ обеспечивают инструменты для решения всех вышеуказанных задач. <a href="https://git-scm.com/">Гит</a> является примером СКВ, а <a href="https://github.com/">ГитХаб</a> - это сайт, обеспечивающий веб-интерфейс для работы с гит, а также множество полезных инструментов для работы с гит-репозиториями лично или в командах, такие как фиксация проблем с кодом, инструменты для проверки кода, инструменты для управления созданием продукта, например назначение задач и их статусов, и т.д.</p> + +<div class="blockIndicator note"> +<p><strong>Важно</strong>: ГИТ на самом деле - распределенная система контроля версий, это значит что полная копия репозитория, содержащая всю кодовую базу сохраняется на твой компьютер (и кого-либо еще). Ты вносишь изменения в свою копию и затем отправляешь эти изменения обратно на сервер, на котором администратор решит соединять ли твои измеения с оригиналом. </p> +</div> + +<h2 id="Подготовка">Подготовка</h2> + +<p>Для использования Git и GitHub тебе необходимо:</p> + +<ul> + <li>Компьютер с установленной версией Git (посмотри <a href="https://git-scm.com/downloads">страницу загрузки Git</a>).</li> + <li>Приложения для работы с Git. В зависимости от того как ты предпочитаешь работать, можешь использовать <a href="https://git-scm.com/downloads/guis/">Git-кленты с графическим интерфейсом</a> (мы рекомендуем GitHub Desktop, SourceTree или Git Kraken) или просто продолжай использовать окно терминала. Если честно, будет весьма полезно для тебя узнать основы использования git-команд в терминале, даже если ты собираешься работать через графический интерфейс.</li> + <li><a href="https://github.com/join">Аккаунт на GitHub</a>. Если у тебя еще его нет, зарегистрируйся сейчас по указанной ссылке.</li> +</ul> + +<p>Что касается предварительных знаний, вам не нужно разбираться в веб-разработке, Git / GitHub или VCS, чтобы приступить к этому модулю. Тем не менее, рекомендуется, чтобы вы разбирались в состоавлении кода, могли его писать и читать, а также сохранили пару строчек кода в своих репозиториях!</p> + +<p>Также желательно, чтобы у вас были некоторые базовые знания о терминале, например, перемещение между каталогами, создание файлов и изменение системного <code>PATH</code>.</p> + +<div class="blockIndicator note"> +<p><strong>Важно</strong>: Github не единственный сайт / инструментарий который ты можешь использовать с Git. Есть и альтернативы, такие как <a href="https://about.gitlab.com/">GitLab</a>, которые ты можешь попробовать, а также ты моежшь попробовать настроить свой собственный сервер Git и использовать вместо GitHub. Мы в этом курсе останвились на GitHub, чтобы показать один из рабочих способов.</p> +</div> + +<h2 id="Guides">Guides</h2> + +<p>Note that the links below take you to resources on external sites. Eventually we will are aiming to have our own dedicated Git/GitHub course, but for now, these will help you get to grips with the subject in hand.</p> + +<dl> + <dt><a href="https://guides.github.com/activities/hello-world/">Hello World (from GitHub)</a></dt> + <dd>This is a good place to start — this practical guide gets you to jump right into using GitHub, learning the basics of Git such as creating repositories and branches, making commits, and opening and merging pull requests.</dd> + <dt><a href="https://guides.github.com/introduction/git-handbook/">Git Handbook (from GitHub)</a></dt> + <dd>This Git Handbook goes into a little more depth, explaining what a VCS is, what a repository is, how the basic GitHub model works, Git commands and examples, and more.</dd> + <dt><a href="https://guides.github.com/activities/forking/">Forking Projects (from GitHub)</a></dt> + <dd>Forking projects is essential when you want to contribute to someone else's code. This guide explains how.</dd> + <dt><a href="https://help.github.com/en/articles/about-pull-requests">About Pull Requests (from GitHub)</a></dt> + <dd>A useful guide to managing pull requests, the way that your suggested code changes are delivered to people's repositories for consideration.</dd> + <dt><a href="https://guides.github.com/features/issues/">Mastering issues (from GitHub)</a></dt> + <dd>Issues are like a forum for your GitHub project, where people can ask questions and report problems, and you can manage updates (for example assigning people to fix issues, clarifying the issue, letting people know things are fixed). This articles gives you what you need to know about issues.</dd> +</dl> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: There is <strong>a lot more</strong> that you can do with Git and GitHub, but we feel that the above represents the minimum you need to know to start using Git effectively. As you get deeper into Git, you'll start to realise that it is easy to go wrong when you start using more complicated commands. Don't worry, even professional web developers find Git confusing sometimes, and often solve problems by searching for solutions on the web, or consulting sites like <a href="https://github.com/k88hudson/git-flight-rules">Flight rules for Git</a> and<a href="https://dangitgit.com/"> Dangit, git!</a></p> +</div> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://guides.github.com/introduction/flow/">Understanding the GitHub flow</a></li> + <li><a href="https://git-scm.com/docs">Git command list</a></li> + <li><a href="https://guides.github.com/features/mastering-markdown/">Mastering markdown</a> (the text format you write in on PR, issue comments, and <code>.md</code> files).</li> + <li><a href="https://guides.github.com/features/pages/">Getting Started with GitHub Pages</a> (how to publish demos and websites on GitHub).</li> + <li><a href="https://learngitbranching.js.org/">Learn Git branching</a></li> + <li><a href="https://github.com/k88hudson/git-flight-rules">Flight rules for Git</a> (a very useful compendium of ways to achieve specific things in Git, including how to correct things when you went wrong).</li> + <li> + <p><a href="https://dangitgit.com/">Dangit, git!</a> (another useful compendium, specifically of ways to correct things when you went wrong).</p> + </li> +</ul> diff --git a/files/ru/learn/tools_and_testing/фронтенд_javascript_фреймворки/index.html b/files/ru/learn/tools_and_testing/фронтенд_javascript_фреймворки/index.html new file mode 100644 index 0000000000..08fb977bb5 --- /dev/null +++ b/files/ru/learn/tools_and_testing/фронтенд_javascript_фреймворки/index.html @@ -0,0 +1,137 @@ +--- +title: Понимание JavaScript-фреймворков для фронтенда +slug: Learn/Tools_and_testing/Фронтенд_JavaScript_фреймворки +translation_of: Learn/Tools_and_testing/Client-side_JavaScript_frameworks +--- +<div>{{LearnSidebar}}<br> +JavaScript-ф<span>реймворки </span>являются неотъемлемой частью современной веб-разработки,</div> + +<div>предоставляя разработчикам проверенные и протестированные</div> + +<div>инструменты для создания масштабируемых и интерактивных веб-приложений. Многие</div> + +<div>современные компании используют фреймворки для своих решений, поэтому многие задачи связанные с разработкой клиентской части веб-приложений теперь требуют опыта работы с ними.<br> + </div> + +<p class="summary">Начинающему разработчику веб-интерфесов, может быть трудно понять, с чего начать изучение фреймворков - их выбор разнообразен, а новые появляются постоянно. В основном же они работают аналогичным образом, но делают некоторые вещи по-разному, также есть некоторые специфичные вещи, которые следует соблюдать при использовании фреймворков.</p> + +<p class="summary">Этим набором статей мы постараемся дать вам удобную отправную точку, чтобы помочь вам начать изучать основы. Мы не стремимся научить вас всему, что вам нужно знать о React / ReactDOM, или Vue, или какой-то другой конкретной среде; Документация этих фреймворков отлично выполняют эту работу. Вместо этого мы хотим сделать шаг назад и сначала ответить на более фундаментальные вопросы, такие как:</p> + +<ul> + <li class="summary">Почему я должен использовать фреймворк? Какие проблемы он решит?</li> + <li class="summary">Какие вопросы я должен задать себе при выборе определённого фреймворка?<br> + Нужен ли мне какой-либо из них вовсе?</li> + <li class="summary">Какими возможностями обладают фреймворки? Как они работают в целом и в чём отличия их имплементаций этих возможностей?</li> + <li class="summary">Как они связаны с "ванильным" JavaScript, или HTML?</li> +</ul> + +<p class="summary">После этого мы предоставим некоторые учебные пособия, охватывающие основы некоторых фреймворков, чтобы предоставить вам достаточно контекста, чтобы вы могли начать углубляться в этой теме. Мы хотим, чтобы вы изучали фреймворки прагматично, не забывая о фундаментальных практиках веб-разработки, таких как, например, доступность.</p> + +<p class="summary"><strong><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">Начните прямо сейчас с "Введение в фронтенд фрейворки"</a></strong></p> + +<h2 id="Prerequisites">Prerequisites</h2> + +<p>You should really learn the basics of the core web languages first before attempting to move on to learning client-side frameworks — <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, and especially <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>.</p> + +<p>Your code will be richer and more professional as a result, and you'll be able to troubleshoot problems with more confidence if you understand the fundamental web platform features that the frameworks are building on top of.</p> + +<h2 id="Introductory_guides">Introductory guides</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">1. Introduction to client-side frameworks</a></dt> + <dd>We begin our look at frameworks with a general overview of the area, looking at a brief history of JavaScript and frameworks, why frameworks exist and what they give us, how to start thinking about choosing a framework to learn, and what alternatives there are to client-side frameworks.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features">2. Framework main features</a></dt> + <dd>Each major JavaScript framework has a different approach to updating the DOM, handling browser events, and providing an enjoyable developer experience. This article will explore the main features of “the big 4” frameworks, looking at how frameworks tend to work from a high level, and the differences between them.</dd> +</dl> + +<h2 id="React_tutorials">React tutorials</h2> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: React tutorials last tested in May 2020, with React/ReactDOM 16.13.1 and create-react-app 3.4.1.</p> + +<p>If you need to check your code against our version, you can find a finished version of the sample React app code in our <a href="https://github.com/mdn/todo-react">todo-react repository</a>. For a running live version, see <a href="https://mdn.github.io/todo-react-build/">https://mdn.github.io/todo-react-build/</a>.</p> +</div> + +<dl> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started">1. Getting started with React</a></dt> + <dd>In this article we will say hello to React. We'll discover a little bit of detail about its background and use cases, set up a basic React toolchain on our local computer, and create and play with a simple starter app, learning a bit about how React works in the process.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning">2. Beginning our React todo list</a></dt> + <dd>Let's say that we’ve been tasked with creating a proof-of-concept in React – an app that allows users to add, edit, and delete tasks they want to work on, and also mark tasks as complete without deleting them. This article will walk you through putting the basic <code>App</code> component structure and styling in place, ready for individual component definition and interactivity, which we'll add later.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components">3. Componentizing our React app</a></dt> + <dd>At this point, our app is a monolith. Before we can make it do things, we need to break it apart into manageable, descriptive components. React doesn’t have any hard rules for what is and isn’t a component – that’s up to you! In this article we will show you a sensible way to break our app up into components.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state">4. React interactivity: Events and state</a></dt> + <dd>With our component plan worked out, it's now time to start updating our app from a completely static UI to one that actually allows us to interact and change things. In this article we'll do this, digging into events and state along the way.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering">5. React interactivity: Editing, filtering, conditional rendering</a></dt> + <dd>As we near the end of our React journey (for now at least), we'll add the finishing touches to the main areas of functionality in our Todo list app. This includes allowing you to edit existing tasks, and filtering the list of tasks between all, completed, and incomplete tasks. We'll look at conditional UI rendering along the way.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility">6. Accessibility in React</a></dt> + <dd>In our final tutorial article, we'll focus on (pun intended) accessibility, including focus management in React, which can improve usability and reduce confusion for both keyboard-only and screenreader users.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources">7. React resources</a></dt> + <dd>Our final article provides you with a list of React resources that you can use to go further in your learning.</dd> +</dl> + +<h2 id="Ember_tutorials">Ember tutorials</h2> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Ember tutorials last tested in May 2020, with Ember/Ember CLI version 3.18.0.</p> + +<p>If you need to check your code against our version, you can find a finished version of the sample Ember app code in the <a href="https://github.com/NullVoxPopuli/ember-todomvc-tutorial/tree/master/steps/00-finished-todomvc/todomvc">ember-todomvc-tutorial repository</a>. For a running live version, see <a href="https://nullvoxpopuli.github.io/ember-todomvc-tutorial/">https://nullvoxpopuli.github.io/ember-todomvc-tutorial/</a> (this also includes a few additional features not covered in the tutorial).</p> +</div> + +<dl> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started">1. Getting started with Ember</a></dt> + <dd>In our first Ember article we will look at how Ember works and what it's useful for, install the Ember toolchain locally, create a sample app, and then do some initial setup to get it ready for development.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization">2. Ember app structure and componentization</a></dt> + <dd>In this article we'll get right on with planning out the structure of our TodoMVC Ember app, adding in the HTML for it, and then breaking that HTML structure into components.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state">3. Ember interactivity: Events, classes and state</a></dt> + <dd>At this point we'll start adding some interactivity to our app, providing the ability to add and display new todo items. Along the way, we'll look at using events in Ember, creating component classes to contain JavaScript code to control interactive features, and setting up a service to keep track of the data state of our app.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer">4. Ember Interactivity: Footer functionality, conditional rendering</a></dt> + <dd>Now it's time to start tackling the footer functionality in our app. Here we'll get the todo counter to update to show the correct number of todos still to complete, and correctly apply styling to completed todos (i.e. where the checkbox has been checked). We'll also wire up our "Clear completed" button. Along the way, we'll learn about using conditional rendering in our templates.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing">5. Routing in Ember</a></dt> + <dd>In this article we learn about routing, or URL-based filtering as it is sometimes referred to. We'll use it to provide a unique URL for each of the three todo views — "All", "Active", and "Completed".</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources">6. Ember resources and troubleshooting</a></dt> + <dd>Our final Ember article provides you with a list of resources that you can use to go further in your learning, plus some useful troubleshooting and other information.</dd> +</dl> + +<h2 id="Vue_tutorials">Vue tutorials</h2> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Vue tutorials last tested in May 2020, with Vue 2.6.11.</p> + +<p>If you need to check your code against our version, you can find a finished version of the sample Vue app code in our <a href="https://github.com/mdn/todo-vue">todo-vue repository</a>. For a running live version, see <a href="https://mdn.github.io/todo-vue/dist/">https://mdn.github.io/todo-vue/dist/</a>.</p> +</div> + +<dl> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started">1. Getting started with Vue</a></dt> + <dd>Now let's introduce Vue, the third of our frameworks. In this article we'll look at a little bit of Vue background, learn how to install it and create a new project, study the high-level structure of the whole project and an individual component, see how to run the project locally, and get it prepared to start building our example.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component">2. Creating our first Vue component</a></dt> + <dd>Now it's time to dive deeper into Vue, and create our own custom component — we'll start by creating a component to represent each item in the todo list. Along the way, we'll learn about a few important concepts such as calling components inside other components, passing data to them via props, and saving data state.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists">3. Rendering a list of Vue components</a></dt> + <dd><span class="author-d-1gg9uz65z1iz85zgdz68zmqkz84zo2qoxwoxz78zz83zz84zz69z2z80zgwxsgnz83zfkt5e5tz70zz68zmsnjz122zz71z">At this point we've got a fully working component; we're now ready to add multiple <code>ToDoItem</code> components to our App. In this artcle we'll look at adding a set of todo item data to our <code>App.vue</code> component, which we'll then loop through and display inside <code>ToDoItem</code> components using the <code>v-for</code> directive. </span></dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models">4. Adding a new todo form: Vue events, methods, and models</a></dt> + <dd>We now have sample data in place, and a loop that takes each bit of data and renders it inside a <code>ToDoItem</code> in our app. What we really need next is the ability to allow our users to enter their own todo items into the app, and for that we'll need a text <code><input></code>, an event to fire when the data is submitted, a method to fire upon submission to add the data and rerender the list, and a model to control the data. This is what we'll cover in this article.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling">5. Styling Vue components with CSS</a></dt> + <dd>The time has finally come to make our app look a bit nicer. In this article we'll explore the different ways of styling Vue components with CSS.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties">6. Using Vue computed properties</a></dt> + <dd>In this article we'll add a counter that displays the number of completed todo items, using a feature of Vue called computed properties. These work similarly to methods, but only re-run when one of their dependencies changes.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering">7. Vue conditional rendering: editing existing todos</a></dt> + <dd>Now it is time to add one of the major parts of functionality that we're still missing — the ability to edit existing todo items. To do this, we will take advantage of Vue's conditional rendering capabilities — namely <code>v-if</code> and <code>v-else</code> — to allow us to toggle between the existing todo item view, and an edit view where you can update todo item labels. We'll also look at adding functionality to delete todo items.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management">8. Focus management with Vue refs</a></dt> + <dd>We are nearly done with Vue. The last bit of functionality to look at is focus management, or put another way, how we can improve our app's keyboard accessibility. We'll look at using Vue refs to handle this — an advanced feature that allows you to have direct access to the underlying DOM nodes below the virtual DOM, or direct access from one component to the internal DOM structure of a child component.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources">9. Vue resources</a></dt> + <dd>Now we'll round off our study of Vue by giving you a list of resources that you can use to go further in your learning, plus some other useful tips.</dd> +</dl> + +<h2 id="Which_frameworks_did_we_choose">Which frameworks did we choose?</h2> + +<p>We are publishing our initial set of articles with guides focusing on three of the major frameworks out there — React/ReactDOM, Ember, and Vue. There is a variety of reasons for this:</p> + +<ul> + <li>They are popular choices that will be around for a while — like with any software tool, it is good to stick with actively-developed choices that are likely to not be discontinued next week, and which will be desirable additions to your skillset when looking for a job.</li> + <li>They have strong communities and good documentation. It is very important to be able to get help with learning a complex subject, especially when you are just starting out.</li> + <li>We don't have the resources to cover <em>all</em> modern frameworks. That list would be very difficult to keep up-to-date anyway, as new ones appear all the time.</li> + <li>As a beginner, trying to choose what to focus on out of the huge number of choices available is a very real problem. Keeping the list short is therefore helpful.</li> +</ul> + +<p>We want to say this up front — we've <strong>not</strong> chosen the frameworks we are focusing on because we think they are the best, or because we endorse them in any way. We just think they score highly on the above criteria.</p> + +<p>Note that we were hoping to have more frameworks included upon intial publication, but we decided to release the content and then add more framework guides later, rather than delay it longer. If your favourite framework is not represented in this content and you'd like to help change that, feel free to discuss it with us! Get in touch with us via <a href="https://wiki.mozilla.org/Matrix">Matrix</a>, or <a href="https://discourse.mozilla.org/c/mdn">Discourse</a>, or drop us a mail on the <a href="mailto:mdn-admins@mozilla.org">mdn-admins list</a>.</p> diff --git a/files/ru/learn/tools_and_testing/фронтенд_javascript_фреймворки/react_getting_started/index.html b/files/ru/learn/tools_and_testing/фронтенд_javascript_фреймворки/react_getting_started/index.html new file mode 100644 index 0000000000..9a898b282a --- /dev/null +++ b/files/ru/learn/tools_and_testing/фронтенд_javascript_фреймворки/react_getting_started/index.html @@ -0,0 +1,462 @@ +--- +title: Начало работы с React +slug: Learn/Tools_and_testing/Фронтенд_JavaScript_фреймворки/React_getting_started +translation_of: >- + Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</div> + +<p class="summary">В этой статье мы скажем привет React. Мы узнаем немного подробностей о его происхождении и сценариях использования, настроим базовый набор инструментов на нашем локальном компьютере, а также создадим и поиграем с простым приложением для начинающих, и в процессе узнаем немного о том, как React работает .</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Что нужно знать:</th> + <td> + <p><a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, и <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>, быть знакомым с <a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Command_line">терминалом/коммандной строкой</a>.</p> + + <p>React использует синтаксис HTML-in-JavaScript под названием JSX (JavaScript и XML). Знание HTML и JavaScript поможет вам изучить JSX и лучше определить, связаны ли ошибки в вашем приложении с JavaScript или с более специфической областью React.</p> + </td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td> + <p>Настроить локальную среду разработки React, создать стартовое приложение и понять основы его работы.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Привет_Реакт">Привет Реакт</h2> + +<p>Как гласит официальный слоган, <a href="https://ru.reactjs.org/">React</a> - это библиотека для создания пользовательских интерфейсов. React не является фреймворком – он даже не рассчитан исключительно для web. Он используется для визуализации и в связке с другими библиотеками. Например, <a href="https://reactnative.dev/">React Native</a> можно использовать для создания мобильных приложений; <a href="https://facebook.github.io/react-360/">React 360</a> можно использовать для создания приложений виртуальной реальности; помимо того есть и другие <a href="https://github.com/chentsulin/awesome-react-renderer">варианты</a>.</p> + +<p>Для создания веб-приложений разработчики используют React в тандеме с <a href="https://reactjs.org/docs/react-dom.html">ReactDOM</a>. React and ReactDOM часто обсуждаются в том же пространстве и используются для решения тех же проблем, что и другие настоящие фреймворки для веб-разработки. Когда мы ссылаемся на React как на «фреймворк», мы подразумеваем это разговорное понимание.</p> + +<p>Основная цель React - минимизировать ошибки, возникающие при разработке пользовательских интерфейсов. Это достигается за счет использования компонентов - автономных логических фрагментов кода, которые описывают часть пользовательского интерфейса. А уже эти компоненты объединяются для создания полноценного пользовательского интерфейса. React абстрагирует большую часть работы по визуализации, оставляя вам возможность сосредоточиться на дизайне.</p> + +<h2 id="Когда_использовать">Когда использовать</h2> + +<p>В отличие от других платформ, рассматриваемых в этом модуле, React не обязывает к строгим правилам в отношении соглашений о коде или организации файлов. Это позволяет командам договариваться, что для них более подходит, и структурировать React проект соответствующим образом. React может отвечать за одну кнопку, несколько частей или же весь пользовательский интерфейс приложения.</p> + +<p>Хотя React <em>можно</em> использовать для <a href="https://ru.reactjs.org/docs/add-react-to-a-website.html">небольших частей интерфейса</a>, «зайти» в него не так просто, как, к примеру, в jQuery, или даже во Vue. Куда легче это сделать создав всё приложения с помощью React.</p> + +<p>Кроме того, такие преимущества React-приложения, как написание интерфейсов с помощью JSX, требуют процесса компиляции. Добавление на сайт компилятора Babel приводит к более медленному выполнению кода, поэтому такие инструменты обычно настраиваются для процесса сборки. Да, возможно, у React есть серьезные требования к инструментарию, но этому можно освоить.</p> + +<p>В этой статье основное внимание будет уделено использованию React для создания всего пользовательского интерфейса с помощью <a href="https://create-react-app.dev/">create-react-app</a>, предоставляемого Facebook.</p> + +<h2 id="Как_React_использует_JavaScript">Как React использует JavaScript?</h2> + +<p>React utilizes features of modern JavaScript for many of its patterns. Its biggest departure from JavaScript comes with the use of <a href="https://reactjs.org/docs/introducing-jsx.html">JSX</a> syntax. JSX extends JavaScript's syntax so that HTML-like code can live alongside it. For example:</p> + +<pre class="brush: js notranslate">const heading = <h1>Mozilla Developer Network</h1>;</pre> + +<p>This heading constant is known as a <strong>JSX expression</strong>. React can use it to render that <code><a href="/en-US/docs/Web/HTML/Element/Heading_Elements"><h1></a></code> tag in our app.</p> + +<p>Suppose we wanted to wrap our heading in a <code><a href="/en-US/docs/Web/HTML/Element/header"><header></a></code> tag, for semantic reasons? The JSX approach allows us to nest our elements within each other, just like we do with HTML:</p> + +<pre class="brush: js notranslate">const header = ( + <header> + <h1>Mozilla Developer Network</h1> + </header> +);</pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: The parentheses in the previous snippet aren't unique to JSX, and don’t have any effect on your application. They're a signal to you (and your computer) that the multiple lines of code inside are part of the same expression. You could just as well write the header expression like this:</p> + +<pre class="brush: js notranslate">const header = <header> + <h1>Mozilla Developer Network</h1> +</header></pre> + +<p>However, this looks kind of awkward, because the <code><a href="/en-US/docs/Web/HTML/Element/header"><header></a></code> tag that starts the expression is not indented to the same position as its corresponding closing tag.</p> +</div> + +<p>Of course, your browser can't read JSX without help. When compiled (using a tool like <a href="https://babeljs.io/">Babel</a> or <a href="https://parceljs.org/">Parcel</a>), our header expression would look like this:</p> + +<pre class="brush: js notranslate">const header = React.createElement("header", null, + React.createElement("h1", null, "Mozilla Developer Network") +);</pre> + +<p>It's <em>possible</em> to skip the compilation step and use <code><a href="https://reactjs.org/docs/react-api.html#createelement">React.createElement()</a></code> to write your UI yourself. In doing this, however, you lose the declarative benefit of JSX, and your code becomes harder to read. Compilation is an extra step in the development process, but many developers in the React community think that the readability of JSX is worthwhile. Plus, popular tooling makes JSX-to-JavaScript compilation part of its setup process. You don't have to configure compilation yourself unless you want to.</p> + +<p>Because JSX is a blend of HTML and JavaScript, some developers find it intuitive. Others say that its blended nature makes it confusing. Once you're comfortable with it, however, it will allow you build user interfaces more quickly and intuitively, and allow others to better understand your code base at a glance.</p> + +<p>To read more about JSX, check out the React team's <a href="https://reactjs.org/docs/jsx-in-depth.html">JSX In Depth</a> article.</p> + +<h2 id="Настройка_вашего_первого_React_приложения">Настройка вашего первого React приложения</h2> + +<p>There are many ways to use React, but we're going to use the command-line interface (CLI) tool create-react-app, as mentioned earlier, which expedites the process of developing a React application by installing some packages and creating some files for you, handling the tooling described above.</p> + +<p>It's possible to <a href="https://reactjs.org/docs/add-react-to-a-website.html">add React to a website without create-react-app</a> by copying some <code><a href="/en-US/docs/Web/HTML/Element/script"><script></a></code> elements into an HTML file, but the create-react-app CLI is a common starting point for React applications. Using it will allow you spend more time building your app, and less time fussing with setup.</p> + +<h3 id="Requirements">Requirements</h3> + +<p>In order to use create-react-app, you need to have <a href="https://nodejs.org/en/">Node.js</a> installed. It's recommended that you use the long-term support (LTS) version. Node includes npm (the node package manager), and npx (the node package runner).</p> + +<p>You may also use the Yarn package manager as an alternative, but we'll assume you are using npm in this set of tutorials. See <a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Package_management">Package management basics</a> for more information on npm and yarn.</p> + +<p>If you're using Windows, you will need to install some software to give you parity with Unix/macOS terminal in order to use the terminal commands mentioned in this tutorial. <strong>Gitbash</strong> (which comes as part of the <a href="https://gitforwindows.org/">git for Windows toolset</a>) or <strong><a href="https://docs.microsoft.com/en-us/windows/wsl/about">Windows Subsystem for Linux</a></strong> (<strong>WSL</strong>) are both suitable. See <a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Command_line">Command line crash course</a> for more information on these, and on terminal commands in general.</p> + +<p>Also bear in mind that React and ReactDOM produce apps that only work on a fairly modern set of browsers — IE9+ by way of some polyfills. It is recommended that you use a modern browser like Firefox, Safari, or Chrome when working through these tutorials.</p> + +<p>Also see the following for more information:</p> + +<ul> + <li><a href="https://nodejs.org/en/knowledge/getting-started/npm/what-is-npm/">"What is npm" on nodejs.org</a></li> + <li><a href="https://blog.npmjs.org/post/162869356040/introducing-npx-an-npm-package-runner">"Introducing npx" on the npm blog</a></li> + <li><a href="https://create-react-app.dev/">The create-react-app documentation</a></li> +</ul> + +<h3 id="Initializing_your_app">Initializing your app</h3> + +<p>create-react-app takes one argument: the name you'd like to give your app. create-react-app uses this name to make a new directory, then creates the necessary files inside it. Make sure you <code>cd</code> to the place you'd like your app to live on your hard drive, then run the following in your terminal:</p> + +<pre class="brush: bash notranslate">npx create-react-app moz-todo-react</pre> + +<p>This creates a <code>moz-todo-react</code> directory, and does several things inside it:</p> + +<ul> + <li>Installs some npm packages essential to the functionality of the app.</li> + <li>Writes scripts for starting and serving the application.</li> + <li>Creates a structure of files and directories that define the basic app architecture.</li> + <li>Initializes the directory as a git repository, if you have git installed on your computer.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: if you have the yarn package manager installed, create-react-app will default to using it instead of npm. If you have both package managers installed and explicitly want to use NPM, you can add the flag <code>--use-npm</code> when you run create-react-app:</p> + +<pre class="brush: bash notranslate">npx create-react-app moz-todo-react --use-npm</pre> +</div> + +<p>create-react-app will display a number of messages in your terminal while it works; this is normal! This might take a few minutes, so now might be a good time to go make a cup of tea.</p> + +<p>When the process is complete, <code>cd</code> into the <code>moz-todo-react</code> directory and run the command <code>npm start</code>. The scripts installed by create-react-app will start being served at a local server at localhost:3000, and open the app in a new browser tab. Your browser will display something like this:</p> + +<p><img alt="Screenshot of Firefox MacOS, open to localhost:3000, showing the default create-react-app application" src="https://mdn.mozillademos.org/files/17203/default-create-react-app.png" style="border-style: solid; border-width: 1px; height: 980px; width: 1600px;"></p> + +<h3 id="Application_structure">Application structure</h3> + +<p>create-react-app gives us everything we need to develop a React application. Its initial file structure looks like this:</p> + +<pre class="notranslate">moz-todo-react +├── README.md +├── node_modules +├── package.json +├── package-lock.json +├── .gitignore +├── public +│ ├── favicon.ico +│ ├── index.html +│ └── manifest.json +└── src + ├── App.css + ├── App.js + ├── App.test.js + ├── index.css + ├── index.js + ├── logo.svg + └── serviceWorker.js</pre> + +<p>The <strong><code>src</code></strong> directory is where we'll spend most of our time, as it's where the source code for our application lives.</p> + +<p>The <strong><code>public</code></strong> directory contains files that will be read by your browser while you're developing the app; the most important of these is <code>index.html</code>. React injects your code into this file so that your browser can run it. There's some other markup that helps create-react-app function, so take care not to edit it unless you know what you're doing. You very much should change the text inside the <code><a href="/en-US/docs/Web/HTML/Element/title"><title></a></code> element in this file to reflect the title of your application. Accurate page titles are important for accessibility!</p> + +<p>The <code>public</code> directory will also be published when you build and deploy a production version of your app. We won’t cover deployment in this tutorial, but you should be able to use a similar solution to that described in our <a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Deployment">Deploying our app</a> tutorial.</p> + +<p>The <code>package.json</code> file contains information about our project that Node.js/npm uses to keep it organized. This file is not unique to React applications; create-react-app merely populates it. You don't need to understand this file at all to complete this tutorial, however, if you'd like to learn more about it, you can read <a href="https://nodejs.org/en/knowledge/getting-started/npm/what-is-the-file-package-json/">What is the file `package.json`? on NodeJS.org</a>; we also talk about it in our <a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Package_management">Package management basics</a> tutorial.</p> + +<h2 id="Изучаем_наш_первый_React_компонент_—_<App>">Изучаем наш первый React компонент — <code><App/></code></h2> + +<p>In React, a <strong>component</strong> is a reusable module that renders a part of our app. These parts can be big or small, but they are usually clearly defined: they serve a single, obvious purpose.</p> + +<p>Let's open <code>src/App.js</code>, since our browser is prompting us to edit it. This file contains our first component, <code>App</code>, and a few other lines of code:</p> + +<pre class="brush: js notranslate">import React from 'react'; +import logo from './logo.svg'; +import './App.css'; + +function App() { + return ( + <div className="App"> + <header className="App-header"> + <img src={logo} className="App-logo" alt="logo" /> + <p> + Edit <code>src/App.js</code> and save to reload. + </p> + <a + className="App-link" + href="https://reactjs.org" + target="_blank" + rel="noopener noreferrer" + > + Learn React + </a> + </header> + </div> + ); +} +export default App;</pre> + +<p>The <code>App.js</code> file consists of three main parts: some <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/import">import</a></code> statements at the top, the <code>App</code> component in the middle, and an <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/export">export</a></code> statement at the bottom. Most React components follow this pattern.</p> + +<h3 id="Import_statements">Import statements</h3> + +<p>The <code>import</code> statements at the top of the file allow <code>App.js</code> to use code that has been defined elsewhere. Let's look at these statements more closely.</p> + +<pre class="brush: js notranslate">import React from 'react'; +import logo from './logo.svg'; +import './App.css';</pre> + +<p>The first statement imports the React library itself. Because React turns the JSX we write into <code>React.createElement()</code>, all React components must import the <code>React</code> module. If you skip this step, your application will produce an error.</p> + +<p>The second statement imports a logo from <code>'./logo.svg'</code>. Note the <code>./</code> at the beginning of the path, and the <code>.svg</code> extension at the end — these tell us that the file is local and that it is not a JavaScript file. Indeed, the <code>logo.svg</code> file lives in our source directory.</p> + +<p>We don't write a path or extension when importing the <code>React</code> module — this is not a local file; instead, it is listed as a dependency in our <code>package.json</code> file. Be careful of this distinction as you work through this lesson!</p> + +<p>The third statement imports the CSS related to our App component. Note that there is no variable name and no <code>from</code> directive. This particular import syntax is not native to JavaScript module syntax – it comes from Webpack, the tool create-react-app uses to bundle all our JavaScript files together and serve them to the browser.</p> + +<h3 id="The_App_component">The <code>App</code> component</h3> + +<p>After the imports, we have a function named <code>App</code>. Whereas most of the JavaScript community prefers camel-case names like <code>helloWorld</code>, React components use pascal-case variable names, like <code>HelloWorld</code>, to make it clear that a given JSX element is a React component, and not a regular HTML tag. If you were to rename the <code>App</code> function to <code>app</code>, your browser would show you an error.</p> + +<p>Let's look at App more closely.</p> + +<pre class="brush: js notranslate">function App() { + return ( + <div className="App"> + <header className="App-header"> + <img src={logo} className="App-logo" alt="logo" /> + <p> + Edit <code>src/App.js</code> and save to reload. + </p> + <a + className="App-link" + href="https://reactjs.org" + target="_blank" + rel="noopener noreferrer" + > + Learn React + </a> + </header> + </div> + ); +}</pre> + +<p>The <code>App</code> function returns a JSX expression. This expression defines what your browser ultimately renders to the DOM.</p> + +<p>Some elements in the expression have attributes, which are written just like in HTML, following a pattern of <code>attribute="value"</code>. On line 3, the opening <code><a href="/en-US/docs/Web/HTML/Element/div"><div></a></code> tag has a <code>className</code> attribute. This the same as the <code><a href="/en-US/docs/Web/HTML/Global_attributes/class">class</a></code> attribute in HTML, but because JSX is JavaScript, we can't use the word <code>class</code> – it's reserved, meaning JavaScript already uses it for a specific purpose and it would cause problems here in our code. A few other HTML attributes are written differently in JSX than they are in HTML too, for the same kind of reason. We'll cover them as we encounter them.</p> + +<p>Take a moment to change the <code><a href="/en-US/docs/Web/HTML/Element/p"><p></a></code> tag on line 6 so that it reads "Hello, world!", then save your file. You'll notice that this change is immediately rendered in the development server running at <code>http://localhost:3000</code> in your browser. Now delete the <code><a href="/en-US/docs/Web/HTML/Element/a"><a></a></code> tag and save; the "Learn React" link will be gone.</p> + +<p>Your <code>App</code> component should now look like this:</p> + +<pre class="brush: js notranslate">function App() { + return ( + <div className="App"> + <header className="App-header"> + <img src={logo} className="App-logo" alt="logo" /> + <p> + Hello, World! + </p> + </header> + </div> + ); +}</pre> + +<h3 id="Export_statements">Export statements</h3> + +<p>At the very bottom of the <code>App.js</code> file, the statement <code>export default App</code> makes our <code>App</code> component available to other modules.</p> + +<h2 id="Interrogating_the_index">Interrogating the index</h2> + +<p>Let’s open <code>src/index.js</code>, because that's where the <code>App</code> component is being used. This file is the entry point for our app, and it initially looks like this:</p> + +<pre class="brush: js notranslate">import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; +import * as serviceWorker from './serviceWorker'; + +ReactDOM.render(<App />, document.getElementById('root')); + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: https://bit.ly/CRA-PWA +serviceWorker.unregister();</pre> + +<p>As with <code>App.js</code>, the file starts by importing all the JS modules and other assets it needs to run. <code>src/index.css</code> holds global styles that are applied to our whole app. We can also see our <code>App</code> component imported here; it is made available for import thanks to the <code>export</code> statement at the bottom of <code>App.js</code>.</p> + +<p>Line 7 calls React’s <code>ReactDOM.render()</code> function with two arguments:</p> + +<ul> + <li>The component we want to render, <code><App /></code> in this case.</li> + <li>The DOM element inside which we want the component to be rendered, in this case the element with an ID of <code>root</code>. If you look inside <code>public/index.html</code>, you'll see that this is a <code><div></code> element just inside the <code><body></code>.</li> +</ul> + +<p>All of this tells React that we want to render our React application with the <code>App</code> component as the root, or first component.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: In JSX, React components and HTML elements must have closing slashes. Writing just <code><App></code> or just <code><img></code> will cause an error.</p> +</div> + +<p><a href="/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">Service workers</a> are interesting pieces of code that help application performance and allow features of your web applications to work offline, but they’re not in scope for this article. You can delete line 5, as well as lines 9 through 12.</p> + +<p>Your final <code>index.js</code> file should look like this:</p> + +<pre class="brush: js notranslate">import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; + +ReactDOM.render(<App />, document.getElementById('root'));</pre> + +<h2 id="Переменные_и_свойства">Переменные и свойства</h2> + +<p>Next, we'll use a few of our JavaScript skills to get a bit more comfortable editing components and working with data in React. We'll talk about how variables are used inside JSX, and introduce props, which are a way of passing data into a component (which can then be accessed using variables).</p> + +<h3 id="Variables_in_JSX">Variables in JSX</h3> + +<p>Back in <code>App.js</code>, let’s focus on line 9:</p> + +<pre class="brush: js notranslate"><img src={logo} className="App-logo" alt="logo" /></pre> + +<p>Here, the <code><img /></code> tag's <code>src</code> attribute value is in curly braces. This is how JSX recognizes variables. React will see <code>{logo}</code>, know you are referring to the logo import on line 2 of our app, then retrieve the logo file and render it.</p> + +<p>Let's try making a variable of our own. Before the return statement of <code>App</code>, add <code>const subject = 'React';</code>. Your <code>App</code> component should now look like this:</p> + +<pre class="brush: js notranslate">function App() { + const subject = "React"; + return ( + <div className="App"> + <header className="App-header"> + <img src={logo} className="App-logo" alt="logo" /> + <p> + Hello, World! + </p> + </header> + </div> + ); +}</pre> + +<p>Change line 8 to use our <code>subject</code> variable instead of the word "world", like this:</p> + +<pre class="brush: js notranslate">function App() { + const subject = "React"; + return ( + <div className="App"> + <header className="App-header"> + <img src={logo} className="App-logo" alt="logo" /> + <p> + Hello, {subject}! + </p> + </header> + </div> + ); +}</pre> + +<p>When you save, your browser should display "Hello, React!" instead of "Hello, world!"</p> + +<p>Variables are convenient, but the one we've just set doesn’t make great use of React's features. That's where props come in.</p> + +<h3 id="Component_props">Component props</h3> + +<p>A <strong>prop</strong> is any data passed into a React component. Props are written inside component calls, and use the same syntax as HTML attributes — <code>prop="value"</code>. Let’s open <code>index.js</code> and give our <code><App/></code> call its first prop.</p> + +<p>Add a prop of <code>subject</code> to the <code><App/></code> component call, with a value of <code>Clarice</code>. When you are done, your code should look something like this:</p> + +<pre class="brush: js notranslate">ReactDOM.render(<App subject="Clarice" />, document.getElementById('root'));</pre> + +<p>Back in <code>App.js</code>, let's revisit the App function itself, which reads like this (with the <code>return</code> statement shortened for brevity):</p> + +<pre class="brush: js notranslate">function App() { + const subject = "React"; + return ( + // return statement + ); +}</pre> + +<p>Change the signature of the <code>App</code> function so that it accepts <code>props</code> as a parameter. Just like any other parameter, you can put <code>props</code> in a <code>console.log()</code> to read it out to your browser's console. Go ahead and do that after your <code>subject</code> constant but before the <code>return</code> statement, like so:</p> + +<pre class="brush: js notranslate">function App(props) { + const subject = "React"; + console.log(props); + return ( + // return statement + ); +}</pre> + +<p>Save your file and check your browser's JavaScript console. You should see something like this logged:</p> + +<pre class="brush: js notranslate">Object { subject: "Clarice" }</pre> + +<p>The object property <code>subject</code> corresponds to the <code>subject</code> prop we added to our <code><App /></code> component call, and the string <code>Clarice</code> corresponds to its value. Component props in React are always collected into objects in this fashion.</p> + +<p>Now that <code>subject</code> is one of our props, let's utilize it in <code>App.js</code>. Change the <code>subject</code> constant so that, instead of defining it as the string <code>React</code>, you are reading the value of <code>props.subject</code>. You can also delete your <code>console.log()</code> if you want.</p> + +<pre class="brush: js notranslate">function App(props) { + const subject = props.subject; + return ( + // return statement + ); +}</pre> + +<p>When you save, the the app should now greet you with "Hello, Clarice!". If you return to <code>index.js</code>, edit the value of <code>subject</code>, and save, your text will change.</p> + +<h2 id="Резюме">Резюме</h2> + +<p>This brings us to the end of our initial look at React, including how to install it locally, creating a starter app, and how the basics work. In the next article we'll start building our first proper application — a todo list. Before we do that, however, let's recap some of the things we’ve learned.</p> + +<p>In React:</p> + +<ul> + <li>Components can import modules they need, and must export themselves at the bottom of their files.</li> + <li>Component functions are named with <code>PascalCase</code>.</li> + <li>You can read JSX variables by putting them between curly braces, like <code>{so}</code>.</li> + <li>Some JSX attributes are different to HTML attributes, so that they don't conflict with JavaScript reserved words. For example, <code>class</code> in HTML translates to <code>className</code> in JSX. Note that multi-word attributes are camel-cased.</li> + <li>Props are written just like attributes inside component calls, and are passed into components.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">Introduction to client-side frameworks</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features">Framework main features</a></li> + <li>React + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started">Getting started with React</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning">Beginning our React todo list</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components">Componentizing our React app</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state">React interactivity: Events and state</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering">React interactivity: Editing, filtering, conditional rendering</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility">Accessibility in React</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources">React resources</a></li> + </ul> + </li> + <li>Ember + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started">Getting started with Ember</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization">Ember app structure and componentization</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state">Ember interactivity: Events, classes and state</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer">Ember Interactivity: Footer functionality, conditional rendering</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing">Routing in Ember</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources">Ember resources and troubleshooting</a></li> + </ul> + </li> + <li>Vue + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started">Getting started with Vue</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component">Creating our first Vue component</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists">Rendering a list of Vue components</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models">Adding a new todo form: Vue events, methods, and models</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling">Styling Vue components with CSS</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties">Using Vue computed properties</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering">Vue conditional rendering: editing existing todos</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management">Focus management with Vue refs</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources">Vue resources</a></li> + </ul> + </li> +</ul> diff --git a/files/ru/learn/understanding_domain_names/index.html b/files/ru/learn/understanding_domain_names/index.html new file mode 100644 index 0000000000..fb561cf8ea --- /dev/null +++ b/files/ru/learn/understanding_domain_names/index.html @@ -0,0 +1,155 @@ +--- +title: Что такое доменные имена +slug: Learn/Understanding_domain_names +tags: + - DNS + - вводная + - домен + - доменное имя + - начальный уровень +translation_of: Learn/Common_questions/What_is_a_domain_name +--- +<div class="summary"> +<p>В этом материале мы обсудим доменные имена: что это такое, как они формируются и как зарегистрировать домен для себя.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Вы должны знать <a href="/en-US/docs/Learn/How_the_Internet_works">как работает Интернет</a> и понимать устройтво <a href="/en-US/Learn/Understanding_URLs">устройство URL</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Вы узнаете, что такое доменные имена, как они работают и почему они важны.</td> + </tr> + </tbody> +</table> + +<h2 id="Summary">Summary</h2> + +<p><span class="seoSummary">Доменные имена - ключевая составляющая инфраструктуры Интернета. Они предоставляют человеко-читаемые адреса веб-серверов, доступных в Интернете.</span></p> + +<p>Каждый компьютер подключен к Интернету и может быть доступен через публичный {{Glossary("IP")}}-адрес, который состоит из 32 бит для IPv4 адреса (такие адреса обычно записываются в виде четырёх чисел от 0 до 255, разделённых точками (напр., <code>173.194.121.32</code>) или 128 bit для IPv6 адреса (они обычно записываются в виде 8 групп по 4 шеснадцетиричных чисел, разделенных двоеточиями (напр, <code>2027:0da8:8b73:0000:0000:8a2e:0370:1337</code>). Компьютеры могут легко обрабатывать эти адреса , но у живых людей уходит слишком много времени на использование таких адресов. IP-адреса также сложно запоминаются и часто меняются со временем. Для решения этой проблемы в Интернете используются человеко-читаемые адреса, называемые доменными именами.</p> + +<h2 id="Активно_изучаем">Активно изучаем</h2> + +<p><em>В данный момент нет обучающего курса . Но вы можете <a href="https://developer.mozilla.org/en-US/docs/MDN/Getting_started">помочь составить его</a>.</em></p> + +<h2 id="Глубокое_погружение">Глубокое погружение</h2> + +<h3 id="Структура_доменных_имён">Структура доменных имён</h3> + +<p>Доменное имя имеет простую структуру, состояющую из нескольких частей (частей может быть бесконечное количество, но на практике число уровней обычно невелико), разделенных точками и <strong>читаемых справа налево</strong>:</p> + +<p><img alt="Anatomy of the MDN domain name" src="https://mdn.mozillademos.org/files/11229/structure.png" style="height: 76px; width: 252px;"></p> + +<p>Каждая из этих частей предоставляет специфическую информацию о доменном имени.</p> + +<dl> + <dt>{{Glossary("TLD")}} (Корневой домен).</dt> + <dd>Корневой домен сообщает наиболее общую информацию. Корневой домен говорит пользователям наиболее общую информацию о службе, доступной по доменному имени. Наиболее общие корневые домены (.com, .org, .net) не требуют от веб-службы соответствия строгим критериям, но некоторые корневые домены имеют и более строгие политики. Например, локальные корневые домены, такие как .us, .fr, или .sh, могут требовать, чтобы услуги по данному адресу предоставлялись на национальном языке или физически размещались на территории страны.</dd> + <dt>Домены</dt> + <dd>Домены - это то, что следует за корневыми доменами. Домен может представлять собой что угодно, от одного знака до целого предложения. Домен сразу за корневым доменом также называют <em>"доменом второго уровня"</em>. Доменное имя может включать неограниченное количество доменов, нет никакого ограничения только на 3 домена в составе доменного имени. Например, www.inf.ed.ac.uk - это корректное доменное имя. Тот, кто контролирует "верхнюю" часть доменного имени (например, <a href="https://mozilla.org">mozilla.org</a>), тот может создавать доменные имена более "низких" уровней (часто называемые, "поддоменами") (например, <a href="https://developer.mozilla.org">developer.mozilla.org</a>).</dd> +</dl> + +<h3 id="Покупка_доменного_имени">Покупка доменного имени</h3> + +<h4 id="Кто_владеет_доменным_именем">Кто владеет доменным именем?</h4> + +<p>Вы не можете “купить доменное имя”. Вы платите за право использовать доменное имя в течение одного или нескольких лет. Вы можете продлить это право и ваше продление будет иметь безусловный приоритет над заявками на домен от других желающих. Но вы никогда не владете доменным именем.</p> + +<p>Компании, называемые регистраторами, ведут реестры доменных имён, которые содержат техническую и административную информацию, связывающую вас и ваш домен.</p> + +<div class="note"> +<p><strong>Примечание: </strong>Для некоторых доменных имён регистратор может отсутстовать, реестр может не вестись. Например, все домены в зоне .fire используются компанией Amazon только в собственных нуждах.</p> +</div> + +<h4 id="Как_найти_свободное_доменное_имя">Как найти свободное доменное имя</h4> + +<p>Для того, чтобы определить, свободно или нет желаемое доменное имя, сделайте следующее,</p> + +<ul> + <li>Перейдите на веб-сайта регистратора доменных имён. Большинство из них предоставляют сервис "whois", который подскажет вам, свободно ли желаемое доменное имя.</li> + <li>Также мы можете использовать командную строку, введя в ней команду whois и получив ответ, например, для <code>mozilla.org</code>:</li> +</ul> + +<pre>$ whois mozilla.org +Domain Name:MOZILLA.ORG +Domain ID: D1409563-LROR +Creation Date: 1998-01-24T05:00:00Z +Updated Date: 2013-12-08T01:16:57Z +Registry Expiry Date: 2015-01-23T05:00:00Z +Sponsoring Registrar:MarkMonitor Inc. (R37-LROR) +Sponsoring Registrar IANA ID: 292 +WHOIS Server: +Referral URL: +Domain Status: clientDeleteProhibited +Domain Status: clientTransferProhibited +Domain Status: clientUpdateProhibited +Registrant ID:mmr-33684 +Registrant Name:DNS Admin +Registrant Organization:Mozilla Foundation +Registrant Street: 650 Castro St Ste 300 +Registrant City:Mountain View +Registrant State/Province:CA +Registrant Postal Code:94041 +Registrant Country:US +Registrant Phone:+1.6509030800 +</pre> + +<p>Как вы видите, нельзя зарегистрировать доменное имя <code>mozilla.org</code> потому что Mozilla Foundation уже зарегистрировало его.</p> + +<p>Теперь давайте посмотрим, можно ли зарегистрировать доменное имя <code>afunkydomainname.org</code>:</p> + +<pre>$ whois afunkydomainname.org +NOT FOUND +</pre> + +<p>Как вы видите, домен не существует в базе данных whois (на момент написания этой статьи), соответственно, его можно зарегистрировать.</p> + +<h4 id="Как_получить_доменное_имя">Как получить доменное имя</h4> + +<p>Процедура довольно проста:</p> + +<ol> + <li>Перейдите на веб-сайт регистратора доменных имён.</li> + <li>Обычно там есть кнопка "Зарегистрировать домен" или что-то подобное. Нажмите её.</li> + <li>Заполните форму требуемыми данными. Убедитесь, что вы не опечатались в названии доменного имени. Потому что, если вы оплатите его, то будет уже поздно исправлять ошибку!</li> + <li>Регистратор сообщит вам, когда доменное имя будет корректно зарегистрировано. Через несколько часов все DNS-сервера обновятся и ваш домен начнёт работать.</li> +</ol> + +<div class="note"> +<p><strong>Примечание:</strong> В процессе регистрации регистратор доменов спросит вас ваш реальный домашний или рабочий адрес. Обязательно заполните его корректно, потому что многие национальные регистраторы могут отменить регистрацию домена, если был указан ошибочный адрес.</p> +</div> + +<h4 id="Обновление_DNS">Обновление DNS</h4> + +<p>Базы данных DNS хранятся на каждом DNS-сервере по всему миру и эти серверы обращаются за обновлениями к нескольким серверам, называемым “authoritative name server” или “корневой DNS-сервер”. Когда ваш регистратор создаёт или обновляет информацию о зарегистрированном домене, она должна обновиться во всех DNS-базах. Каждый DNS-сервер хранит информацию о домене фиксированное количество времени, а затем автоматически обновляет её (DNS-сервер запрашивает корневой сервер снова). Соответственно, обновление баз занимает какое-то время, пока информация о новых или измененных доменах распространяется по Интернету.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Это время часто называется <strong>время распространения</strong>. Тем не менее эта задержка не означает, что за это время доменное имя обновит само себя на всех серверах сверху донизу. Очень часто DNS-сервер, запрашиваемый вашим компьютером не знает конкретного домена и запрашивает о нём корневые DNS-сервера по мере требования.</p> +</div> + +<h3 id="Как_работает_DNS-запрос">Как работает DNS-запрос?</h3> + +<p>Как мы уже увидели, когда вы хотите, чтобы веб-страница отобразилась в вашем браузере, легче напечатать доменное имя, чем IP-адрес. Давайте разберем весь процесс:</p> + +<ol> + <li>Напечатайте <code>mozilla.org</code> в адресной строке вашего браузера.</li> + <li>Ваш браузер спросит ваш компьютер, знает ли он уже, какому IP-адресу соответствует этот домен (используя локальный DNS-кэш). Если имя есть в кэше, оно транслируется в IP-адрес и браузер направляется к необходимому серверу. И всё.</li> + <li>Если же ваш компьютер не знает, какой IP-адрес соответствует доменному имени <code>mozilla.org</code>, он запрашивает DNS-сервер, чья задача - сообщить вашему компьютеру какой IP-адрес соответствует запрошенному доменному имени.</li> + <li>Теперь ваш компьютер знает соответствие и может взаимодействовать с сервером.</li> +</ol> + +<p><img alt="Explanation of the steps needed to obtain the result to a DNS request" src="https://mdn.mozillademos.org/files/8961/2014-10-dns-request2.png" style="height: 702px; width: 544px;"></p> + +<h2 id="Следующие_шаги">Следующие шаги</h2> + +<p>Итак, мы поговорили о процессах и архитектуре. Время двигаться дальше.</p> + +<ul> + <li>Если вы хотите попробовать сделать что-то руками, то самое время разобраться в дизайне и изучить <a href="/en-US/Learn/Anatomy_of_a_web_page">анатомию веб-страницы</a>.</li> + <li>Также не стоит забывать, что некоторые аспекты создания сайта стоят денег. Здесь мы рассказываем, <a href="/en-US/docs/Learn/How_much_does_it_cost">сколько стоит создание веб-сайта</a>.</li> + <li>И ещё вы можете прочитать о <a href="http://en.wikipedia.org/wiki/Domain_name">доменных именах</a> в Wikipedia.</li> +</ul> diff --git a/files/ru/learn/understanding_links_on_the_web/index.html b/files/ru/learn/understanding_links_on_the_web/index.html new file mode 100644 index 0000000000..63a22eb949 --- /dev/null +++ b/files/ru/learn/understanding_links_on_the_web/index.html @@ -0,0 +1,102 @@ +--- +title: Разбираемся с веб ссылками +slug: Learn/Understanding_links_on_the_web +tags: + - Навигация + - инфраструктура + - начальный уровень +translation_of: Learn/Common_questions/What_are_hyperlinks +--- +<div class="summary"> +<p>В данной статье мы узнаем, что такое ссылки и почему они важны.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительно:</th> + <td>Вы должны знать <a href="/en-US/Learn/How_the_Internet_works">как работает интернет</a> и иметь представление о <a href="/en-US/docs/Learn/page_vs_site_vs_server_vs_search_engine">разнице между веб-страницей, веб-сайтом, веб-сервером и поисковой системой.</a></td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Изучить, что такое веб-ссылки и почему они важны.</td> + </tr> + </tbody> +</table> + +<h2 id="Коротко">Коротко</h2> + +<p>Гиперссылки, в народе ссылки, являются фундаментальной основой Веба. Чтобы объяснить, что такое ссылки, мы должны обратиться к основам Веб-архитектуры. </p> + +<p>В 1989 году Тим Бернерс-Ли (Tim Berners-Lee), создатель Веба, говорил о трёх китах, на которых стоит Веб:</p> + +<ol> + <li>{{Glossary("URL")}}, система адресов, которая отслеживает веб-документы. </li> + <li>{{Glossary("HTTP")}}, транспортный протокол, помогающий найти документы по заданным URL</li> + <li>{{Glossary("HTML")}}, формат документа, позволяющий встраивать <em>гиперссылки</em></li> +</ol> + +<p>Как вы видите, все в Вебе крутится вокруг документов и способах обеспечения доступа к ним. Первоначальная цель Веба заключалась в предоставлении легкого инструмента доступа к текстовым документам, их чтения и навигации по ним. С тех пор Веб эволюционировал в инструмент обеспечения доступа к изображениям, видео и бинарным данным, но все эти улучшения врядли были бы возможны без тех самых трёх китов, о которых говорил Тим. </p> + +<p>До Веба было весьма сложно получить доступ к документам и перемещаться от одного к другому. Став понятными для пользователя, URL'ы уже сделали жизнь гораздо проще, но нам довольно сложно было печатать длинный URL каждый раз, когда мы хотели получить документ. Вот тут то гиперссылки и совершили революцию. Ссылка может связать любой текст с URL, так что пользователь может моментально достигнуть цели всего лишь активируя ссылку.</p> + +<p>По умолчанию голубого цвета и подчёркнутые, ссылки выделяются из общего текста. Кликните на ссылку, чтобы активировать ее, или, если вы используете клавиатуру, перейдите на ссылку при помощи Tab и нажмите Enter.</p> + +<p><img alt="Example of a basic display and effect of a link in a web page" src="https://mdn.mozillademos.org/files/8625/link-1.png" style="height: 492px; width: 477px;"></p> + +<p>Ссылки стали прорывом, который сделал Веб таким полезным и популярным. В остальной части этой статьи мы обсудим различные типы ссылок и их важность в современном Веб-дизайне. </p> + +<h2 id="Активно_изучаем">Активно изучаем</h2> + +<p><em>В данном разделе нет контента. <a href="/en-US/docs/MDN/Getting_started">Please, consider contributing</a>.</em></p> + +<h2 id="Глубокое_погружение">Глубокое погружение</h2> + +<p>Как мы определили, ссылка <span style="background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: Arial,Helvetica,sans-serif; font-size: 13px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;">— </span><strong style="background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: Arial,Helvetica,sans-serif; font-size: 28px; font-style: normal; font-variant: normal; font-weight: 700; letter-spacing: normal; line-height: 1.2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;"> </strong>это строка, которая связана с URL. Мы используем ссылки, чтобы с легкостью перепрыгивать с одного документа на другой. Здесь существуют некоторые нюансы, которые важно рассмотреть: </p> + +<h3 id="Типы_ссылок">Типы ссылок</h3> + +<dl> + <dt>Внутренняя ссылка</dt> + <dd>Ссылка между двумя веб-страницами, принадлежащими к одному веб-сайту. Без внутренных ссылок нет такого понятия как веб-сайт (конечно, если это не одностраничный сайт).</dd> + <dt>Внешняя ссылка</dt> + <dd>Ссылка с вашей веб-страницы на чью-либо другую веб-страницу. Без внешних ссылок не будет Веба, так как Веб <span style="background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: Arial,Helvetica,sans-serif; font-size: 13px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;">— </span> это сеть веб-страниц. Используйте внешние ссылки для того, чтобы предоставить информацию помимо той, что вы поддерживаете на вашем сайте. </dd> + <dt>Входящие ссылки</dt> + <dd>Ссылка с чьей-либо веб-страницы на ваш сайт. Это внешняя ссылка наоборот. Имейте в виду, что вам не обязательно отвечать тем же кому-то, кто ссылается на ваш сайт.</dd> +</dl> + +<p>Когда вы создаёте веб-сайт, фокусируйтесь на внутренних ссылках, так как они делают ваш сайт возможным и удобным для использования. Найдите нужный баланс между большим и недостаточным количеством ссылок. Мы поговорим о дизайне навигации сайта в другой статье, но в качестве правила, каждый раз когда вы создаете веб-страницу, убедитесь, что хотя бы одна из ваших страниц ссылается на неё. С другой стороны, если на вашем сайте более чем десять страниц, добиваться того, чтобы каждая страница ссылалась друг на друга, может быть весьма контрпродуктивно. </p> + +<p>Когда вы начинаете, вам не имеет смысла сильно волноваться о наличии внешних и входящих ссылок, но они важны, если вы хотите, чтобы поисковые системы находили ваш сайт. (См. более детальное объяснение ниже.)</p> + +<h3 id="Якоря_Anchors">Якоря (Anchors)</h3> + +<p>В большинстве случаев ссылки связывают две страницы вместе. <strong>Якоря </strong>(<strong>Anchors) </strong>же связывают две области одного документа. Когда вы следуете по ссылке указывающей на якорь, ваш браузер переходит с одной части текущего документа на другую, вместо загрузки нового документа. Хотя вы создаёте и используете якоря точно так же, как любые другие ссылки. </p> + +<p><img alt="Example of a basic display and effect of an anchor in a web page" src="https://mdn.mozillademos.org/files/8627/link-2.png" style="height: 492px; width: 477px;"></p> + +<h3 id="Ссылки_и_поисковые_системы">Ссылки и поисковые системы</h3> + +<p>Ссылки важны как для ваших пользователей, так и для поисковых систем. Каждый раз когда поисковые движки проверяют страницу, они индексируют сайт следуя по доступным ссылкам. Поисковые движки не только следуют по ссылкам, чтобы обнаружить разные страницы сайта, но также используют текст ссылки, чтобы определить поисковый запрос, который позволит найти страницу. </p> + +<p>Итак, ссылки влияют на готовность поисковых систем сослаться на ваш сайт. Проблема в том, что активность поисковых систем сложно оценить. Компании обычно хотят, чтобы их сайты выводились первыми в результатах поиска, и многочисленные поиски решений дают нам понять, по крайней мере, следующее:</p> + +<ul> + <li>Текст ссылки влияет на то, какой поисковый запрос выдаст URL.</li> + <li>Чем больше существует входящих ссылок на сайт, тем выше он будет в результатах поиска. </li> + <li><em>Внешние ссылки </em>влияют на оценку и сайта источника, и сайта, на который они ссылаются, но в какой степени, <span style="background-color: #ffffff; color: #333333; display: inline !important; float: none; font-family: Arial,Helvetica,sans-serif; font-size: 13px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; white-space: normal;">— </span> не известно. </li> +</ul> + +<p><a href="http://en.wikipedia.org/wiki/Search_engine_optimization">SEO</a> (поисковая оптимизация) - это комплекс мер для "поднятия" позиции сайтов в поисковой выдаче. Оптимизация использования ссылок на сайте является одной из ключевых в SEO.</p> + + + +<h2 id="Следующие_шаги">Следующие шаги</h2> + +<p>Так что теперь, конечно, Вы захотите создать несколько веб-страниц со ссылками!</p> + +<ul> + <li>Чтобы получить более теоретическое обоснование, узнайте об <a href="/en-US/docs/Learn/Understanding_URLs">URL-адресах и их структуре</a>, поскольку каждая ссылка указывает на URL-адрес.</li> + <li>Хотите что-нибудь более практичное? В статье <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Создание гиперссылок</a> нашего модуля <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML">Введение в HTML</a> подробно объясняется, как реализовывать ссылки.</li> + <li>Приступите к изучению HTML. Научитесь <a href="/en-US/docs/Learn/HTML/Write_a_simple_page_in_HTML">создавать HTML-документы и связывать их между собой.</a></li> +</ul> diff --git a/files/ru/learn/understanding_urls/index.html b/files/ru/learn/understanding_urls/index.html new file mode 100644 index 0000000000..41fe5182c7 --- /dev/null +++ b/files/ru/learn/understanding_urls/index.html @@ -0,0 +1,161 @@ +--- +title: Что такое URL-адрес? +slug: Learn/Understanding_URLs +tags: + - URL + - Адрес + - Порт + - Ресурс + - Якорь + - домен + - протокол +translation_of: Learn/Common_questions/What_is_a_URL +--- +<div class="summary"> +<p>Данная статья описывает Единый локатор ресурсов или Uniform Resource Locators (URLs), объясняет, что это такое, и опиcывает его структуру. </p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предварительно:</th> + <td>Вам нужно узнать <a href="/ru/docs/Learn/How_the_Internet_works">как работает интернет</a>, <a href="/ru/docs/Learn/What_is_a_Web_server">что такое Веб сервер</a> and <a href="/ru/docs/Learn/Understanding_links_on_the_web">что лежит в основе веб ссылок </a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Вы узнаете, что такое URL и как они работают в вебе.</td> + </tr> + </tbody> +</table> + +<h2 id="Введение">Введение</h2> + +<p>Наряду с понятиями <a href="/ru/docs/Glossary/Hypertext">гипертекста</a> и <a href="/ru/docs/Glossary/HTTP">протокола HTTP</a>, понятие <a href="ru/docs/Glossary/URL">URL</a> является одной из основных концепций Всемирной паутины. Это механизм, используемый <a href="ru/docs/Glossary/Browser">браузерами</a> для получения любого опубликованного во Всемирной сети ресурса.</p> + +<p><strong>URL</strong> обозначает <em>Uniform Resource Locator</em>. URL это лишь адрес, который выдан уникальному ресурсу в интернете. В теории, каждый корректный URL ведет на уникальный ресурс. Такими ресурсами могут быть HTML-страница, CSS-файл, изображение и т.д. На практике, существуют некоторые исключения, когда, например, URL ведет на ресурс, который больше не существует или который был перемещён. Поскольку ресурс, доступный по URL, а также сам URL обрабатываются веб-сервером, его владелец должен внимательно следить за размещаемыми ресурсами и связанными с ними URL.</p> + +<h2 id="Активное_обучение">Активное обучение</h2> + +<p><em>Активного обучения пока не существует. <a href="/ru/docs/MDN/Getting_started">Пожайлуста подумайте, возможно Вы сможете внести свой вклад</a>.</em></p> + +<h2 id="Подробная_информация">Подробная информация</h2> + +<h3 id="Основы_анатомия_URL">Основы: анатомия URL</h3> + +<p>Вот несколько примеров URL:</p> + +<pre>https://developer.mozilla.org +https://developer.mozilla.org/ru/docs/Learn/ +https://developer.mozilla.org/ru/search?q=URL</pre> + +<p>Каждый из этих URLs могут быть напечатаны в адресной строке браузера, чтобы заставить его загрузить связанную страницу (ресурс).</p> + +<p>URL состоит из различных частей, некоторые из которых являются обязательными, а некоторые - факультативными. Рассмотрим наиболее важные части на примере:</p> + +<pre>http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument</pre> + +<dl> + <dt><img alt="Protocol" src="https://mdn.mozillademos.org/files/8013/mdn-url-protocol@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>http://</code> это протокол. Он отображает, какой протокол браузер должен использовать. Обычно это HTTP-протокол или его безопасная версия - HTTPS. Интернет требует эти 2 протокола, но браузеры часто могут использовать и другие протоколы, например <code>mailto:</code> (чтобы открыть почтовый клиент) или <code>ftp:</code> для запуска передачи файлов, так что не стоит удивляться, если вы вдруг увидите другие протоколы.</dd> + <dt><img alt="Domaine Name" src="https://mdn.mozillademos.org/files/8015/mdn-url-domain@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>www.example.com</code> это доменное имя. Оно означает, какой веб-сервер должен быть запрошен. В качестве альтернативы может быть использован и {{Glossary("IP address", "IP-адрес")}}, но это делается редко, поскольку запоминать IP сложнее, и это не популярно в интернете.</dd> + <dt><img alt="Port" src="https://mdn.mozillademos.org/files/8017/mdn-url-port@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>:80</code> это порт. Он отображает технический параметр, используемый для доступа к ресурсам на веб-сервере. Обычно подразумевается, что веб-сервер использует стандартные порты HTTP-протокола (80 для HTTP и 443 для HTTPS) для доступа к своим ресурсам. В любом случае, порт - это факультативная составная часть URL.</dd> + <dt><img alt="Path to the file" src="https://mdn.mozillademos.org/files/8019/mdn-url-path@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>/path/to/myfile.html</code> это адрес ресурса на веб-сервере. В прошлом, адрес отображал местоположение реального файла в реальной директории на веб-сервере. В наши дни это чаще всего абстракция, позволяющая обрабатывать адреса и отображать тот или иной контент из баз данных.</dd> + <dt><img alt="Parameters" src="https://mdn.mozillademos.org/files/8021/mdn-url-parameters@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>?key1=value1&key2=value2</code> это дополнительные параметры, которые браузер сообщает веб-серверу. Эти параметры - список пар ключ/значение, которые разделены символом <code>&</code>. Веб-сервер может использовать эти параметры для исполнения дополнительных команд перед тем как отдать ресурс. Каждый веб-сервер имеет свои собственные правила обработки этих параметров и узнать их можно, только спросив владельца сервера.</dd> + <dt><img alt="Anchor" src="https://mdn.mozillademos.org/files/8023/mdn-url-anchor@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>#SomewhereInTheDocument</code> это якорь на другую часть того же самого ресурса. Якорь представляет собой вид "закладки" внутри ресурса, которая переадресовывает браузер на "заложенную" часть ресурса. В HTML-документе, например, браузер может переместиться в точку, где установлен якорь; в видео- или аудио-документе браузер может перейти к времени, на которое ссылается якорь. Важно отметить, что часть URL после #, которая также известна как идентификатор фрагмента, никогда не посылается на сервер вместе с запросом.</dd> +</dl> + +<p>{{Note('Есть и <a href="http://en.wikipedia.org/wiki/Uniform_Resource_Locator">другие составные части и правила</a>, касающиеся URL, но обычно они не используются ни пользователями, ни разработчика. Поэтому не стоит о них беспокоиться, вам не обязательно их знать, чтобы формировать работоспособные URL.')}}</p> + +<p>Вам стоит представлять URL как обычный почтовый адрес: <em>протокол</em> обозначает почтовый транспорт, который вы собираетесь использовать,<em>доменное имя</em> - это город, <em>порт</em> - это почтовый индекс; <em>адрес</em> - это номер дома;<em>параметры</em> представляют собой дополнительную информацию, как, например, номер квартиры; и, наконец, <em>якорь</em> представляет собой конкретного получателя, которому вы адресуете своё письмо.</p> + +<h3 id="Как_использовать_URL">Как использовать URL</h3> + +<p>Каждый URL может быть напечатан напрямую в адресной строке браузера, чтобы сразу получить запрошенный ресурс. Но это только вершина айсберга!</p> + +<p>Язык {{Glossary("HTML")}} — <a href="/ru/docs/Learn/HTML/HTML_tags">который будет обсуждать позже</a> — позволяет активно использовать URL для:</p> + +<ul> + <li>создания ссылок на другие документы с помощью тега {{HTMLElement("a")}};</li> + <li>связывания документа с его дополнительными файлами, например с помощью тегов {{HTMLElement("link")}} или {{HTMLElement("script")}};</li> + <li>отображения медиа-элементов, например изображений (с помощью тега {{HTMLElement("img")}}), видео (с помощью тега {{HTMLElement("video")}}), звуков и музыки (с помощью тега {{HTMLElement("audio")}}) и так далее;</li> + <li>отображения других HTML-документов внутри текущего с помощью тега {{HTMLElement("iframe")}}.</li> +</ul> + +<div class="note"> +<p><strong>Примечание:</strong> При указании URL-адресов для загрузки ресурсов как части страницы (например, при использовании <code><script></code>, <code><audio></code>, <code><img></code>, <code><video></code>, и т.д.), следует использовать только URL-адреса HTTP и HTTPS. Использование FTP, например, не особенно безопасно и больше не поддерживается многими браузерами.</p> +</div> + +<p>Другие технологии, такие как {{Glossary("CSS")}} или {{Glossary("JavaScript")}}, также активно используют URL, так что это реально основа веба.</p> + +<h3 id="Абсолютные_и_относительные_URL">Абсолютные и относительные URL</h3> + +<p>Все, что мы изучали выше - это <em>абсолютные URL</em>. Но так же существуют и <em>относительные URL</em>. Изучим их.</p> + +<p>Обязательные части URL во многом зависят от контекста, в котором используется URL. В адресной строке браузера URL не имеет никакого контекста, так что приходится вводить полный (или <em>абсолютный</em>) URL, такие как мы рассматривали выше. Обычно вам не требуется вводить протокол (браузер подставляет HTTP по умолчанию) и порт (который нужен только в том случае, если сервер использует нестандартный порт), но остальные части URL всё равно необходимы.</p> + +<p>Когда URL используется в документе, например в HTML-странице, ситуация отличается. Потому что браузер уже знает URL текущего документа и он может использовать эти сведения для дополнения недостающих частей любого адреса, указанного в документе. Простейший пример <em>относительного</em> URL - указание только <em>адресной части</em> URL. А если адрес в URL начинается с символа <code>"/</code>", браузер запросит ресурс от корня сервера, без отсылки к контексту текущего документа.</p> + +<p>Разберем это на примерах.</p> + +<h4 id="Примеры_абсолютных_URL">Примеры абсолютных URL</h4> + +<dl> + <dt>Полный URL (такой же, как обсуждали в начале статьи)</dt> + <dd> + <pre>https://developer.mozilla.org/ru/docs/Learn</pre> + </dd> + <dt>Скрыт протокол</dt> + <dd> + <pre>//developer.mozilla.org/ru/docs/Learn</pre> + + <p>В этом случае браузер использует тот же протокол, что использовался для загрузки текущего документа.</p> + </dd> + <dt>Скрыт домен</dt> + <dd> + <pre>/ru/docs/Learn</pre> + + <p>Это наиболее частый пример использования аболютного URL в HTML-документе. Браузер использует тот же протокол и то же доменное имя, как у текущего документа. <strong>Примечание:</strong> <em>не возможно скрыть домен, не скрывая при этом протокол, только вместе</em>.</p> + </dd> +</dl> + +<h4 id="Примеры_относительных_URL">Примеры относительных URL</h4> + +<p>Для лучшего понимания следующих примеров, давайте договоримся, что мы обращаемся к URL из документа, который опубликован по адресу: <code>https://developer.mozilla.org/ru/docs/Learn</code></p> + +<dl> + <dt>Дочерние ресурсы</dt> + <dd> + <pre>Skills/Infrastructure/Understanding_URLs +</pre> + </dd> + <dd>Поскольку URL не начинается с <code>/</code>, браузер сделает попытку найти документ в поддиректории относительно текущего документа. В данном примере будет запрошен этот URL: <code>https://developer.mozilla.org/ru/docs/Learn/Skills/Infrastructure/Understanding_URLs</code></dd> + <dt>Назад по дереву папок</dt> + <dd> + <pre>../CSS/display</pre> + + <p>В этом случае, мы используем команду <code>../</code> — унаследованную из файловой системы UNIX — чтобы сказать браузеру, что он должен подняться на 1 директорию вверх. Соответственно, здесь мы хотим открыть URL: <code>https://developer.mozilla.org/ru/docs/Learn/../CSS/display</code>, который может быть упрощен до вида: <code>https://developer.mozilla.org/ru/docs/CSS/display</code></p> + </dd> +</dl> + +<h3 id="Семантические_URL">Семантические URL</h3> + +<p>Помимо своего технического значения, URL представляют собой человеко-читаемые записи о местоположении документов на веб-ресурсе. Они могут быть запомнены и любой может ввести их в адресную строку своего браузера. Веб создавался для людей и распространённой практикой является принцип записи URL, который называется <a href="http://en.wikipedia.org/wiki/Semantic_URL"><em>семантические URL</em></a>. Семантические URL используют в своём составе слова, значение которых может быть понято любым человеком, даже тем, кто не разбирается в технических нюансах.</p> + +<p>Семантика, разумеется, плохо распознаётся компьютерами. Вы наверняка видели URL, которые выглядят как куча случайных символов. Но у семантических URL есть много преимуществ:</p> + +<ul> + <li>Ими легче управлять.</li> + <li>Они дают понять пользователю, что находится по данному URL даже без перехода на страницу.</li> + <li>Поисковые системы могут использовать семантику для улучшения классификации страниц.</li> +</ul> + +<h2 id="Следующие_шаги">Следующие шаги</h2> + +<ul> + <li><a href="/ru/docs/Learn/Understanding_domain_names">Понимание доменных имен</a></li> +</ul> diff --git a/files/ru/learn/доступность/accessibility_troubleshooting/index.html b/files/ru/learn/доступность/accessibility_troubleshooting/index.html new file mode 100644 index 0000000000..d47abae869 --- /dev/null +++ b/files/ru/learn/доступность/accessibility_troubleshooting/index.html @@ -0,0 +1,101 @@ +--- +title: Устранение проблем доступности +slug: Learn/Доступность/Accessibility_troubleshooting +translation_of: Learn/Accessibility/Accessibility_troubleshooting +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/Accessibility/Mobile", "Learn/Accessibility")}}</div> + +<p class="summary">In the assessment for this module, we present to you a simple site with a number of accessibility issues that you need to diagnose and fix.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a basic understanding of HTML, CSS, and JavaScript, an understanding of the <a href="/en-US/docs/Learn/Accessibility">previous articles in the course</a>.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To test basic knowledge of accessibility fundamentals.</td> + </tr> + </tbody> +</table> + +<h2 id="Starting_point">Starting point</h2> + +<p>To get this assessment started, you should go and grab the <a href="https://github.com/mdn/learning-area/blob/master/accessibility/assessment-start/assessment-files.zip?raw=true">ZIP containing the files that comprise the example</a>. Decompress the contents into a new directory somewhere on your local computer.</p> + +<p>The finished assessment site should look like so:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14555/assessment-site-finished.png" style="border-style: solid; border-width: 1px; display: block; height: 457px; margin: 0px auto; width: 800px;"></p> + +<p>You will see some differences/issues with the display of the starting state of the assessment — this is mainly due to the differences in the markup, which in turn cause some styling issues as the CSS is not applied properly. Don't worry — you'll be fixing these problems in the upcoming sections!</p> + +<h2 id="Project_brief">Project brief</h2> + +<p>For this project, you are presented with a fictional nature site displaying a "factual" article about bears. As it stands, it has a number of accessibility issues — your task is to explore the existing site and fix them to the best of your abilities, answering the questions given below.</p> + +<h3 id="Color">Color</h3> + +<p>The text is difficult to read because of the current color scheme. Can you do a test of the current color contrast (text/background), report the results of the test, and then fix it by changing the assigned colors?</p> + +<h3 id="Semantic_HTML">Semantic HTML</h3> + +<ol> + <li>The content is still not very accessible — report on what happens when you try to navigate it using a screenreader.</li> + <li>Can you update the article text to make it easier for screenreader users to navigate?</li> + <li>The navigation menu part of the site (wrapped in <code><div class="nav"></div></code>) could be made more accessible by putting it in a proper HTML5 semantic element. Which one should it be updated to? Make the update.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: You'll need to update the CSS rule selectors that style the <font> tags to their proper equivalents for the semantic headings. Once you add paragraph elements, you'll notice the styling looking better.</font></p> +</div> + +<h3 id="The_images"><font>The images</font></h3> + +<p><font>The images are currently inaccessible to screenreader users. Can you fix this?</font></p> + +<h3 id="The_audio_player"><font>The audio player </font></h3> + +<ol> + <li><font>The <code><audio></code> player isn't accessible to hearing impaired (deaf) people — can you add some kind of accessible alternative for these users?</font></li> + <li><font>The <code><audio></code> player isn't accessible to those using older browsers that don't support HTML5 audio. How can you allow them to still access the audio?</font></li> +</ol> + +<h3 id="The_forms"><font>The forms</font></h3> + +<ol> + <li><font>The <code><input></code> element in the search form at the top could do with a label, but we don't want to add a visible text label that would potentially spoil the design and isn't really needed by sighted users. How can you add a label that is only accessible to screenreaders?</font></li> + <li><font>The two <code><input></code> elements in the comment form have visible text labels, but they are not unambiguously associated with their labels — how do you achieve this? Note that you'll need to update some of the CSS rule as well.</font></li> +</ol> + +<h3 id="The_showhide_comment_control"><font>The show/hide comment control</font></h3> + +<p><font>The show/hide comment control button is not current keyboard-accessible. Can you make it keyboard accessible, both in terms of focusing it using the tab key, and activating it using the return key?</font></p> + +<h3 id="The_table"><font>The table</font></h3> + +<p><font>The data table is not currently very accessible — it is hard for screenreader users to associate data rows and columns together, and the table also has no kind of summary to make it clear what it shows. Can you add some features to your HTML to fix this problem?</font></p> + +<h3 id="Other_considerations"><font>Other considerations?</font></h3> + +<p><font>Can you list two more ideas for improvements that would make the website more accessible?</font></p> + +<h2 id="Assessment"><font>Assessment</font></h2> + +<p><font>If you are following this assessment as part of an organized course, you should be able to give your work to your teacher/mentor for marking. If you are self-learning, then you can get the marking guide fairly easily by asking on the </font><a href="https://discourse.mozilla.org/t/accessibility-troubleshooting-assessment/24691">discussion thread for this exercise</a><font>, or in the <a href="irc://irc.mozilla.org/mdn">#mdn</a> IRC channel on <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Try the exercise first — there is nothing to be gained by cheating!</font></p> + +<p><font>{{PreviousMenu("Learn/Accessibility/Mobile", "Learn/Accessibility")}}</font></p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/Доступность/What_is_accessibility">Что такое доступность?</a></li> + <li><a href="/ru/docs/Learn/Accessibility/HTML">HTML: Хорошая основа для доступности</a></li> + <li><a href="/ru/docs/Learn/Accessibility/CSS_and_JavaScript">CSS и JavaScript доступность - лучшие практики</a></li> + <li><a href="/ru/docs/Learn/Accessibility/WAI-ARIA_basics">Основы WAI-ARIA</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Multimedia">Доступность мультимедиа</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Mobile">Мобильная доступность</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Accessibility_troubleshooting">Устранение проблем доступности</a></li> +</ul> diff --git a/files/ru/learn/доступность/css_and_javascript/index.html b/files/ru/learn/доступность/css_and_javascript/index.html new file mode 100644 index 0000000000..31ed1cb106 --- /dev/null +++ b/files/ru/learn/доступность/css_and_javascript/index.html @@ -0,0 +1,357 @@ +--- +title: CSS и JavaScript доступность - лучшие практики +slug: Learn/Доступность/CSS_and_JavaScript +tags: + - CSS + - JavaScript +translation_of: Learn/Accessibility/CSS_and_JavaScript +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Accessibility/HTML","Learn/Accessibility/WAI-ARIA_basics", "Learn/Accessibility")}}</div> + +<p class="summary">CSS и JavaScript, при правильном использовании, появляется возможность получить доступный web - опыт ... или же они могут значительно навредить доступности если не правильно используются. Это статья в общих очертаниях описывает рекомендации по использованию CSS и JavaScript , это является лучшей практикой, поэтому следует учитывать для обеспечения того, чтобы даже сложное содержание было максимально доступным</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">необходимые условия:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML, CSS, и JavaScript, и понимать (что такое доступность) <a href="/en-US/docs/Learn/Accessibility/What_is_accessibility">what accessibility is</a>.</td> + </tr> + <tr> + <th scope="row">Цели:</th> + <td>Приобрести хорошую осведомленность при использовании CSS и JavaScript в ваших web документах для максимального увелечения доступности и (not detract from it)-(привет я не понял как переводится эти слова так что помогите если понимаете).</td> + </tr> + </tbody> +</table> + +<h2 id="CSS_и_JavaScript_доступны">CSS и JavaScript доступны?</h2> + +<p>CSS и JavaScript не имеют такого же непосредственного значения для доступности как HTML, но они остаются способными для помощи или для повреждения доступности, в зависимости от того как их использовать. Другими словами, важно чтобы вы рассмотрели некоторые рекомендации для лучшей практики,чтобы убедится, что CSS JavaScript не разрушат доступность ваших документов.</p> + +<h2 id="CSS">CSS</h2> + +<p>Let's start off by looking at CSS.</p> + +<h3 id="Correct_semantics_and_user_expectation">Correct semantics and user expectation</h3> + +<p>It is possible to use CSS to make any HTML element look like <em>anything</em>, but this doesn't mean that you should. As we frequently mentioned in our <a href="/en-US/docs/Learn/Accessibility/HTML">HTML: A good basis for accessibility</a> article, you should use the appropriate semantic element for the job, whenever possible. If you don't, it can cause confusion and usability issues for everyone, but particularly users with disabilities. Using correct semantics has a lot to do with user expectations — elements look and behave in certain ways, according to their functionality, and these common conventions are expected by users.</p> + +<p>As an example, a screen reader user can't navigate a page via heading elements if the developer hasn't appropriately used heading elements to markup the content. By the same token, a heading loses its visual purpose if you style it so it doesn't look like a heading.</p> + +<p>The rule of thumb is that you can update the styling of a page feature to fit in your design, but don't change it so much that it no longer looks or behaves as expected. The following sections summarize the main HTML features to consider.</p> + +<h4 id="Standard_text_content_structure">"Standard" text content structure</h4> + +<p>Headings, paragraphs, lists — the core text content of your page:</p> + +<pre class="brush: html notranslate"><h1>Heading</h1> + +<p>Paragraph</p> + +<ul> + <li>My list</li> + <li>has two items.</li> +</ul></pre> + +<p>Some typical CSS might look like this:</p> + +<pre class="brush: css notranslate">h1 { + font-size: 5rem; +} + +p, li { + line-height: 1.5; + font-size: 1.6rem; +}</pre> + +<p>You should:</p> + +<ul> + <li>Select sensible font sizes, line heights, letter spacing, etc. to make your text logical, legible, and comfortable to read.</li> + <li>Make sure your headings stand out from your body text, typically big and bold like the default styling. Your lists should look like lists.</li> + <li>Your text color should contrast well with your background color.</li> +</ul> + +<p>See <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a> and <a href="/en-US/docs/Learn/CSS/Styling_text">Styling text</a> for more information.</p> + +<h4 id="Emphasised_text">Emphasised text</h4> + +<p>Inline markup that confers specific emphasis to the text that it wraps:</p> + +<pre class="brush: html notranslate"><p>The water is <em>very hot</em>.</p> + +<p>Water droplets collecting on surfaces is called <strong>condensation</strong>.</p></pre> + +<p>You might want to add some simple coloring to your emphasised text:</p> + +<pre class="brush: css notranslate">strong, em { + color: #a60000; +}</pre> + +<p>You will however rarely need to style emphasis elements in any significant way. The standard conventions of bold and italic text are very recognisable, and changing the style can cause confusion. For more on emphasis, see <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Emphasis_and_importance">Emphasis and importance</a>.</p> + +<h4 id="Abbreviations">Abbreviations</h4> + +<p>An element that allows an abbreviation, acronym, or initialization to be associated with its expansion:</p> + +<pre class="brush: html notranslate"><p>Web content is marked up using <abbr title="Hypertext Markup Language">HTML</abbr>.</p></pre> + +<p>Again, you might want to style it in some simple way:</p> + +<pre class="brush: css notranslate">abbr { + color: #a60000; +}</pre> + +<p>The recognised styling convention for abbreviations is a dotted underline, and it is unwise to significantly deviate from this. For more on abbreviations, see <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting#Abbreviations">Abbreviations</a>.</p> + +<h4 id="Links">Links</h4> + +<p>Hyperlinks — the way you get to new places on the web:</p> + +<pre class="brush: html notranslate"><p>Visit the <a href="https://www.mozilla.org">Mozilla homepage</a>.</p></pre> + +<p>Some very simple link styling is shown below:</p> + +<pre class="brush: css notranslate">a { + color: #ff0000; +} + +a:hover, a:visited, a:focus { + color: #a60000; + text-decoration: none; +} + +a:active { + color: #000000; + background-color: #a60000; +}</pre> + +<p>The standard link conventions are underlined and a different color (default: blue) in their standard state, another color variation when the link has previously been visited (default: purple), and yet another color when the link is activated (default: red). In addition, the mouse pointer changes to a pointer icon when links are moused over, and the link receives a highlight when focused (e.g. via tabbing) or activated. The following image shows the highlight in both Firefox (a dotted outline) and Chrome (a blue outline):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14371/focus-highlight-firefox.png" style="display: block; height: 173px; margin: 0px auto; width: 319px;"></p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14369/focus-highlight-chrome.png" style="display: block; height: 169px; margin: 0px auto; width: 309px;"></p> + +<p>You can be creative with link styles, as long as you keep giving users feedback when they interact with the links. Something should definitely happen when states change, and you shouldn't get rid of the pointer cursor or the outline — both are very important accessibility aids for those using keyboard controls.</p> + +<h4 id="Form_elements">Form elements</h4> + +<p>Elements to allow users to input data into websites:</p> + +<pre class="brush: html notranslate"><div> + <label for="name">Enter your name</label> + <input type="text" id="name" name="name"> +</div></pre> + +<p>You can see some good example CSS in our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/css/form-css.html">form-css.html</a> example (<a href="http://mdn.github.io/learning-area/accessibility/css/form-css.html">see it live</a> also).</p> + +<p>Most of the CSS you'll write for forms will be for sizing the elements, lining up labels and inputs, and getting them looking neat and tidy.</p> + +<p>You shouldn't however deviate too much from the expected visual feedback form elements receive when they are focused, which is basically the same as links (see above). You could style form focus/hover states to make this behaviour more consistent across browsers or fit in better with your page design, but don't get rid of it altogether — again, people rely on these clues to help them know what is going on.</p> + +<h4 id="Tables">Tables</h4> + +<p>Tables for presenting tabular data.</p> + +<p>You can see a good, simple example of table HTML and CSS in our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/css/table-css.html">table-css.html</a> example (<a href="http://mdn.github.io/learning-area/accessibility/css/table-css.html">see it live also</a>).</p> + +<p>Table CSS generally serves to make the table fit better into your design and look less ugly. It is a good idea to make sure the table headers stand out (normally using bold), and use zebra striping to make different rows easier to parse.</p> + +<h3 id="Color_and_color_contrast">Color and color contrast</h3> + +<p>When choosing a color scheme for your website, make sure that the text (foreground) color contrasts well with the background color. Your design might look cool, but it is no good if people with visual impairments like color blindness can't read your content.</p> + +<p>There is an easy way to check whether your contrast is large enough to not cause problems. There are a number of contrast checking tools online that you can enter your foreground and background colors into, to check them. For example WebAIM's <a href="http://webaim.org/resources/contrastchecker/">Color Contrast Checker</a> is simple to use, and provides an explanation of what you need to conform to the WCAG criteria around color contrast.</p> + +<div class="note"> +<p><strong>Note</strong>: A high contrast ratio will also allow anyone using a smartphone or tablet with a glossy screen to better read pages when in a bright environment, such as sunlight.</p> +</div> + +<p>Another tip is to not rely on color alone for signposts/information, as this will be no good for those who can't see the color. Instead of marking required form fields in red, for example, mark them with an asterisk and in red.</p> + +<h3 id="Hiding_things">Hiding things</h3> + +<p>There are many instances where a visual design will require that not all content is shown at once. For example, in our <a href="http://mdn.github.io/learning-area/css/css-layout/practical-positioning-examples/info-box.html">Tabbed info box example</a> (see <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/practical-positioning-examples/info-box.html">source code</a>) we have three panels of information, but we are <a href="/en-US/docs/Learn/CSS/CSS_layout/Positioning">positioning</a> them on top of one another and providing tabs that can be clicked to show each one (it is also keyboard accessible — you can alternatively use Tab and Enter/Return to select them).</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13368/tabbed-info-box.png" style="display: block; height: 400px; margin: 0px auto; width: 450px;"></p> + +<p>Screen reader users don't care about any of this — they are happy with the content as long as the source order makes sense, and they can get to it all. Absolute positioning (as used in this example) is generally seen as one of the best mechanisms of hiding content for visual effect, because it doesn't stop screen readers from getting to it.</p> + +<p>On the other hand, you shouldn't use {{cssxref("visibility")}}<code>:hidden</code> or {{cssxref("display")}}<code>:none</code>, because they do hide content from screen readers. Unless of course, there is a good reason why you want this content to be hidden from screen readers.</p> + +<div class="note"> +<p><strong>Note</strong>: <span class="subtitle"><a href="http://webaim.org/techniques/css/invisiblecontent/">Invisible Content Just for Screen Reader Users</a> has a lot more useful detail surrounding this topic.</span></p> +</div> + +<h3 id="Accept_that_users_can_override_styles">Accept that users can override styles</h3> + +<h4 id="Accept_that_users_can_override_your_styles">Accept that users can override your styles</h4> + +<p>It is possible for users to override your styles with their own custom styles, for example:</p> + +<ul> + <li>See Sarah Maddox's <a class="external external-icon" href="https://www.itsupportguides.com/knowledge-base/computer-accessibility/how-to-use-a-custom-style-sheet-css-with-firefox/" rel="noopener">How to use a custom style sheet (CSS) with Firefox</a> for a useful guide covering how to do this manually in Firefox, and <a href="https://www.itsupportguides.com/knowledge-base/computer-accessibility/how-to-use-a-custom-style-sheet-css-with-internet-explorer/">How to use a custom style sheet (CSS) with Internet Explorer</a> by Adrian Gordon for the equivalent <abbr>IE</abbr> instructions.</li> + <li>It is probably easier to do it using an extension, for example the Stylish extension is available for <a href="https://addons.mozilla.org/en-US/firefox/addon/stylish/">Firefox</a>, <a href="https://safari-extensions.apple.com/details/?id=com.sobolev.stylish-5555L95H45">Safari</a>, <a href="https://addons.opera.com/en/extensions/details/stylish/">Opera</a>, and <a href="https://chrome.google.com/webstore/detail/stylish/fjnbnpbmkenffdnngjfgmeleoegfcffe">Chrome</a>.</li> +</ul> + +<p>Users might do this for a variety of reasons. A visually impaired user might want to make the text bigger on all websites they visit, or a user with severe color deficiency might want to put all websites in high contrast colors that are easy for them to see. Whatever the need, you should be comfortable with this, and make your designs flexible enough so that such changes will work in your design. As an example, you might want to make sure your main content area can handle bigger text (maybe it will start to scroll to allow it all to be seen), and won't just hide it, or break completely.</p> + +<h2 id="JavaScript">JavaScript</h2> + +<p>JavaScript can also break accessibility, depending on how it is used.</p> + +<p>Modern JavaScript is a powerful language, and we can do so much with it these days, from simple content and UI updates to fully-fledged 2D and 3D games. There is no rule that says all content has to be 100% accessible to all people — you just need to do what you can, and make your apps as accessible as possible.</p> + +<p>Simple content and functionality is arguably easy to make accessible — for example text, images, tables, forms and push button that activate functions. As we looked at in our <a href="/en-US/docs/Learn/Accessibility/HTML">HTML: A good basis for accessibility</a> article, the key considerations are:</p> + +<ul> + <li>Good semantics: Using the right element for the right job. For example, making sure you use headings and paragraphs, and {{htmlelement("button")}} and {{htmlelement("a")}} elements</li> + <li>Making sure content is available as text, either directly as text content, good text labels for form elements, or <a href="/en-US/docs/Learn/Accessibility/HTML#Text_alternatives">text alternatives</a>, e.g. alt text for images.</li> +</ul> + +<p>We also looked at an example of how to use JavaScript to build in functionality where it is missing — see <a href="/en-US/docs/Learn/Accessibility/HTML#Building_keyboard_accessibility_back_in">Building keyboard accessibility back in</a>. This is not ideal — really you should just use the right element for the right job — but it shows that it is possible in situations where for some reason you can't control the markup that is used. Another way to improve accessibility for non-semantic JavaScript-powered widgets is to use WAI-ARIA to provide extra semantics for screen reader users. The next article will also cover this in detail.</p> + +<p>Complex functionality like 3D games are not so easy to make accessible — a complex 3D game created using <a href="/en-US/docs/Web/API/WebGL_API">WebGL</a> will be rendered on a {{htmlelement("canvas")}} element, which has no facility at this time to provide text alternatives or other information for severely visually impaired users to make use of. It is arguable that such a game doesn't really have this group of people as a part of its main target audience, and it would be unreasonable to expect you to make it 100% accessible to blind people, however you could implement <a href="/en-US/docs/Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard">keyboard controls</a> so it is usable by non-mouse users, and make the color scheme contrasting enough to be usable by those with color deficiencies.</p> + +<h3 id="The_problem_with_too_much_JavaScript">The problem with too much JavaScript</h3> + +<p>The problem often comes when people rely on JavaScript too much. Sometimes you'll see a website where everything has been done with JavaScript — the HTML has been generated by JavaScript, the CSS has been generated by JavaScript, etc. This has all kinds of accessibility and other issues associated with it, so it is not advised.</p> + +<p>As well as using the right element for the right job, you should also make sure you are using the right technology for the right job! Think carefully about whether you need that shiny JavaScript-powered 3D information box, or whether plain old text would do. Think carefully about whether you need a complex non-standard form widget, or whether a text input would do. And don't generate all your HTML content using JavaScript if at all possible.</p> + +<h3 id="Keeping_it_unobtrusive">Keeping it unobtrusive</h3> + +<p>You should keep <strong>unobtrusive JavaScript</strong> in mind when creating your content. The idea of unobtrusive JavaScript is that it should be used wherever possible to enhance functionality, not build it in entirely — basic functions should ideally work without JavaScript, although it is appreciated that this is not always an option. But again, a large part of it is using built-in browser functionality where possible.</p> + +<p>Good example uses of unobtrusive JavaScript include:</p> + +<ul> + <li>Providing client-side form validation, which alerts users to problems with their form entries quickly, without having to wait for the server to check the data. If it isn't available, the form will still work, but validation might be slower.</li> + <li>Providing custom controls for HTML5 <code><video></code>s that are accessible to keyboard-only users, along with a direct link to the video that can be used to access it if JavaScript is not available (the default <code><video></code> browser controls aren't keyboard accessible in most browsers).</li> +</ul> + +<p id="Client-side_form_validation">As an example, we've written a quick and dirty client-side form validation example — see <a href="https://github.com/mdn/learning-area/blob/master/accessibility/css/form-validation.html">form-validation.html</a> (also <a href="http://mdn.github.io/learning-area/accessibility/css/form-validation.html">see the demo live</a>). Here you'll see a simple form; when you try to submit the form with one or both fields left empty, the submit fails, and an error message box appears to tell you what is wrong.</p> + +<p>This kind of form validation is unobtrusive — you can still use the form absolutely fine without the JavaScript being available, and any sensible form implementation will have server-side validation active as well, because it is too easy for malicious users to bypass client-side validation (for example, by turning JavaScript off in the browser). The client-side validation is still really useful for reporting errors — users can know about mistakes they make instantly, rather than having to wait for a round trip to the server and a page reload. This is a definite usability advantage.</p> + +<div class="note"> +<p><strong>Note</strong>: Server-side validation has not been implemented in this simple demo.</p> +</div> + +<p>We've made this form validation pretty accessible too. We've used {{htmlelement("label")}} elements to make sure the form labels are unambiguously linked to their inputs, so screen readers can read them out alongside:</p> + +<pre class="brush: html notranslate"><label for="name">Enter your name:</label> +<input type="text" name="name" id="name"></pre> + +<p>We only do the validation when the form is submitted — this is so that we don't update the UI too often and potentially confuse screen reader (and possibly other) users:</p> + +<pre class="brush: js notranslate">form.onsubmit = validate; + +function validate(e) { + errorList.innerHTML = ''; + for(var i = 0; i < formItems.length; i++) { + var testItem = formItems[i]; + if(testItem.input.value === '') { + errorField.style.left = '360px'; + createLink(testItem); + } + } + + if(errorList.innerHTML !== '') { + e.preventDefault(); + } +}</pre> + +<div class="note"> +<p><strong>Note</strong>: In this example, we are hiding and showing the error message box using absolute positioning rather than another method such as visibility or display, because it doesn't interfere with the screen reader being able to read content from it.</p> +</div> + +<p>Real form validation would be much more complex than this — you'd want to check that the entered name actually looks like a name, the entered age is actually a number and is realistic (e.g. not a minus number, or four digits). Here we've just implemented a simple check that a value has been filled in to each input field (<code>if(testItem.input.value === '')</code>).</p> + +<p>When the validation has been performed, if the tests pass then the form is submitted. If there are errors (<code>if(errorList.innerHTML !== '')</code>) then we stop the form submitting (using <code><a href="/en-US/docs/Web/API/Event/preventDefault">preventDefault()</a></code>), and display any error messages that have been created (see below). This mechanism means that the errors will only be shown if there are errors, which is better for usability.</p> + +<p>For each input that doesn't have a value filled in when the form is submitted, we create a list item with a link and insert it in the <code>errorList</code>.</p> + +<pre class="brush: js notranslate">function createLink(testItem) { + var listItem = document.createElement('li'); + var anchor = document.createElement('a'); + anchor.textContent = testItem.input.name + ' field is empty: fill in your ' + testItem.input.name + '.'; + anchor.href = '#' + testItem.input.name; + anchor.onclick = function() { + testItem.input.focus(); + }; + listItem.appendChild(anchor); + errorList.appendChild(listItem); +}</pre> + +<p>Each link serves a dual purpose — it tells you what the error is, plus you can click on it/activate it to jump straight to the input element in question and correct your entry.</p> + +<div class="note"> +<p><strong>Note</strong>: The <code>focus()</code> part of this example is a bit tricky. Chrome and Edge (and newer versions of IE) will focus the element when the link is clicked, without needing the <code>onclick</code>/<code>focus()</code> block. Safari will only highlight the form element with the link on its own, so needs the <code>onclick</code>/<code>focus()</code> block to actually focus it. Firefox doesn't focus the inputs properly at all in this context, so Firefox users can't take advantage of this at present (although everything else works fine). The Firefox issue should be fixed soon — work is being done to give Firefox behaviour parity with other browsers (see {{bug(277178)}}).</p> +</div> + +<p>In addition, the <code>errorField</code> is placed at the top of the source order (although it is positioned differently in the UI using CSS), meaning that users can find out exactly what's wrong with their form submissions and get to the input elements in question by going back up to the start of the page.</p> + +<p>As a final note, we have used some WAI-ARIA attributes in our demo to help solve accessibility problems caused by areas of content constantly updating without a page reload (screen readers won't pick this up or alert users to it by default):</p> + +<pre class="notranslate"><div class="errors" role="alert" aria-relevant="all"> + <ul> + </ul> +</div></pre> + +<p>We will explain these attributes in our next article, which covers <a href="/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA</a> in much more detail.</p> + +<div class="note"> +<p><strong>Note</strong>: Some of you will probably be thinking about that fact that HTML5 forms have built-in validation mechanisms like the <code>required</code>, <code>min</code>/<code>minlength</code>, and <code>max</code>/<code>maxlength</code> attributes (see the {{htmlelement("input")}} element reference for more information). We didn't end up using these in the demo because cross-browser support for them is patchy (for example IE10 and above only, no Safari support).</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: WebAIM's <a href="http://webaim.org/techniques/formvalidation/">Usable and Accessible Form Validation and Error Recovery</a> provides some further useful information about accessible form validation.</p> +</div> + +<h3 id="Other_JavaScript_accessibility_concerns">Other JavaScript accessibility concerns</h3> + +<p>There are other things to be aware of when implementing JavaScript and thinking about accessibility. We will add more as we find them.</p> + +<h4 id="mouse-specific_events">mouse-specific events</h4> + +<p>As you will be aware, most user interactions are implemented in client-side JavaScript using event handlers, which allow us to run functions in response to certain events happening. Some events can have accessibility issues. The main example you'll come across is mouse-specific events like <a href="/en-US/docs/Web/Events/mouseover">mouseover</a>, <a href="/en-US/docs/Web/Events/mouseout">mouseout</a>, <a href="/en-US/docs/Web/Events/dblclick">dblclick</a>, etc. Functionality that runs in response to these events will not be accessible using other mechanisms, like keyboard controls.</p> + +<p>To mitigate such problems, you should double up these events with similar events that can be activated by other means (so-called device-independent event handlers) — <a href="/en-US/docs/Web/Events/focus">focus</a> and <a href="/en-US/docs/Web/Events/blur">blur</a> would provide accessibility for keyboard users.</p> + +<p>Let's look at an example that highlights when this could be useful. Maybe we want to provide a thumbnail image that shows a larger version of the image when it is moused over or focused (like you'd see on an e-commerce product catalog.)</p> + +<p>We've made a very simple example, which you can find at <a href="http://mdn.github.io/learning-area/accessibility/css/mouse-and-keyboard-events.html">mouse-and-keyboard-events.html</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/accessibility/css/mouse-and-keyboard-events.html">source code</a>). The code features two functions that show and hide the zoomed-in image; these are run by the following lines that set them as event handlers:</p> + +<pre class="brush: js notranslate">imgThumb.onmouseover = showImg; +imgThumb.onmouseout = hideImg; + +imgThumb.onfocus = showImg; +imgThumb.onblur = hideImg;</pre> + +<p>The first two lines run the functions when the mouse pointer hovers over and stops hovering over the thumbnail, respectively. This won't allow us to access the zoomed view by keyboard though — to allow that, we've included the last two lines, which run the functions when the image is focused and blurred (when focus stops). This can be done by tabbing over the image, because we've included <code>tabindex="0"</code> on it.</p> + +<p>The <a href="/en-US/docs/Web/Events/click">click</a> event is interesting — it sounds mouse-dependent, but most browsers will activate <a href="/en-US/docs/Web/API/GlobalEventHandlers/onclick">onclick</a> event handlers after Enter/Return is pressed on a link or form element that has focus, or when such an element is tapped on a touchscreen device. This doesn't work by default however when you allow a non-default-focusable event to have focus using tabindex — in such cases you need to detect specifically when that exact key is pressed (see <a href="/en-US/docs/Learn/Accessibility/HTML#Building_keyboard_accessibility_back_in">Building keyboard accessibility back in</a>).</p> + +<h2 id="Summary">Summary</h2> + +<p>We hope this article has given you a good amount of detail and understanding about the accessibility issues surrounding CSS and JavaScript use on web pages.</p> + +<p>Next up, WAI-ARIA!</p> + +<div>{{PreviousMenuNext("Learn/Accessibility/HTML","Learn/Accessibility/WAI-ARIA_basics", "Learn/Accessibility")}}</div> + +<div> +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/Доступность/What_is_accessibility">Что такое доступность?</a></li> + <li><a href="/ru/docs/Learn/Accessibility/HTML">HTML: Хорошая основа для доступности</a></li> + <li><a href="/ru/docs/Learn/Accessibility/CSS_and_JavaScript">CSS и JavaScript доступность - лучшие практики</a></li> + <li><a href="/ru/docs/Learn/Accessibility/WAI-ARIA_basics">Основы WAI-ARIA</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Multimedia">Доступность мультимедиа</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Mobile">Мобильная доступность</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Accessibility_troubleshooting">Устранение проблем доступности</a></li> +</ul> +</div> diff --git a/files/ru/learn/доступность/html/index.html b/files/ru/learn/доступность/html/index.html new file mode 100644 index 0000000000..64c19fd4d6 --- /dev/null +++ b/files/ru/learn/доступность/html/index.html @@ -0,0 +1,537 @@ +--- +title: 'HTML: Хорошая основа для доступности' +slug: Learn/Доступность/HTML +tags: + - HTML + - a11y + - Клавиатура + - Кнопки + - Начинающий + - Семантика + - Ссылки + - Формы + - вспомагательные технологии + - доступность +translation_of: Learn/Accessibility/HTML +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Accessibility/What_is_Accessibility","Learn/Accessibility/CSS_and_JavaScript", "Learn/Accessibility")}}</div> + +<p class="summary">Большая часть содержимого интернета может быть сделана доступной просто благодаря использованию правильных HTML элементов по назначению. В этой статье подробно рассмотрено как HTML может быть использован для обеспечения максимальной доступности.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML (смотрите <a href="/ru/docs/Learn/HTML/Введение_в_HTML">Введение в HTML</a>), и понимания, <a href="/ru/docs/Learn/Доступность/What_is_accessibility">что такое доступность</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Познакомиться с тем, какие особенности HTML способствуют доступности, и как использовать их на ваших веб-страницах должным образом.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="HTML_и_доступность">HTML и доступность</h2> + +<p>По мере изучения HTML: чтения статей, просмотра примеров и т.д., вы заметите одну общую тему — важность использования семантического HTML (иногда называемого POSH (Plain Old Semantic HTML), или «старый добрый семантический HTML»). Это означает использование HTML элементов по назначению насколько это возможно.</p> + +<p>Вы спросите, почему это так важно? В конце концов, можно использовать комбинацию CSS и JavaScript, чтобы заставить почти любой HTML элемент вести себя так, как вы захотите. Например, кнопка для воспроизведения видео на вашем сайте может быть обозначена вот так:</p> + +<pre class="brush: html"><div>Воспроизвести видео</div></pre> + +<p>Но, как вы увидите далее, в данном случае намного логичнее использовать правильный элемент:</p> + +<pre class="brush: html"><button>Воспроизвести видео</button></pre> + +<p>HTML элементы <code><button></code> не только имеют соответствующие кнопке стили по-умолчанию (которые вы скорее всего захотите переписать), они также имеют встроенную доступность с клавиатуры: между ними можно передвигаться с помощью кнопки <kbd>Tab</kbd> и активировать, используя <kbd>Enter</kbd>.</p> + +<p>Вёрстка с помощью семантического HTML не займёт больше времени, чем с помощью не семантического (плохого) HTML, если делать это последовательно с самого начала проекта, и это также имеет другие преимущества помимо доступности:</p> + +<ol> + <li><strong>Легче разрабатывать</strong> — как сказано выше, вы получаете функционал «из коробки», плюс проще для восприятия.</li> + <li><strong>Лучше для мобильных</strong> — семантический HTML легче по размеру, чем не семантический спаггети-код, и его легче сделать адаптивным.</li> + <li><strong>Хорошо для SEO</strong> — поисковики уделяют больше внимания ключевым словам внутри заголовков, ссылок и т.д., чем ключевым словам, помещённым в не семантический <code><div></code> и т.д., поэтому клиентам будет проще найти ваш сайт.</li> +</ol> + +<p>Давайте рассмотрим доступный HTML более детально.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Желательно, чтобы у вас был установлен скринридер, чтобы вы могли тестировать примеры, приведённые ниже. Посмотрите наше <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">Руководство по скринридерам</a> для более подробной информации.</p> +</div> + +<h2 id="Хорошая_семантика">Хорошая семантика</h2> + +<p>Мы уже говорили о важности хорошей семантики, и почему нам стоит использовать HTML элементы по назначению. Это нельзя игнорировать, поскольку это одно из основных мест, где ломается доступность из-за плохой семантики, если должным образом не уделять внимания.</p> + +<p>В интернете люди делают очень странные вещи с HTML разметкой. Некоторые злоупотребляют HTML, используя устаревшие практики, которые не были полностью забыты, а некоторые просто не знают. В любом случае, вам стоит заменить по возможности плохой код, где бы вы его не увидели.</p> + +<p>У вас не всегда есть возможность избавиться от плохой вёрстки: ваши страницы могут быть сгенерированы каким-нибудь фреймворком на стороне сервера, над которым у вас нет полного контроля, или на страницах есть сторонний контент (такой как рекламные баннеры), которые вы также не контролируете.</p> + +<p>Цель не «всё или ничего», однако — каждое улучшение, которое вам под силу сделать, поможет обеспечить доступность.</p> + +<h3 id="Текстовый_контент">Текстовый контент</h3> + +<p>Одно из самых лучших вспомогательных средств доступности для пользователя скринридера — хорошая структура заголовков, параграфов, список и т.д. Пример хорошей семантики может выглядеть так:</p> + +<pre class="brush: html example-good line-numbers language-html"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>h1</span><span class="punctuation token">></span></span>Мой заголовок<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>h1</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">>Это первый раздел моей страницы.</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">>Я добавлю ещё один параграф тут.</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">> + +<ol> + <li>Это</li> + <li>список для</li> + <li>чтения</li> +</ol></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>h2</span><span class="punctuation token">></span></span>Мой подзаголовок<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>h2</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>Это первый подраздел моей страницы. Я бы хотела, чтобы люди могли найти этот контент!<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>h2</span><span class="punctuation token">>Мой второй подзаголовок</</span></span><span class="tag token"><span class="tag token">h2</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>Это второй подраздел. Думаю, он намного интереснее, чем предыдущий.<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span></code></pre> + +<p>Мы подготовили версию с длинными текстом, чтобы вы попробовали со скринридером (смотрите <a href="http://mdn.github.io/learning-area/accessibility/html/good-semantics.html">good-semantics.html</a>). Если вы попробуете поперемещаться, то увидите, как легко ориентироваться на странице:</p> + +<ol> + <li>Скринридер озвучивает каждый заголовок по мере перемещения, оповещая вас, что является заголовком, а что параграфом. </li> + <li>Он останавливается после каждого элемента, позволяя вам переместиться в любое другое место, которое вам надо.</li> + <li>Во многих скринридерах Вы можете перемещаться к следующему/предыдущему заголовкам.</li> + <li>Во многих скринридерах Вы также можете вызвать список всех заголовков, который можно использовать как содержание, чтобы найти определённую информацию. </li> +</ol> + +<p>Иногда люди используют презентационные элементы HTML и перенос строки, чтобы написать заголовки или параграфы:</p> + +<pre class="brush: html example-bad line-numbers language-html"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>font</span> <span class="attr-name token">size</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>7<span class="punctuation token">"</span></span><span class="punctuation token">>Мой заголовок</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>font</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="punctuation token">Это первый раздел моей страницы.</span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="punctuation token">Я добавлю ещё один параграф тут.</span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">> +1. Это +</span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">> +2. список для +</span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">> +3. чтения +</span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>font</span> <span class="attr-name token">size</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>5<span class="punctuation token">"</span></span><span class="punctuation token">>Мой подзаголовок</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>font</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +Это первый подраздел моей страницы. Я бы хотела, чтобы люди могли найти этот контент! +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>font</span> <span class="attr-name token">size</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>5<span class="punctuation token">"</span></span><span class="punctuation token">>Мой второй подзаголовок</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>font</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +Это второй подраздел. Думаю, он намного интереснее, чем предыдущий.</code></pre> + +<p>Если вы попробуете полную версию с помощью скринридера (смотрите <a href="http://mdn.github.io/learning-area/accessibility/html/bad-semantics.html">bad-semantics.html</a>), вам не слишком это понравится: скринридеру нечего использовать как ориентир, поэтому вы не сможете получить содержание, а вся страница для скринридера — это один большой блок, поэтому он озвучит всё за один раз, без остановок. </p> + +<p>Есть и другие проблемы, помимо доступности — сложнее стилизовать контент, используя CSS, или манипулировать им с помощью JavaScript, например, потому что там нет элементов, которые можно использовать как селекторы.</p> + +<h4 id="Использование_понятного_языка">Использование понятного языка</h4> + +<p>Язык, который вы используете, также может влиять на доступность. В целом, лучше использовать понятный язык, который не слишком сложный, и который не использует ненужные жаргоны и сленг. Это помогает не только людям с когнитивными или другими нарушениями, но и читателям, для которых текст написан не на родном языке, молодым людям... на самом деле всем! Кроме этого, стоит избегать использование языка и символов, которые не могут быть чётко озвучено скринридером. Например:</p> + +<ul> + <li>Не используйте тире, если можете избежать этого. Вместо «5-7», напишите «от 5 до 7».</li> + <li>Не пишите сокращения: вместо «Янв» пишите «Январь».</li> + <li>Расшифровывайте аббревиатуры, как минимум один или два раза. Вместо «HTML» при первом употреблении, пишите «Hypertext Markup Language».</li> +</ul> + +<h3 id="Вёрстка">Вёрстка</h3> + +<p>В старые недобрые времена, люди верстали с помощью HTML-таблиц: использовали различные табличные ячейки для размещения шапки, подвала, боковую панель, колонку с основным контентом и т.д. Это плохая идея, потому что скринридер, скорее всего, выдаст непонятную озвучку, особенно, если раскладка сложная и имеет много вложенных таблиц.</p> + +<p>Посмотрите пример табличной вёрстки, открыв <a href="http://mdn.github.io/learning-area/accessibility/html/table-layout.html">table-layout.html</a>, которая выглядит примерно так:</p> + +<pre class="brush: html"><table width="1200"> + <!-- main heading row --> + <tr id="heading"> + <td colspan="6"> + + <h1 align="center">Шапка</h1> + + </td> + </tr> + <!-- nav menu row --> + <tr id="nav" bgcolor="#ffffff"> + <td width="200"> + <a href="#" align="center">Главная</a> + </td> + <td width="200"> + <a href="#" align="center">Наша команда</a> + </td> + <td width="200"> + <a href="#" align="center">Проекты</a> + </td> + <td width="200"> + <a href="#" align="center">Контакты</a> + </td> + <td width="300"> + <form width="300"> + <input type="search" name="q" placeholder="Поиск" width="300"> + </form> + </td> + <td width="100"> + <button width="100">Вперёд!</button> + </td> + </tr> + <!-- spacer row --> + <tr id="spacer" height="10"> + <td> + + </td> + </tr> + <!-- main content and aside row --> + <tr id="main"> + <td id="content" colspan="4" bgcolor="#ffffff"> + + <!-- основной контент --> + </td> + <td id="aside" colspan="2" bgcolor="#ff80ff" valign="top"> + <h2>Связанный контент</h2> + + <!-- второстепенный контент --> + + </td> + </tr> + <!-- spacer row --> + <tr id="spacer" height="10"> + <td> + + </td> + </tr> + <!-- footer row --> + <tr id="footer" bgcolor="#ffffff"> + <td colspan="6"> + <p>© 2050 никто. Все права защищены.</p> + </td> + </tr> + </table></pre> + +<p>Если вы попробуете поперемещаться с помощью скринридера, вероятно, он скажет вам, что перед вами таблица (хотя некоторые скринридеры могу различать табличную вёрстку от таблиц данных). После этого, скорее всего (в зависимости от того, какой скринридер вы используете), вам придётся переместиться в таблицу как в объект, посмотрев каждый элемент по отдельности, затем выйти из таблицы, чтобы продолжить перемещение по контенту.</p> + +<p>Табличная вёрстка — пережиток прошлого, который имел смысл, когда поддержка CSS не была сильно распространена среди браузеров, но она создаёт путаницу среди пользователей скринридеров, и плоха по многим другим причинам (злоупотребление таблицами, пожалуй, требует больше разметки, делает дизайн менее гибким). Не делайте так!</p> + +<p>Вы можете проверить эти утверждения, сравнив предыдущий опыт с <a href="http://mdn.github.io/learning-area/html/introduction-to-html/document_and_website_structure/">более современной структурой веб-сайта</a>, которая выглядит так:</p> + +<pre class="brush: html"><header> + <h1>Шапка</h1> +</header> + +<nav> + <!-- основная навигация --> +</nav> + +<!-- Основной контент нашей страницы --> +<main> + + <!-- На ней есть статьи --> + <article> + <h2>Заголовок статьи</h2> + + <!-- сама статья --> + </article> + + <aside> + <h2>Связанный контент</h2> + + <!-- второстепенный контент --> + </aside> + +</main> + +<!-- А здесь наш основной подвал, который используется на всех страницах нашего сайта --> + +<footer> + <!-- здесь содержимое подвала --> +</footer></pre> + +<p>Если вы попробуете нашу более современную структуру с помощью скринридера, вы увидите, что разметка больше не сбивает с толку скринридер. Она также более компактная с точки зрения размера кода, что означает, его легче поддерживать, а пользователям меньше скачивать (особенно для тех, у кого медленный интенет).</p> + +<p>На что ещё стоит обратить внимание при вёрстке — это использование семантических HTML5 элементов, которые можно увидеть в примере выше (смотрите <a href="/ru/docs/Web/HTML/Element#Секционирование_содержания">секционирование содержания)</a>: вы можно верстать, используя только вложенные {{htmlelement("div")}} элементы, но лучше использовать соответствующие секционные элементы, чтобы обернуть вашу основную навигацию ({{htmlelement("nav")}}), футер ({{htmlelement("footer")}}), повторяющийся контент ({{htmlelement("article")}}) и т.д. Эти элементы предоставляют дополнительную семантику для скринридеров (и других инструментов), чтобы давать пользователю дополнительную информацию о контенте, по которому они перемещаются (смотрите статью <a href="http://www.weba11y.com/blog/2016/04/22/screen-reader-support-for-new-html5-section-elements/">Screen Reader Support for new HTML5 Section Elements</a> для представления поддержки этих элементов с помощью скринридеров).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Помимо того, что ваш контент имеет семантическую и красивую разметку, он должен иметь логический порядок в его исходном коде — позже вы всегда можете разместить элементы там, где хотите, с помощью CSS, но располагать элементы в правильном порядке нужно в самом начале, чтобы то, что зачитывает пользователям скринридер, имело смысл.</p> +</div> + +<h3 id="Элементы_интерфейса">Элементы интерфейса</h3> + +<p>Под элементами интерфейса мы подразумеваем основные элементы веб-страниц, с которыми взаимодействует пользователь, в основном это кнопки, ссылки и элементы форм. В этом разделе мы рассмотрим основные проблемы доступности, которые стоит учитывать при создании таких элементов. В следующих статьях про WAI-ARIA и мультимедиа мы рассмотрим другие аспекты доступности пользовательского интерфейса.</p> + +<p>Одним из ключевых аспектов доступуности элементов интерфейса является то, что браузеры по-умолчанию позволяют управлять ими с помощью клавиатуры. Вы можете проверить это, открыв в новой вкладке <a href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/accessibility/native-keyboard-accessibility.html">native-keyboard-accessibility.html </a>(смотрите <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/accessibility/native-keyboard-accessibility.html">исходный код</a>). Попробуйте понажимать клавишу <kbd>Tab</kbd>, после нескольких нажатий вы заметите, что фокус перемещается по всем фокусируемым элементам. Сфокусированные элеметы подсвечиваются браузерными стилями по-умолчанию (в зависимости от браузера они немного разные), чтобы можно было понять, какой элемент в фокусе.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14215/button-focused-unfocused.png" style="border-style: solid; border-width: 1px; display: block; height: 39px; margin: 0px auto; width: 288px;"></p> + +<p>Вы можете нажать <kbd>Enter</kbd>, чтобы перейти по сфокусированной ссылке или нажать кнопку (мы добавили немного JavaScript, чтобы кнопки выводили окно с сообщением), или начать печатать в текстовом поле (другие элементы формы имеют разное управление, например, у элемента {{htmlelement("select")}} можно отобразить опции и переключаться между ними, используя клавиши-стрелки вверх и вниз).</p> + +<div class="note"> +<p><strong>Примечание</strong>: Различные браузеры могут иметь разное управление с клавиатуры. Для более подробной информации смотрите <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Using_native_keyboard_accessibility">Using native keyboard accessibility.</a></p> +</div> + +<p>Такое поведение вы получаете сразу по-умолчанию, просто используя правильные элементы, например:</p> + +<pre class="brush: html example-good"><h1>Ссылки</h1> + +<p>Это ссылка ведёт на сайт <a href="https://www.mozilla.org">Mozilla</a>.</p> + +<p>Другая ссылка на <a href="https://developer.mozilla.org">Mozilla Developer Network</a>.</p> + +<h2>Кнопки</h2> + +<p> + <button data-message="Это из первой кнопки">Нажми меня!</button> + <button data-message="Это из второй кнопки">Меня тоже нажми!</button> + <button data-message="Это из третьей кнопки">И меня!</button> +</p> + +<h2>Форма</h2> + +<form> + <div> + <label for="name">Укажите ваше имя:</label> + <input type="text" id="name" name="name"> + </div> + <div> + <label for="age">Укажите ваш возраст:</label> + <input type="text" id="age" name="age"> + </div> + <div> + <label for="mood">Выберите ваше настроение:</label> + <select id="mood" name="mood"> + <option>Счастливый</option> + <option>Грустный</option> + <option>Злой</option> + <option>Обеспокоенный</option> + </select> + </div> +</form></pre> + +<p>Это предполагает использование соответствующим образом ссылок, кнопок, элементов форм и меток (включая элемент {{htmlelement("label")}} для элементов форм).</p> + +<p>Однако, опять же, люди иногда делают странные вещи с HTML. Например, иногда вы видите кнопки, размеченные с помощью элемента {{htmlelement("div")}}:</p> + +<pre class="brush: html example-bad"><div data-message="Это из первой кнопки">Нажми меня!</div> +<div data-message="Это из второй кнопки">Меня тоже нажми!</div> +<div data-message="Это из третьей кнопки">И меня!</div></pre> + +<p>Такой код не советуется использовать: вы сразу же теряете нативную доступность с клавиатуры, которая у вас была бы, если просто использовать элемент {{htmlelement("button")}}, к тому же {{htmlelement("div")}} по-умолчанию не имеет кнопочных стилей.</p> + +<h4 id="Добавление_доступности_с_клавиатуры">Добавление доступности с клавиатуры</h4> + +<p>Для добавления доступности с клавиатуры несоответствующим элементам придётся немного поработать (вы можете посмотреть пример, открыв <a class="external external-icon" href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/accessibility/fake-div-buttons.html">fake-div-buttons.html</a>, а также <a class="external external-icon" href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/accessibility/fake-div-buttons.html">исходный код</a>). Мы дали нашим поддельным <code><div></code>-кнопкам возможность фокусироваться (в том числе через <kbd>Tab</kbd>), указав аттрибут <code>tabindex="0"</code>:</p> + +<pre class="brush: html"><div data-message="Это из первой кнопки" tabindex="0">Кликни меня!</div> +<div data-message="Это из второй кнопки" tabindex="0">Меня тоже кликни!</div> +<div data-message="Это из третьей кнопки" tabindex="0">И меня!</div></pre> + +<p>Аттрибут {{htmlattrxref("tabindex")}} в первую очередь предназначен для того, чтобы менять порядок фокусируемых элементов в последовательной навигации (указанный в виде положительного целого числа). Это почти всегда — плохая идея, которая может вызвать большую путаницу. Используйте его, если он правда необходим, например, если визуальный порядок сильно отличается от исходного, и вы хотите более логичную последовательную навигацию. Есть два варианта значений <code>tabindex</code>:</p> + +<ul> + <li><code>tabindex="0"</code> — как указано выше, это значение позовляет элементу быть выделеным и достигнутым с помощью последовательной навигации. Это самое полезное значение <code>tabindex</code>.</li> + <li><code>tabindex="-1"</code> — позволяет элементам, которые обычно не принимают фокусное выделение, получать его программно, например, с помощью JavaScript, или как цель якорной ссылки.</li> +</ul> + +<p>Хотя дополнение, которые мы сделали, позволяет нам перемещаться по кнопкам с помощью <kbd>Tab</kbd>, оно не позволяет нам активировать их кнопкой <kbd>Enter</kbd>. Для этого нам необходимо добавить хитрый кусочек JavaScript:</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js">document<span class="punctuation token">.</span>onkeydown <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>e<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span><span class="punctuation token">(</span>e<span class="punctuation token">.</span>keyCode <span class="operator token">===</span> <span class="number token">13</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="comment token">// Кнопка Enter</span> + document<span class="punctuation token">.</span>activeElement<span class="punctuation token">.</span><span class="function token">click</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> +<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre> + +<p>Мы навешиваем обработчик событий на <code>document</code> для обнаружения нажатий с клавиатуры. Далее, через свойство объекта события <code><a href="/ru/docs/Web/API/KeyboardEvent/keyCode">keyCode</a></code>, проверяем, какая кнопка была нажата. Если код клавиши совпадает с кодом клавиши <kbd>Enter</kbd>, мы выполняем функцию, которая хранится в обработчике кнопки <code>onclick</code>, используя <code>document.activeElement.click().</code> <code><a href="/ru/docs/Web/API/Document/activeElement">activeElement</a></code> возвращает текущий сфокусированный элемент.</p> + +<p>Слишком много дополнительной мороки с добавлением такой функциональности. И обязательно будут ещё проблемы. <strong>Лучше просто сразу использовать правильные элементы по назначению.</strong></p> + +<h4 id="Содержательные_текстовые_метки">Содержательные текстовые метки</h4> + +<p>Текстовые метки (описания) для элементов интерфейса полезны всем пользователям, но их правильное описание — особенно важно для пользователей с ограниченными способностями.</p> + +<p>Вы должны следить за тем, чтобы кнопки и ссылки имели понятные и уникальные текстовые описания. Не используйте фразу «Кликните здесь», потому что пользователи скринридеров иногда вызывают список кнопок и элементов форм. В примере ниже можно увидеть такой список, вызванный из VoiceOver на Mac.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14335/voiceover-formcontrols.png" style="display: block; height: 604px; margin: 0px auto; width: 802px;"></p> + +<p>Удостоверьтесь, что описания вне контекста имеют смысл, так же как и в контексте параграфа, в котором они содержаться. Например, вот хороший текст для ссылки:</p> + +<pre class="brush: html example-good"><p>Киты очень классные существа. <a href="whales.html">Узнай больше о китах</a>.</p></pre> + +<p>а это плохой текст для ссылки:</p> + +<pre class="brush: html example-bad"><p>Киты очень классные существа. Чтобы узнать больше о китах, <a href="whales.html">нажмите здесь</a>.</p></pre> + +<div class="note"> +<p><strong>Примечание: </strong>Более подробно о создании ссылок и лучших практиках можно почитать в статье «<a href="/ru/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Создание ссылок</a>». Также посмотреть на примеры хороших и плохих ссылок можно на <a class="external external-icon" href="http://mdn.github.io/learning-area/accessibility/html/good-links.html">good-links.html</a> и <a class="external external-icon" href="http://mdn.github.io/learning-area/accessibility/html/bad-links.html">bad-links.html</a>. </p> +</div> + +<p>Описания форм также важны для понимания, что нужно вводить в каждое текстовое поле. Следующий пример кажется достаточно разумным:</p> + +<pre class="brush: html example-bad">Укажите ваше имя: <input type="text" id="name" name="name"></pre> + +<p>Однако, это не совсем удобно для пользователей с ограниченными возможностями. В примере нет ничего, что могло бы однозначно связать описание текстового поля с самим текстовым полем, и чётко указать, как его заполнить, если вы не можете видеть. Если бы вы воспользовались скринридером, скорее всего он озвучил описание примерно как «редактировать текст».</p> + +<p>Следующий пример намного лучше:</p> + +<pre class="brush: html example-good"><div> + <label for="name">Укажите ваше имя:</label> + <input type="text" id="name" name="name"> +</div></pre> + +<p>С такой разметкой описание будет явно связано с текстовым полем, и будет звучать как «Укажите ваше имя: редактировать текст».</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14337/voiceover-good-form-label.png" style="display: block; margin: 0 auto;"></p> + +<p>Как бонус, в большинстве браузеров привязка описания к полю ввода означает, что вы можете щелкнуть по описанию, чтобы выбрать/активировать элемент формы. Это облегчает нажатие на элемент формы из-за увеличенной зоны нажатия.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Посмотреть на хорошие и плохие пример форм можно на <a href="http://mdn.github.io/learning-area/accessibility/html/good-form.html">good-form.html</a> и <a href="http://mdn.github.io/learning-area/accessibility/html/bad-form.html">bad-form.html</a>.</p> +</div> + +<h2 id="Доступные_таблицы">Доступные таблицы</h2> + +<p>Обычные таблицы с данными можно сверстать очень простой разметкой, например:</p> + +<pre class="brush: html"><table> + <tr> + <td>Имя</td> + <td>Возраст</td> + <td>Пол</td> + </tr> + <tr> + <td>Гавриил</td> + <td>13</td> + <td>Мужской</td> + </tr> + <tr> + <td>Эвелина</td> + <td>8</td> + <td>Женский</td> + </tr> + <tr> + <td>Фрида</td> + <td>5</td> + <td>Женский</td> + </tr> +</table></pre> + +<p>Но есть проблемы — пользователи скринридера никак не смогут связать вместе строки или столбцы в группу данных. Чтобы это сделать, нужно знать какие из строк являются заголовками, и озаглавливают ли они строки, столбцы и т.д. Для таблицы выше это можно определить только визуально (попробуйте сами на примере, открыв <a href="http://mdn.github.io/learning-area/accessibility/html/bad-table.html">bad-table.html</a>).</p> + +<p>Теперь посмотрим на <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/styling-tables/punk-bands-complete.html">пример таблицы с панк-группами</a>, где можно увидеть несколько вспомогательных средств:</p> + +<ul> + <li>Заголовки таблиц определены, используя элементы {{htmlelement("th")}}; можно также указать являются ли они заголовками для строк или столбцов с помощью аттрибута <code>scope</code>. Это даёт нам полные группы данных, которые скринридер обработает как отдельные блоки.</li> + <li>Элемент {{htmlelement("caption")}} и аттрибут <code>summary</code> у элемента {{htmlelement("table")}} выполняют похожую работу — они выступают в качестве альтернативного текста для таблицы, предоставляя пользователям скринридера краткое содержание. Элемент <code><caption></code> обычно предпочтительнее, так как контент становится доступнее и для зрячих пользователей, которые могут посчитать это полезным. На самом деле необязательно ни то, ни другое.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Более подробную информацию о доступных таблицах можно узнать в статье <a href="/ru/docs//ru/docs/Learn/HTML/Tables/Advanced">HTML-таблицы: продвинутые возможности и доступность</a>.</p> +</div> + +<h2 id="Альтернативный_текст">Альтернативный текст</h2> + +<p>В то время как текстовый контент доступен по-умолчанию, этого нельзя сказать о мультимедийном контенте — изображения/видео-контент не может быть просмотрен людьми с нарушениями зрения, а аудио контент не может быть услышан людьми с нарушениями слуха. Мы подробно рассмотрим видео и аудио контент в статье о доступности мультимедиа позже, но в этой статье мы рассмотрим доступность для простого элемента {{htmlelement("img")}}.</p> + +<p>У нас есть простой пример, <a href="http://mdn.github.io/learning-area/accessibility/html/accessible-image.html">accessible-image.html</a>, который содержит четыре копии одного и того же изображения:</p> + +<pre><img src="dinosaur.png"> + +<img src="dinosaur.png" + alt="Красный тираннозавр Рекс: стоящий как человек двуногий динозавр, с маленькими передними лапами и большой головой с большим количеством острых зубов."> + +<img src="dinosaur.png" + alt="Красный тираннозавр Рекс: стоящий как человек двуногий динозавр, с маленькими передними лапами и большой головой с большим количеством острых зубов." + title="Красный динозавр Mozilla"> + + +<img src="dinosaur.png" aria-labelledby="dino-label"> + +<p id="dino-label">Красный тираннозавр Рекс Mozilla: стоящий как человек двуногий динозавр, с маленькими передними лапами и большой головой с большим количеством острых зубов.</p> +</pre> + +<p>Первое изображение, когда оно просматривается программой чтения с экрана, не очень помогает пользователю — например, VoiceOver озвучивает его как «/dinosaur.png, image». Он озвучивает имя файла, чтобы попытаться помочь. В этом примере пользователь, по крайней мере, будет знать, что это какой-то динозавр, но часто файлы могут загружаться с программно-генерируемыми именами (например, с цифровой камеры), и эти имена файлов, скорее всего, не обеспечат контекста для содержимого изображения.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вот почему вы никогда не должны включать текстовое содержимое в изображение — скринридеры просто не могут получить к нему доступ.Есть и другие недостатки — вы не можете выбрать его и скопировать/вставить. Просто не делайте этого!</p> +</div> + +<p>Когда скринридер встретит второе изображение, он озвучит аттрибут <code>alt</code> полностью: «Красный тираннозавр Рекс: стоящий как человек двуногий динозавр, с маленькими передними лапами и большой головой с большим количеством острых зубов».</p> + +<p>Это подчёркивает важность не только использования содержательных файловых имён в случаях отсутствия, так называемого, <strong>альтернативного текста</strong>, но также важность предоставления альтернативного текста в аттрибуте <code>alt</code>, где это возможно. Заметьте, что содержание аттрибута <code>alt</code> должно всегда предоставлять прямое представление изображения и то, что оно визуально передаёт. Любые личные знания или дополнительное описание не должны быть включены, так как это не принесёт пользы людям, которые не видели изображение ранее.</p> + +<p>Также стоит учитывать, имеют ли изображения значение внутри вашего контента, или они исключительно для украшения без смысла. Если они декоративные, лучше оставить значение аттрибута <code>alt</code> пустым (смотрите «<a href="#Пустые_аттрибуты_alt">Пустые аттрибуты alt</a>») или просто вставить их как фон с помощью CSS.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Для более подробной информации об изображениях и лучших практиках читайте «<a href="/ru/docs/Learn/HTML/Multimedia_and_embedding/Изображения_в_HTML">Изображения в HTML»</a> и «<a href="/ru/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Адаптивные изображения</a>».</p> +</div> + +<p>Если вы всё же хотите предоставить дополнительную контекстуальную информацию, поместите её в тексте рядом с изображением или внутри аттрибута <code>title</code>, как показано ниже. В этом случае большинство скринридеров озвучат альтернативный текст, аттрибут <code>title</code> и имя файла. Дополнительно, при наведении мышкой браузеры отобразят текст из аттрибута <code>title</code> как всплывающую подсказку.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14333/title-attribute.png" style="display: block; margin: 0 auto;"></p> + +<p>Давайте взглянем на четвёртый способ:</p> + +<pre class="brush: html"><img src="dinosaur.png" aria-labelledby="dino-label"> + +<p id="dino-label">Красный тираннозавр Mozilla ... </p></pre> + +<p>В этом случае мы вообще не используем аттрибут <code>alt</code>. Вместо этого мы представили наше описание изображения как обычный параграф, указали <code>id</code>, и потом использовали аттрибут <code>aria-labelledby</code>, сославшись на тот <code>id</code>. Это вынуждает скринридеры использовать параграф как альтернативный текст/описание изображения. Это особенно удобно, если вы хотите использовать один текст как описание для нескольких изображений, что невозомжно с помощью аттрибута <code>alt</code>.</p> + +<div class="note"> +<p><strong>Примечание</strong>: <code>aria-labelledby</code> — часть спецификации <a href="https://www.w3.org/TR/wai-aria-1.1/">WAI-ARIA</a>, которая позволяет разработчиками добавлять, где требуется, дополнительную семантику разметке для улучшения доступности при использовании скринридеров. Чтобы узнать больше о том, как это работает, читайте статью <a href="/ru/docs/Learn/Accessibility/WAI-ARIA_basics">«Основы WAI-ARIA».</a></p> +</div> + +<h3 id="Другие_механизмы_альтернативного_текста">Другие механизмы альтернативного текста</h3> + +<p>У изображений есть ещё один механизм для предоставления описательного текста. Например, есть аттрибут <code>longdesc</code>, который предназначен для указания отдельной веб-страницы, содержащей расширенное описание изображения:</p> + +<pre class="brush: html"><img src="dinosaur.png" longdesc="dino-info.html"></pre> + +<p>Звучит, как хорошая идея, особенно для такой инфографики как диаграммы с большим количеством информации, которую, в качестве альтернативы, можно представить в виде доступной таблицы с данными (смотрите предыдущий раздел). Однако, <code>longdesc</code> нестабильно поддерживается скринридерами, и контент полностью недоступен пользователям, которые не используют скринридеры. Пожалуй, намного лучше будет вставить длинное описание на страницу вместе с изображением, или указать обычную ссылку.</p> + +<p>HTML5 содержит два новых элемента — {{htmlelement("figure")}} и {{htmlelement("figcaption")}}, которые, как предполагается, должны связывать какую-любо фигуру (всё что угодно, необязательно изображение) с заголовком фигуры:</p> + +<pre class="brush: html"><figure> + <img src="dinosaur.png" alt="Тираннозавр организации Mozilla"> + <figcaption>Красный тираннозавр Рекс: стоящий как человек двуногий динозавр, с маленькими передними лапами и большой головой с большим количеством острых зубов.</figcaption> +</figure></pre> + +<p>К сожалению, большинство скринридеров, кажется, пока ещё не умеют связывать заголовки фигур с самими фигурами, но такая структура элементов удобна для CSS стилизации, к тому же, она предоставляет способ расположить описание рядом с изображением в исходнике.</p> + +<h3 id="Пустые_аттрибуты_alt">Пустые аттрибуты alt</h3> + +<pre class="brush: html"><h3> + <img src="article-icon.png" alt=""> + Тираннозавр Рекс: король динозвров +</h3></pre> + +<p>Бывает, что в дизайне страницы присутствуют изображения, но они исполняют декоративную роль. В примере выше вы можете заметить, что у изображения пустой аттрибут <code>alt</code> — это сделано, чтобы скринридер опознал изображение, но не стал озвучивать её описание (вместо этого, он бы озвучил её как «изображение», или аналогично).</p> + +<p>Причина, по которой стоит использовать пустой аттрибут <code>alt</code>, вместо того, чтобы просто его не указывать в том, что большинство скринридеров объявят весь URL-адрес изображения, если не указан <code>alt</code>. В пример выше изображение используется как украшение для связанного с ним заголовка. В таких случаях и случаях, когда изображение является украшением и не имеет ценное содержание, вы должны использовать пустой аттрибут <code>alt</code>. Другой вариант — использовать aria роль role="presentation". Это также предотвратит озвучивание скринридером альтернативного текста.</p> + +<div class="note"> +<p><strong>Примечание</strong>: По возможности для отображения декоративных изображений вы должны использовать CSS.</p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>Теперь вы должны хорошо разбираться в написании доступного HTML для большинства случаев. Наша статья про основы WAI-ARIA также заполнит пробелы в знаниях, но эта статья посвящена основам. Далее мы рассмотрим CSS и JavaScript, и как хорошое или плохое их использование влияет на доступность. </p> + +<p>{{PreviousMenuNext("Learn/Accessibility/What_is_Accessibility","Learn/Accessibility/CSS_and_JavaScript", "Learn/Accessibility")}}</p> + + + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/Доступность/What_is_accessibility">Что такое доступность?</a></li> + <li><a href="/ru/docs/Learn/Accessibility/HTML">HTML: Хорошая основа для доступности</a></li> + <li><a href="/ru/docs/Learn/Accessibility/CSS_and_JavaScript">CSS и JavaScript доступность - лучшие практики</a></li> + <li><a href="/ru/docs/Learn/Accessibility/WAI-ARIA_basics">Основы WAI-ARIA</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Multimedia">Доступность мультимедиа</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Mobile">Мобильная доступность</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Accessibility_troubleshooting">Устранение проблем доступности</a></li> +</ul> diff --git a/files/ru/learn/доступность/index.html b/files/ru/learn/доступность/index.html new file mode 100644 index 0000000000..422bead1d7 --- /dev/null +++ b/files/ru/learn/доступность/index.html @@ -0,0 +1,55 @@ +--- +title: Доступность +slug: Learn/Доступность +tags: + - CSS + - HTML + - JavaScript + - Удобство + - доступность +translation_of: Learn/Accessibility +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Изучение HTML, CSS, и JavaScript полезно, если вы хотите стать веб-разработчиком, но ваши знания должны быть глубже обычного использования технологий — вы должны быть ответственны и максимизировать доступность ваших веб-приложений, не лишая никого возможности их использования. Чтобы достигнуть этого, вы можете следовать общепринятым лучшим практикам (которые демонстрируются в статьях посвященных <a href="/ru-RU/docs/Learn/HTML">HTML</a>, <a href="/ru-RU/docs/Learn/CSS">CSS</a> и <a href="/ru-RU/docs/Learn/JavaScript">JavaScript</a>), проводить <a href="/ru-RU/docs/Learn/Tools_and_testing/Cross_browser_testing">кросс-браузерное тестирование</a> и обращать внимание на доступность с самого начала. В этом модуле мы рассмотрим эту тему в деталях.</p> + +<h2 id="Прежде_чем_начать">Прежде чем начать</h2> + +<p>Чтобы разобраться с большей частью материалов этого модуля, хорошей идеей будет проходить одновременно один или несколько из модулей других тем (<a href="/ru-RU/docs/Learn/HTML">HTML</a>, <a href="/ru-RU/docs/Learn/CSS">CSS</a> или <a href="/ru-RU/docs/Learn/JavaScript">JavaScript</a>), или, что ещё лучше, пройти соответствующие части данного модуля во время изучения этих технологий.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Если вы работаете на компьютере/планшете/другом устройстве, на котором у вас нет возможности создавать файлы, вы можете попробовать большую часть примеров кода в онлайн программах, таких как <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Справочники">Справочники</h2> + +<dl> + <dt><a href="/ru/docs/Learn/Accessibility/What_is_accessibility">Что такое доступность?</a></dt> + <dd>Данная статья открывает модуль, в котором рассматривается, что такое доступность на самом деле — она включает в себя группы людей, которые нам нужно учитывать и почему, какие инструменты используют разные пользователи для взаимодействия с вебом, и как мы можем сделать доступность частью нашего рабочего процесса веб-разработки.</dd> + <dt><a href="/ru-RU/docs/Learn/Accessibility/HTML">HTML: Хорошая основа для доступности</a></dt> + <dd>Большая часть содержимого интернета может быть сделана доступной просто благодаря использованию HTML элементов по назначению. В этой статье подробно рассмотрено как HTML может быть использован для обеспечения максимальной доступности.</dd> + <dt><a href="/ru-RU/docs/Learn/Accessibility/CSS_and_JavaScript">Лучшие практики CSS и JavaScript для обеспечения доступности</a></dt> + <dd>CSS и JavaScript, при правильном использовании, также имеют потенциал для обеспечения доступности, но при неправильном использовании они могут существенно ухудшить доступность. Эта статья раскрывает некоторые из лучших практик CSS и JavaScript которые должны помочь сделать даже очень сложное содержимое как можно более доступным.</dd> + <dt><a href="/ru-RU/docs/Learn/Accessibility/WAI-ARIA_basics">Основы WAI-ARIA</a></dt> + <dd><em>Web Accessibility Initiative - Accessible Rich Internet Applications </em>— это технологический стандарт для предоставления возможности полноценного использования Интернета людьми с физическими ограничениями.<br> + Исходя из предыдущей статьи, иногда создание сложных элементов управления пользовательским интерфейсом, которые включают в себя не семантический HTML и динамический контент, обновляемый с помощью JavaScript, может быть затруднено. WAI-ARIA — это технология, которая может помочь в решении таких проблем, добавляя дополнительную семантику, которую браузеры и вспомогательные технологии могут распознавать и использовать, чтобы пользователи знали, что происходит. Здесь мы покажем, как использовать его на базовом уровне для улучшения доступности.</dd> + <dt><a href="/ru-RU/docs/Learn/Accessibility/Multimedia">Доступный мультимедиа контент</a></dt> + <dd>Другая категория контента, которая может создавать проблемы с доступностью, это мультимедиа — видео, аудио и изображения, которые должны быть предоставлены с надлежащей текстовой альтернативой, чтобы их могли понять с помощью вспомогательных технологий и их пользователи. В этой статье показано, как это можно сделать.</dd> + <dt><a href="/ru-RU/docs/Learn/Accessibility/Mobile">Доступность на мобильных устройствах</a></dt> + <dd>Поскольку веб-доступ на мобильных устройствах является настолько популярным, и на популярных платформах, таких как iOS и Android, есть полноценные средства обеспечения доступности, важно учитывать доступность вашего веб-контента для этих платформ. В этой статье рассматриваются соображения доступности для мобильных устройств.</dd> +</dl> + +<h2 id="Проверка_знаний">Проверка знаний</h2> + +<dl> + <dt><a href="/ru-RU/docs/Learn/Accessibility/Accessibility_troubleshooting">Найди недочеты в доступности</a></dt> + <dd>В этом блоке представлен достаточно простой сайт, в котором, однако, есть множество недочетов в доступности. Необходимо найти их и починить.</dd> +</dl> + +<h2 id="Также_советуем_посмотреть">Также советуем посмотреть</h2> + +<ul> + <li><a href="https://egghead.io/courses/start-building-accessible-web-applications-today">Начать создание доступных веб-приложений сегодня</a> — отличная серия видеоуроков Марси Саттона.</li> + <li><a href="https://dequeuniversity.com/resources/">Ресурсы университета Deque</a> — включает примеры кода, ссылки для чтения с экрана и другие полезные ресурсы.</li> + <li><a href="http://webaim.org/resources/">Ресурсы WebAIM</a> — включает руководства, контрольные списки, инструменты и многое другое.</li> +</ul> diff --git a/files/ru/learn/доступность/mobile/index.html b/files/ru/learn/доступность/mobile/index.html new file mode 100644 index 0000000000..bbdc7f0e1d --- /dev/null +++ b/files/ru/learn/доступность/mobile/index.html @@ -0,0 +1,304 @@ +--- +title: Мобильная доступность +slug: Learn/Доступность/Mobile +tags: + - Mobile +translation_of: Learn/Accessibility/Mobile +--- +<div> +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Accessibility/Multimedia","Learn/Accessibility/Accessibility_troubleshooting", "Learn/Accessibility")}}</div> + +<p class="summary">With web access on mobile devices being so popular, and popular platforms such as iOS and Android having fully fledged accessibility tools, it is important to consider the accessibility of your web content on these platforms. This article looks at mobile-specific accessibility considerations.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a basic understanding of HTML, CSS, and JavaScript, and an understanding of the <a href="/en-US/docs/Learn/Accessibility">previous articles in the course</a>.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand what problems exist with accessibility on mobile devices, and how to overcome them.</td> + </tr> + </tbody> +</table> + +<h2 id="Accessibility_on_mobile_devices">Accessibility on mobile devices</h2> + +<p>The state of accessibility — and support for web standards in general — is good in modern mobile devices. Long gone are the days when mobile devices ran completely different web technologies to desktop browsers, forcing developers to use browser sniffing and serve them completely separate sites (although quite a few companies still detect usage of mobile devices and serve them a separate mobile domain).</p> + +<p>These days, mobile devices in general can handle "full fat" websites, and the main platforms even have screenreaders built in to enable visually impaired users to use them successfully. Modern mobile browsers tend to have good support for <a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA</a>, too.</p> + +<p>To make a website accessible and usable on mobile, you just need to follow general good web design and accessibility best practices.</p> + +<p>There are some exceptions that need special consideration for mobile; the main ones are:</p> + +<ul> + <li>Control mechanisms — Make sure interface controls such as buttons are accessible on mobiles (i.e., mainly touchscreen), as well as desktops/laptops (mainly mouse/keyboard).</li> + <li>User input — Make user input requirements as painless as possible on mobile (e.g., in forms, keep typing to a minimum).</li> + <li>Responsive design — Make sure layouts work on mobile, conserve image download sizes, and think about provision of images for high-resolution screens.</li> +</ul> + +<h2 id="Summary_of_screenreader_testing_on_Android_and_iOS">Summary of screenreader testing on Android and iOS</h2> + +<p>The most common mobile platforms have fully functional screenreaders. These function in much the same way as desktop screenreaders, except they are largely operated using touch gestures rather than key combinations.</p> + +<p>Let's look at the main two: TalkBack on Android and VoiceOver on iOS.</p> + +<h3 id="Android_TalkBack">Android TalkBack</h3> + +<p>The TalkBack screenreader is built into the Android operating system.</p> + +<p>To turn it on, select <em>Settings > Accessibility > TalkBack</em>, and then press the slider switch to turn it on. Follow any additional on-screen prompts that you are presented with.</p> + +<p><strong>Note:</strong> Older versions of TalkBack are turned on in <a href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">slightly different ways</a>.</p> + +<p>When TalkBack is turned on, your Android device's basic controls will be a bit different. For example:</p> + +<ol> + <li>Single-tapping an app will select it, and the device will read out what the app is.</li> + <li>Swiping left and right will move between apps, or buttons/controls if you are in a control bar. The device will read out each option.</li> + <li>Double-tapping anywhere will open the app/select the option.</li> + <li>You can also "explore by touch" — hold your finger down on the screen and drag it around, and your device will read out the different apps/items you move across.</li> +</ol> + +<p>If you want to turn TalkBack off:</p> + +<ol> + <li>Navigate to your <em>Settings</em> app using the above gestures.</li> + <li>Navigate to <em>Accessibility > TalkBack</em>.</li> + <li>Navigate to the slider switch and activate it to turn it off.</li> +</ol> + +<p><strong>Note:</strong> You can get to your homescreen at any time by swiping up and left in a smooth motion. If you have more than one homescreen, you can move between them by swiping two fingers left and right.</p> + +<p>For a more complete list of TalkBack gestures, see <a href="https://support.google.com/accessibility/android/answer/6151827">Use TalkBack gestures</a>.</p> + +<h4 id="Unlocking_the_phone">Unlocking the phone</h4> + +<p>When TalkBack is turned on, unlocking the phone is a bit different.</p> + +<p>You can do a two-finger swipe up from the bottom of the lock screen. If you've set a passcode or pattern for unlocking your device, you will then be taken to the relevant entry screen to enter it.</p> + +<p>You can also explore by touch to find the <em>Unlock</em> button at the bottom middle of the screen, and then double-tap.</p> + +<h4 id="Global_and_local_menus">Global and local menus</h4> + +<p>TalkBack allows you to access global and local context menus, wherever you have navigated to on the device. The former provides global options relating to the device as a whole, and the latter provides options relating just to the current app/screen you are in.</p> + +<p>To get to these menus:</p> + +<ol> + <li>Access the global menu by quickly swiping down, and then right.</li> + <li>Access the local menu by quickly swiping up, and then right.</li> + <li>Swipe left and right to cycle between the different options.</li> + <li>Once you've selected the option you want, double-click to choose that option.</li> +</ol> + +<p>For details on all the options available under the global and local context menus, see <a href="https://support.google.com/accessibility/android/answer/6007066">Use global and local context menus</a>.</p> + +<h4 id="Browsing_web_pages">Browsing web pages</h4> + +<p>You can use the local context menu while in a web browser to find options to navigate web pages using just the headings, form controls, or links, or navigate line by line, etc.</p> + +<p>For example, with TalkBack turned on:</p> + +<ol> + <li>Open your web browser.</li> + <li>Activate the URL bar.</li> + <li>Enter a web page that has a bunch of headings on it, such as the front page of bbc.co.uk. To enter the text of the URL: + <ul> + <li>Select the URL bar by swiping left/right till you get to it, and then double-tapping.</li> + <li>Hold your finger down on the virtual keyboard until you get the character you want, and then release your finger to type it. Repeat for each character.</li> + <li>Once you've finished, find the Enter key and press it.</li> + </ul> + </li> + <li>Swipe left and right to move between different items on the page.</li> + <li>Swipe up and right with a smooth motion to enter the local content menu.</li> + <li>Swipe right until you find the "Headings and Landmarks" option.</li> + <li>Double-tap to select it. Now you'll be able to swipe left and right to move between headings and ARIA landmarks.</li> + <li>To go back to the default mode, enter the local context menu again by swiping up and right, select "Default", and then double-tap to activate.</li> +</ol> + +<p><strong>Note:</strong> See <a href="https://support.google.com/accessibility/android/answer/6283677?hl=en&ref_topic=3529932">Get started on Android with TalkBack</a> for more complete documentation.</p> + +<h3 id="iOS_VoiceOver">iOS VoiceOver</h3> + +<p>A mobile version of VoiceOver is built into the iOS operating system.</p> + +<p>To turn it on, go to Your <em>Settings</em> app and select <em>General > Accessibility > VoiceOver</em>. Press the <em>VoiceOver</em> slider to enable it (you'll also see a number of other options related to VoiceOver on this page).</p> + +<p>Once VoiceOver is enabled, the iOS's basic control gestures will be a bit different:</p> + +<ol> + <li>A single tap will cause the item you tap on to be selected; your device will speak the item you've tapped on.</li> + <li>You can also navigate the items on the screen by swiping left and right to move between them, or by sliding your finger around on the screen to move between different items (when you find the item you want, you can remove your finger to select it).</li> + <li>To activate the selected item (e.g., open a selected app), double-tap anywhere on the screen.</li> + <li>Swipe with three fingers to scroll through a page.</li> + <li>Tap with two fingers to perform a context-relevant action — for example, taking a photo while in the camera app.</li> +</ol> + +<p>To turn it off again, navigate back to <em>Settings > General > Accessibility > VoiceOver</em> using the above gestures, and toggle the <em>VoiceOver</em> slider back to off.</p> + +<h4 id="Unlock_phone">Unlock phone</h4> + +<p>To unlock the phone, you need to press the home button (or swipe) as normal. If you have a passcode set, you can select each number by swiping/sliding (as explained above) and then double-tapping to enter each number when you've found the right one.</p> + +<h4 id="Using_the_Rotor">Using the Rotor</h4> + +<p>When VoiceOver is turned on, you have a navigation feature called the Rotor available to you, which allows you to quickly choose from a number of common useful options. To use it:</p> + +<ol> + <li>Twist two fingers around on the screen like you are turning a dial. Each option will be read aloud as you twist further around. You can go back and forth to cycle through the options.</li> + <li>Once you've found the option you want: + <ul> + <li>Release your fingers to select it.</li> + <li>If it is an option you can iterate the value of (such as Volume or Speaking Rate), you can do a swipe up or down to increase or decrease the value of the selected item.</li> + </ul> + </li> +</ol> + +<p>The options available under the Rotor are context-sensitive — they will differ depending on what app or view you are in (see below for an example).</p> + +<h4 id="Browsing_web_pages_2">Browsing web pages</h4> + +<p>Let's have a go at web browsing with VoiceOver:</p> + +<ol> + <li>Open your web browser.</li> + <li>Activate the URL bar.</li> + <li>Enter a web page that has a bunch of headings on it, such as the front page of bbc.co.uk. To enter the text of the URL: + <ul> + <li>Select the URL bar by swiping left/right until you get to it, and then double-tapping.</li> + <li>For each character, hold your finger down on the virtual keyboard until you get the character you want, and then release your finger to select it. Double-tap to type it.</li> + <li>Once you've finished, find the Enter key and press it.</li> + </ul> + </li> + <li>Swipe left and right to move between items on the page. You can double-tap an item to select it (e.g., follow a link).</li> + <li>By default, the selected Rotor option will be Speaking Rate; you can currently swipe up and down to increase or decrease the speaking rate.</li> + <li>Now turn two fingers around the screen like a dial to show the rotor and move between its options. Here are a few examples of the options available: + <ul> + <li><em>Speaking Rate</em>: Change the speaking rate.</li> + <li><em>Containers</em>: Move between different semantic containers on the page.</li> + <li><em>Headings</em>: Move between headings on the page.</li> + <li><em>Links</em>: Move between links on the page.</li> + <li><em>Form Controls</em>: Move between form controls on the page.</li> + <li><em>Language</em>: Move between different translations, if they are available.</li> + </ul> + </li> + <li>Select <em>Headings</em>. Now you'll be able to swipe up and down to move between headings on the page.</li> +</ol> + +<p><strong>Note:</strong> For a more complete reference covering the VoiceOver gestures available and other hints on accessibility testing on iOS, see <a href="https://developer.apple.com/library/content/technotes/TestingAccessibilityOfiOSApps/TestAccessibilityonYourDevicewithVoiceOver/TestAccessibilityonYourDevicewithVoiceOver.html#//apple_ref/doc/uid/TP40012619-CH3">Test Accessibility on Your Device with VoiceOver</a>.</p> + +<h2 id="Control_mechanisms">Control mechanisms</h2> + +<p>In our CSS and JavaScript accessibility article, we looked at the idea of events that are specific to a certain type of control mechanism (see <a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/CSS_and_JavaScript#mouse-specific_events">Mouse-specific events</a>). To recap, these cause accessibility issues because other control mechanisms can't activate the associated functionality.</p> + +<p>As an example, the <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick">click</a> event is good in terms of accessibility — an associated event handler can be invoked by clicking the element the handler is set on, tabbing to it and pressing Enter/Return, or tapping it on a touchscreen device. Try our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/simple-button-example.html">simple-button-example.html</a> example (<a href="http://mdn.github.io/learning-area/accessibility/mobile/simple-button-example.html">see it running live</a>) to see what we mean.</p> + +<p>Alternatively, mouse-specific events such as <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onmousedown">mousedown</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onmouseup">mouseup</a> create problems — their event handlers cannot be invoked using non-mouse controls.</p> + +<p>If you try to control our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/simple-box-drag.html">simple-box-drag.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/mobile/simple-box-drag.html">see example live</a>) example with keyboard or touch, you'll see the problem. This occurs because we are using code such as the following:</p> + +<pre><code>div.onmousedown = function() { + initialBoxX = div.offsetLeft; + initialBoxY = div.offsetTop; + movePanel(); +} + +document.onmouseup = stopMove;</code></pre> + +<p>To enable other forms of control, you need to use different, yet equivalent events — for example, touch events work on touchscreen devices:</p> + +<pre><code>div.ontouchstart = function(e) { + initialBoxX = div.offsetLeft; + initialBoxY = div.offsetTop; + positionHandler(e); + movePanel(); +} + +panel.ontouchend = stopMove;</code></pre> + +<p>We've provided a simple example that shows how to use the mouse and touch events together — see <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/multi-control-box-drag.html">multi-control-box-drag.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/mobile/multi-control-box-drag.html">see the example live</a> also).</p> + +<p><strong>Note:</strong> You can also see fully functional examples showing how to implement different control mechanisms at <a href="https://developer.mozilla.org/en-US/docs/Games/Techniques/Control_mechanisms">Implementing game control mechanisms</a>.</p> + +<h2 id="Responsive_design">Responsive design</h2> + +<p><a href="https://developer.mozilla.org/en-US/docs/Web/Apps/Progressive/Responsive">Responsive design</a> is the practice of making your layouts and other features of your apps dynamically change depending on factors such as screen size and resolution, so they are usable and accessible to users of different device types.</p> + +<p>In particular, the most common problems that need to be addressed for mobile are:</p> + +<ul> + <li>Suitability of layouts for mobile devices. A multi-column layout won't work as well on a narrow screen, for example, and the text size may need to be increased so it is legible. Such issues can be solved by creating a responsive layout using technologies such as <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries">media queries</a>, <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag">viewport</a>, and <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a>.</li> + <li>Conserving image sizes downloaded. In general, small screen devices won't need images that are as large as their desktop counterparts, and they are more likely to be on slow network connections. Therefore, it is wise to serve smaller images to narrow screen devices as appropriate. You can handle this using <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">responsive image techniques</a>.</li> + <li>Thinking about high resolutions. Many mobile devices have high-resolution screens, and therefore need higher-resolution images so that the display can continue to look crisp and sharp. Again, you can serve images as appropriate using responsive image techniques. In addition, many image requirements can be fulfilled using the SVG vector images format, which is well-supported across browsers today. SVG has a small file size and will stay sharp regardless of whatever size is being displayed (see <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the web</a> for more details).</li> +</ul> + +<p><strong>Note:</strong> We won't provide a full discussion of responsive design techniques here, as they are covered in other places around MDN (see above links).</p> + +<h3 id="Specific_mobile_considerations">Specific mobile considerations</h3> + +<p>There are other important issues to consider when making sites more accessible on mobile. We have listed a couple here, but we will add more when we think of them.</p> + +<h4 id="Not_disabling_zoom">Not disabling zoom</h4> + +<p>Using <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag">viewport</a>, it is possible to disable zoom, using code like this in your {{htmlelement("head")}}:</p> + +<pre><code><meta name="viewport" content="user-scalable=no"></code></pre> + +<p>You should never do this if at all possible — many people rely on zoom to be able to see the content of your website, so taking this functionality away is a really bad idea. There are certain situations where zooming might break the UI; in such cases, if you feel that you absolutely need to disable zoom, you should provide some other kind of equivalent, such as a control for increasing the text size in a way that doesn't break your UI.</p> + +<h4 id="Keeping_menus_accessible">Keeping menus accessible</h4> + +<p>Because the screen is so much narrower on mobile devices, it is very common to use media queries and other technologies to make the navigation menu shrink down to a tiny icon at the top of the display — which can be pressed to reveal the menu only if it's needed — when the site is viewed on mobile. This is commonly represented by a "three horizontal lines" icon, and the design pattern is consequently known as a "hamburger menu".</p> + +<p>When implementing such a menu, you need to make sure that the control to reveal it is accessible by appropriate control mechanisms (normally touch for mobile), as discussed in {{anch("Control mechanisms")}} above, and that the rest of the page is moved out of the way or hidden in some way while the menu is being accessed, to avoid confusion with navigating it.</p> + +<p>Click here for a <a href="http://fritz-weisshart.de/meg_men/">good hamburger menu example</a>.</p> + +<h2 id="User_input">User input</h2> + +<p>On mobile devices, inputting data tends to be more annoying for users than the equivalent experience on desktop computers. It is more convenient to type text into form inputs using a desktop or laptop keyboard than a touchscreen virtual keyboard or a tiny mobile physical keyboard.</p> + +<p>For this reason, it is worth trying to minimize the amount of typing needed. As an example, instead of getting users to fill out their job title each time using a regular text input, you could instead offer a {{htmlelement("select")}} menu containing the most common options (which also helps with consistency in data entry), and offer an "Other" option that displays a text field to type any outliers into. You can see a simple example of this idea in action in <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/common-job-types.html">common-job-types.html</a> (see the <a href="http://mdn.github.io/learning-area/accessibility/mobile/common-job-types.html">common jobs example live</a>).</p> + +<p>It is also worth considering the use of HTML5 form input types such as date on mobile platforms as they handle them well — both Android and iOS, for example, display usable widgets that fit well with the device experience. See <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/html5-form-examples.html">html5-form-examples.html</a> for some examples (see the <a href="http://mdn.github.io/learning-area/accessibility/mobile/html5-form-examples.html">HTML5 form examples live</a>) — try loading these and manipulating them on mobile devices. For example:</p> + +<ul> + <li>Types <code>number</code>, <code>tel</code>, and <code>email</code> display suitable virtual keyboards for entering numbers/telephone numbers.</li> + <li>Types <code>time</code> and <code>date</code> display suitable pickers for selecting times and dates.</li> +</ul> + +<p>If you want to provide a different solution for desktops, you could always serve different markup to your mobile devices using feature detection. See <a href="http://diveinto.html5doctor.com/detect.html#input-types">input types</a> for raw information on detecting different input types, and also check out our <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">feature detection article</a> for much more information.</p> + +<h2 id="Summary">Summary</h2> + +<p>In this article we have provided you with some details about common mobile accessibility-specific issues and how to overcome them. We also took you through usage of the most common screenreaders to aid you in accessibility testing.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://www.smashingmagazine.com/guidelines-for-mobile-web-development/">Guidelines For Mobile Web Development</a> — A list of articles in <em>Smashing Magazine</em> covering different techniques for mobile web design.</li> + <li><a href="http://www.creativebloq.com/javascript/make-your-site-work-touch-devices-51411644">Make your site work on touch devices</a> — Useful article about using touch events to get interactions working on mobile devices.</li> +</ul> + +<div>{{PreviousMenuNext("Learn/Accessibility/Multimedia","Learn/Accessibility/Accessibility_troubleshooting", "Learn/Accessibility")}}</div> + +<div> +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/Доступность/What_is_accessibility">Что такое доступность?</a></li> + <li><a href="/ru/docs/Learn/Accessibility/HTML">HTML: Хорошая основа для доступности</a></li> + <li><a href="/ru/docs/Learn/Accessibility/CSS_and_JavaScript">CSS и JavaScript доступность - лучшие практики</a></li> + <li><a href="/ru/docs/Learn/Accessibility/WAI-ARIA_basics">Основы WAI-ARIA</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Multimedia">Доступность мультимедиа</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Mobile">Мобильная доступность</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Accessibility_troubleshooting">Устранение проблем доступности</a></li> +</ul> +</div> +</div> diff --git a/files/ru/learn/доступность/multimedia/index.html b/files/ru/learn/доступность/multimedia/index.html new file mode 100644 index 0000000000..e07550ba5e --- /dev/null +++ b/files/ru/learn/доступность/multimedia/index.html @@ -0,0 +1,360 @@ +--- +title: Доступность мультимедиа +slug: Learn/Доступность/Multimedia +tags: + - JavaScript +translation_of: Learn/Accessibility/Multimedia +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Accessibility/WAI-ARIA_basics","Learn/Accessibility/Mobile", "Learn/Accessibility")}}</div> + +<p class="summary">Another category of content that can create accessibility problems is multimedia — video, audio, and image content need to be given proper textual alternatives so they can be understood by assistive technologies and their users. This article shows how.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a basic understanding of HTML, CSS, and JavaScript, an understanding of <a href="/en-US/docs/Learn/Accessibility/What_is_accessibility">what accessibility is</a>.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand the accessibility issues behind multimedia, and how to overcome them.</td> + </tr> + </tbody> +</table> + +<h2 id="Multimedia_and_accessibility">Multimedia and accessibility</h2> + +<p>So far in this module we have looked at a variety of content and what needs to be done to ensure its accessibility, ranging from simple text content to data tables, images, native controls such as form elements and buttons, and even more complex markup structures (with <a href="/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA</a> attributes).</p> + +<p>This article on the other hand looks at another general class of content that arguably isn't as easy to ensure accessibility for — multimedia. Images, videos, {{htmlelement("canvas")}} elements, Flash movies, etc., aren't as easily understood by screenreaders or navigated by the keyboard, and we need to give them a helping hand.</p> + +<p>But don't despair — here we will help you navigate through the techniques available for making multimedia more accessible.</p> + +<h2 id="Simple_images">Simple images</h2> + +<p>We already covered simple text alternatives for HTML images in our <a href="/en-US/docs/Learn/Accessibility/HTML">HTML: A good basis for accessibility</a> article — you can refer back to there for the full details. In short, you should ensure that where possible visual content has an alternative text available for screenreaders to pick up and read to their users.</p> + +<p>For example:</p> + +<pre class="brush: html"><img src="dinosaur.png" + alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."> +</pre> + +<h2 id="Accessible_audio_and_video_controls">Accessible audio and video controls</h2> + +<p>Implementing controls for web-based audio/video shouldn't be a problem, right? Let's investigate.</p> + +<h3 id="The_problem_with_native_HTML5_controls">The problem with native HTML5 controls</h3> + +<p>HTML5 video and audio instances even come with a set of inbuilt controls that allow you to control the media straight out of the box. For example (see <code>native-controls.html</code> <a href="https://github.com/mdn/learning-area/blob/master/accessibility/multimedia/native-controls.html">source code</a> and <a href="http://mdn.github.io/learning-area/accessibility/multimedia/native-controls.html">live</a>):</p> + +<pre class="brush: html"><audio controls> + <source src="viper.mp3" type="audio/mp3"> + <source src="viper.ogg" type="audio/ogg"> + <p>Your browser doesn't support HTML5 audio. Here is a <a href="viper.mp3">link to the audio</a> instead.</p> +</audio> + +<br> + +<video controls> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> +</video></pre> + +<p>The controls attribute provides play/pause buttons, seek bar, etc. — the basic controls you'd expect from a media player. It looks like so in Firefox and Chrome:</p> + +<p><img alt="Screenshot of Video Controls in Firefox" src="https://mdn.mozillademos.org/files/14440/native-controls-firefox.png" style="display: block; height: 361px; margin: 0px auto; width: 400px;"></p> + +<p><img alt="Screenshot of Video Controls in Chrome" src="https://mdn.mozillademos.org/files/14438/native-controls-chrome.png" style="display: block; height: 344px; margin: 0px auto; width: 400px;"></p> + +<p>However, there are problems with these controls:</p> + +<ul> + <li>They are not keyboard accessible, in any browser except for Opera</li> + <li>Different browsers give the native controls differing styling and functionality, and they aren't stylable, meaning that they can't be easily made to follow a site style guide.</li> +</ul> + +<p>To remedy this, we can create our own custom controls. Let's look at how.</p> + +<h3 id="Creating_custom_audio_and_video_controls">Creating custom audio and video controls</h3> + +<p>HTML5 video and audio share an API — HTML Media Element — which allows you to map custom functionality to buttons and other controls — both of which you define yourself.</p> + +<p>Let's take the video example from above and add custom controls to them.</p> + +<h4 id="Basic_setup">Basic setup</h4> + +<p>First, grab a copy of our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/multimedia/custom-controls-start.html">custom-controls-start.html</a>, <a href="https://github.com/mdn/learning-area/blob/master/accessibility/multimedia/custom-controls.css">custom-controls.css</a>, <a href="https://raw.githubusercontent.com/mdn/learning-area/master/accessibility/multimedia/rabbit320.mp4">rabbit320.mp4</a>, and <a href="https://raw.githubusercontent.com/mdn/learning-area/master/accessibility/multimedia/rabbit320.webm">rabbit320.webm</a> files and save them in a new directory on your hard drive.</p> + +<p>Create a new file called main.js and save it in the same directory.</p> + +<p>First of all, let's look at the HTML for the video player, in the HTML:</p> + +<pre class="brush: html"><section class="player"> + <video controls> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> + </video> + + <div class="controls"> + <button class="playpause">Play</button> + <button class="stop">Stop</button> + <button class="rwd">Rwd</button> + <button class="fwd">Fwd</button> + <div class="time">00:00</div> + </div> +</section></pre> + +<h4 id="JavaScript_basic_setup">JavaScript basic setup</h4> + +<p>We've inserted some simple control buttons below our video. These controls of course won't do anything by default; to add functionality, we will use JavaScript.</p> + +<p>We will first need to store references to each of the controls — add the following to the top of your JavaScript file:</p> + +<pre class="brush: js">var playPauseBtn = document.querySelector('.playpause'); +var stopBtn = document.querySelector('.stop'); +var rwdBtn = document.querySelector('.rwd'); +var fwdBtn = document.querySelector('.fwd'); +var timeLabel = document.querySelector('.time');</pre> + +<p>Next, we need to grab a reference to the video/audio player itself — add this line below the previous lines:</p> + +<pre class="brush: js">var player = document.querySelector('video');</pre> + +<p>This holds a reference to a {{domxref("HTMLMediaElement")}} object, which has several useful properties and methods available on it that can be used to wire up functionality to our buttons.</p> + +<p>Before moving onto creating our button functionality, let's remove the native controls so they don't get in the way of our custom controls. Add the following, again at the bottom of your JavaScript:</p> + +<pre class="brush: js">player.removeAttribute('controls');</pre> + +<p>Doing it this way round rather than just not including the controls attribute in the first place has the advantage that if our JavaScript fails for any reason, the user still has some controls available.</p> + +<h4 id="Wiring_up_our_buttons">Wiring up our buttons</h4> + +<p>First, let's set up the play/pause button. We can get this to toggle between play and pause with a simple conditional function, like the following. Add it to your code, at the bottom:</p> + +<pre class="brush: js">playPauseBtn.onclick = function() { + if(player.paused) { + player.play(); + playPauseBtn.textContent = 'Pause'; + } else { + player.pause(); + playPauseBtn.textContent = 'Play'; + } +};</pre> + +<p>Next, add this code to the bottom, which controls the stop button:</p> + +<pre class="brush: js">stopBtn.onclick = function() { + player.pause(); + player.currentTime = 0; + playPauseBtn.textContent = 'Play'; +};</pre> + +<p>There is no <code>stop()</code> function available on {{domxref("HTMLMediaElement")}}s, so instead we <code>pause()</code> it, and at the same time set the <code>currentTime</code> to 0.</p> + +<p>Next, our rewind and fast forward buttons — add the following blocks to the bottom of your code:</p> + +<pre class="brush: js">rwdBtn.onclick = function() { + player.currentTime -= 3; +}; + +fwdBtn.onclick = function() { + player.currentTime += 3; + if(player.currentTime >= player.duration || player.paused) { + player.pause(); + player.currentTime = 0; + playPauseBtn.textContent = 'Play'; + } +};</pre> + +<p>These are very simple, just adding or subtracting 3 seconds to the <code>currentTime</code> each time they are clicked. In a real video player, you'd probably want a more elaborate seeking bar, or similar.</p> + +<p>Note that we also check to see if the <code>currentTime</code> is more than the total media <code>duration</code>, or if the media is not playing, when the Fwd button is pressed. If either conditions are true, we simply stop the video, to avoid the user interface going wrong if they attempt to fast forward when the video is not playing, or fast forward past the end of the video.</p> + +<p>Last of all, add the following to the end of the code, to control the time elapsed display:</p> + +<pre class="brush: js">player.ontimeupdate = function() { + var minutes = Math.floor(player.currentTime / 60); + var seconds = Math.floor(player.currentTime - minutes * 60); + var minuteValue; + var secondValue; + + if (minutes<10) { + minuteValue = "0" + minutes; + } else { + minuteValue = minutes; + } + + if (seconds<10) { + secondValue = "0" + seconds; + } else { + secondValue = seconds; + } + + mediaTime = minuteValue + ":" + secondValue; + timeLabel.textContent = mediaTime; +};</pre> + +<p>Each time the time updates (once per second), we fire this function. It works out the number of minutes and seconds from the given currentTime value that is just in seconds, adds a leading 0 if either the minute or second value is less than 10, and then create the display readout and adds it to the time label.</p> + +<h4 id="Further_reading">Further reading</h4> + +<p>This gives you a basic idea of how to add custom player functionality to video/audio player instances. For more information on how to add more complex features to video/audio players, including Flash fallbacks for older browsers, see:</p> + +<ul> + <li><a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery">Audio and video delivery</a></li> + <li><a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery/Video_player_styling_basics">Video player styling basics</a></li> + <li><a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery/cross_browser_video_player">Creating a cross-browser video player</a></li> +</ul> + +<p>We've also created an advanced example to show how you could create an object-oriented system that finds every video and audio player on the page (no matter how many there are) and adds our custom controls to it. See <a href="http://mdn.github.io/learning-area/accessibility/multimedia/custom-controls-OOJS/">custom-controls-oojs</a> (also <a href="https://github.com/mdn/learning-area/tree/master/accessibility/multimedia/custom-controls-OOJS">see the source code</a>).</p> + +<h2 id="Audio_transcripts">Audio transcripts</h2> + +<p>To provide deaf people with access to audio content, you really need to create text transcripts. These can either be included on the same page as the audio in some way, or included on a separate page and linked to.</p> + +<p>In terms of actually creating the transcript, your options are:</p> + +<ul> + <li>Commercial services — You could pay a professional to do the transcription, see for example companies like <a href="https://scribie.com/">Scribie</a>, <a href="https://castingwords.com/">Casting Words</a>, or <a href="https://www.rev.com/">Rev</a>. Look around and ask advice to make sure you find a reputable company that you'll be able to work with effectively.</li> + <li>Community/grass roots/self transcription — If you are part of an active community or team in your workplace, then you could ask them for help with doing the translations. You could even have a go at doing them yourself.</li> + <li>Automated services — There are AI services available, like <a href="https://trint.com">Trint</a>. Upload a video/audio file to the site, and it automatically transcribes it for you. On YouTube you can choose to generate automated captions/transcripts. Depending on how clear the spoken audio is, the resulting transcript quality will vary greatly. </li> +</ul> + +<p>As with most things in life, you tend to get what you pay for; different services will vary in accuracy and time taken to produce the transcript. If you pay a reputable company or AI service to do the transcription, you will probably get it done rapidly and to a high quality. If you don't want to pay for it, you are likely to get it done at a lower quality, and/or slowly.</p> + +<p>It is not OK to publish an audio resource but promise to publish the transcript later on — such promises often aren't kept, which will erode trust between you and your users. If the audio you are presenting is something like a face to face meeting or live spoken performance, it would be acceptable to take notes during the performance, publish them in full along with the audio, then seek help in cleaning up the notes afterwards.</p> + +<h3 id="Transcript_examples">Transcript examples</h3> + +<p>If you use an automated service, then you'll probably have to use the user interface that the tool provides. For example, take a look at <a href="https://www.youtube.com/watch?v=zFFBsj97Od8">Audio Transcription Sample 1</a> and choose <em>More > Transcript</em>.</p> + +<p>If you are creating your own user interface to present your audio and associated transcript, you can do it however you like, but it might make sense to include it in a showable/hideable panel; see our <a href="http://mdn.github.io/learning-area/accessibility/multimedia/audio-transcript-ui/">audio-transcript-ui</a> example (also see the <a href="https://github.com/mdn/learning-area/tree/master/accessibility/multimedia/audio-transcript-ui">source code</a>).</p> + +<h3 id="Audio_descriptions">Audio descriptions</h3> + +<p>On occasions where there are visuals accompanying your audio, you'll need to provide audio descriptions of some kind to describe that extra content.</p> + +<p>In many cases this will simply take the form of video, in which case you can implement captions using the techniques described in the next section of the article.</p> + +<p>However, there are some edge cases. You might for example have an audio recording of a meeting that refers to an accompanying resource such as a spreadsheet or chart. In such cases, you should make sure that the resources are provided along with the audio + transcript, and specifically link to them in the places where they are referred to in the transcript. This of course will help all users, not just people who are deaf.</p> + +<div class="note"> +<p><strong>Note</strong>: An audio transcript will in general help multiple user groups. As well as giving deaf users access to the information contained in the audio, think about a user with a low bandwidth connection, who would find downloading the audio inconvenient. Think also about a user in a noisy environment like a pub or bar, who is trying to access the information but can't hear it over the noise.</p> +</div> + +<h2 id="Video_text_tracks">Video text tracks</h2> + +<p>To make video accessible for deaf, blind, or even other groups of users (such as those on low bandwidth, or who don't understand the language the video is recorded in), you need to include text tracks along with your video content.</p> + +<div class="note"> +<p><strong>Note</strong>: text tracks are also useful for potentially any user, not just those with disabilities. for example, some users may not be able to hear the audio because they are in noisy environments (like a crowded bar when a sports game is being shown) or might not want to disturb others if they are in a quiet place (like a library.)</p> +</div> + +<p>This is not a new concept — television services have had closed captioning available for quite a long time:</p> + +<p><img alt='Frame from an old-timey cartoon with closed captioning "Good work, Goldie. Keep it up!"' src="https://mdn.mozillademos.org/files/14436/closed-captions.png" style="display: block; height: 240px; margin: 0px auto; width: 320px;"></p> + +<p>Whereas many countries offer English films with subtitles written in their own native languages, and different language subtitles are often available on DVDs, for example</p> + +<p><img alt='An English film with German subtitles "Emo, warum erkennst du nicht die Schonheit dieses Ortes?"' src="https://mdn.mozillademos.org/files/14442/Subtitles_German.jpg" style="display: block; margin: 0 auto;"></p> + +<p>There are different types of text track with different purposes. The main ones you'll come across are:</p> + +<ul> + <li>Captions — There for the benefit of deaf users who can't hear the audio track, including the words being spoken, and contextual information such as who spoke the words, if the people were angry or sad, and what mood the music is currently creating.</li> + <li>Subtitles — Include translations of the audio dialog, for users that don't understand the language being spoken.</li> + <li>Descriptions — These include descriptions for blind people who can't see the video, for example what the scene looks like.</li> + <li>Chapter titles — Chapter markers intended to help the user navigate the media resource</li> +</ul> + +<h3 id="Implementing_HTML5_video_text_tracks">Implementing HTML5 video text tracks</h3> + +<p>Text tracks for displaying with HTML5 video need to be written in WebVTT, a text format containing multiple strings of text along with metadata such as what time in the video you want each text string to be displayed, and even limited styling/positioning information. These text strings are called cues.</p> + +<p>A typical WebVTT file will look something like this:</p> + +<pre>WEBVTT + +1 +00:00:22.230 --> 00:00:24.606 +This is the first subtitle. + +2 +00:00:30.739 --> 00:00:34.074 +This is the second. + + ...</pre> + +<p>To get this displayed along with the HTML media playback, you need to:</p> + +<ul> + <li>Save it as a .vtt file in a sensible place.</li> + <li>Link to the .vtt file with the {{htmlelement("track")}} element. <code><track></code> should be placed within <code><audio></code> or <code><video></code>, but after all <code><source></code> elements. Use the {{htmlattrxref("kind","track")}} attribute to specify whether the cues are subtitles, captions, or descriptions. Furthermore, use {{htmlattrxref("srclang","track")}} to tell the browser what language you have written the subtitles in.</li> +</ul> + +<p>Here's an example:</p> + +<pre class="brush: html"><video controls> + <source src="example.mp4" type="video/mp4"> + <source src="example.webm" type="video/webm"> + <track kind="subtitles" src="subtitles_en.vtt" srclang="en"> +</video></pre> + +<p>This will result in a video that has subtitles displayed, kind of like this:</p> + +<p><img alt='Video player with standard controls such as play, stop, volume, and captions on and off. The video playing shows a scene of a man holding a spear-like weapon, and a caption reads "Esta hoja tiene pasado oscuro."' src="https://mdn.mozillademos.org/files/7887/video-player-with-captions.png" style="display: block; height: 365px; margin: 0px auto; width: 593px;"></p> + +<p>For more details, please read <a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video">Adding captions and subtitles to HTML5 video</a>. You can find <a href="http://iandevlin.github.io/mdn/video-player-with-captions/">the example</a> that goes along with this article on Github, written by Ian Devlin (see the <a href="https://github.com/iandevlin/iandevlin.github.io/tree/master/mdn/video-player-with-captions">source code</a> too.) This example uses some JavaScript to allow users to choose between different subtitles. Note that to turn the subtitles on, you need to press the "CC" button and select an option — English, Deutsch, or Español.</p> + +<div class="note"> +<p><strong>Note</strong>: Text tracks and transcriptions also help you with {{glossary("SEO")}}, since search engines especially thrive on text. Text tracks even allow search engines to link directly to a spot partway through the video.</p> +</div> + +<h2 id="Other_multimedia_content">Other multimedia content</h2> + +<p>The above sections don't cover all types of multimedia content that you might want to put on a web page. You might also need to deal with games, animations, slideshows, embedded video, and content created using other available technologies such as:</p> + +<ul> + <li><a href="/en-US/docs/Web/API/Canvas_API">HTML5 canvas</a></li> + <li>Flash</li> + <li>Silverlight</li> +</ul> + +<p>For such content, you need to deal with accessibility concerns on a case by case basis. In some cases it is not so bad, for example:</p> + +<ul> + <li>If you are embedding audio content using a plugin technology like Flash or Silverlight, you can probably just provide an audio transcript in the same manner as we already showed above in the {{anch("Transcript examples")}} section.</li> + <li>If you are embedding video content using a plugin technology like Flash or Silverlight, you can take advantage of captioning/subtitling techniques available to those technologies. For example, see <a href="http://www.adobe.com/accessibility/products/flash/captions.html">Flash captions</a>, <a href="https://support.brightcove.com/en/video-cloud/docs/using-flash-only-player-api-closed-captioning">Using the Flash-Only Player API for Closed Captioning</a>, or <a href="https://blogs.msdn.microsoft.com/anilkumargupta/2009/05/01/playing-subtitles-with-videos-in-silverlight/">Playing Subtitles with Videos in Silverlight</a>.</li> +</ul> + +<p>However, other multimedia is not so easy to make accessible. If for example you are dealing with an immersive 3D game or virtual reality app, it really is quite difficult to provide text alternatives for such an experience, and you might argue that blind users are not really in the target audience bracket for such apps.</p> + +<p>You can however make sure that such an app has good enough color contrast and clear presentation so it is perceivable to those with low vision/color blindness, and also make it keyboard accessible. Remember that accessibility is about doing as much as you can, rather than striving for 100% accessibility all the time, which is often impossible.</p> + +<h2 id="Summary">Summary</h2> + +<p>This chapter has provided a summary of accessibility concerns for multimedia content, along with some practical solutions.</p> + +<p>{{PreviousMenuNext("Learn/Accessibility/WAI-ARIA_basics","Learn/Accessibility/Mobile", "Learn/Accessibility")}}</p> + +<p> </p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/Доступность/What_is_accessibility">Что такое доступность?</a></li> + <li><a href="/ru/docs/Learn/Accessibility/HTML">HTML: Хорошая основа для доступности</a></li> + <li><a href="/ru/docs/Learn/Accessibility/CSS_and_JavaScript">CSS и JavaScript доступность - лучшие практики</a></li> + <li><a href="/ru/docs/Learn/Accessibility/WAI-ARIA_basics">Основы WAI-ARIA</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Multimedia">Доступность мультимедиа</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Mobile">Мобильная доступность</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Accessibility_troubleshooting">Устранение проблем доступности</a></li> +</ul> + +<p> </p> diff --git a/files/ru/learn/доступность/wai-aria_basics/index.html b/files/ru/learn/доступность/wai-aria_basics/index.html new file mode 100644 index 0000000000..d04c4fd483 --- /dev/null +++ b/files/ru/learn/доступность/wai-aria_basics/index.html @@ -0,0 +1,416 @@ +--- +title: Основы WAI-ARIA +slug: Learn/Доступность/WAI-ARIA_basics +tags: + - JavaScript +translation_of: Learn/Accessibility/WAI-ARIA_basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Accessibility/CSS_and_JavaScript","Learn/Accessibility/Multimedia", "Learn/Accessibility")}}</div> + +<p class="summary"><font>Исходя из предыдущей статьи, иногда создание сложных элементов UI, которые включают в себя неcемантичный HTML и динамически обновляемый с помощью JavaScript контент, может быть затруднено. </font><font>WAI-ARIA - это технология, которая может помочь в решении таких проблем, добавляя дополнительную разметку, которую браузеры и вспомогательные технологии могут распознавать и использовать, чтобы пользователи знали, что происходит. В этой статье</font><font> мы покажем, как использовать эту технологию на базовом уровне для улучшения доступности.</font></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML, CSS и JavaScript, понимание <a href="/en-US/docs/Learn/Accessibility">предыдущей статьи курса</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Ознакомиться с WAI-ARIA и узнать, как эту технологию можно использовать для включения полезной дополнительной семантики в целях повышения доступности.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_такое_WAI-ARIA">Что такое WAI-ARIA?</h2> + +<p>Давайте начнем с рассмотрения того, что такое WAI-ARIA и чем она может быть полезна.</p> + +<h3 id="Новый_набор_проблем">Новый набор проблем</h3> + +<p>С тех пор как веб-приложения стали более сложными и динамичными, появились новые специальные возможности и проблемы.</p> + +<p><font><font>Например, HTML5 ввел ряд семантических элементов, </font><font>чтобы определить общую разметку страниц ( </font></font><a href="https://developer.mozilla.org/ru/docs/Web/HTML/Element/nav" title="HTML-элемент <nav> определяет отдельную секцию документа, назначение которой обозначение ссылок навигации (как внутри текущего документа, так и ведущих на другую страницу). В качестве примера такой секции можно привести меню, якорные ссылки."><code><nav></code></a><font><font>, </font></font><a href="https://developer.mozilla.org/ru/docs/Web/HTML/Element/footer" title="HTML-элемент <footer> представляет нижний колонтитул (футер, подвал) для своего ближайшего элемента секционного контента или секционного корня. Футер обычно содержит информацию об авторе секции, информацию об авторском праве или ссылки на связанные документы."><code><footer></code></a><font><font>и т.д.). До того как </font><font>они были доступны, разработчики просто использовали </font></font><a href="https://developer.mozilla.org/ru/docs/Web/HTML/Element/div" title='Элемент разделения контента HTML (<div>) является базовым контейнером для элементов основного потока ( flow content ). Он не влияет на контент или формат пока не стилизован, используя CSS. Являясь "чистым" контейнером, элемент <div> по своему существу не представляет ничего. Между тем, он используется для группировки контента, что позволяет легко его стилизовать, используя '><code><div></code></a><font><font> с идентификаторами или классами, например </font></font><code><div class="nav"></code><font><font>, но это создавало проблемы, так как не было никакого простого способа найти определенный раздел страницы программным способом.</font></font></p> + +<p>Первоначальным решением было добавить одну или несколько скрытых ссылок вверху страницы для ссылки на навигацию (или на что-то еще), например:</p> + +<pre class="brush: html"><a href="#hidden" class="hidden">Skip to navigation</a></pre> + +<p>Но это все еще не очень точно, и может использоваться только тогда, когда программа чтения с экрана читает сверху страницы.</p> + +<p>В качестве другого примера, в приложения стали использовать сложные элементы управления, такие как поля выбора даты, ползунки для выбора значений и т.д. HTML5 предоставляет специальные типы ввода для отображения таких элементов управления:</p> + +<pre class="brush: html"><input type="date"> +<input type="range"></pre> + +<p><font><font>Они не очень хорошо поддерживаются в разных браузерах, и их очень сложно стилизовать, что делает их не очень полезными для интеграции с дизайном сайтов. </font><font>В результате разработчики нередко используют библиотеки JavaScript, которые генерируют такие элементы управления, как последовательность вложенных </font></font><a href="https://wiki.developer.mozilla.org/ru/docs/Web/HTML/Element/div" title="Элемент разделения контента HTML (<div>) является универсальным контейнером для потокового контента. Он не влияет на контент или макет до тех пор, пока не будет стилизован с помощью CSS."><code><div></code></a><font><font>элементов или ячеек таблиц с именами классов, которые затем стилизуются с помощью CSS и управляют с помощью JavaScript.</font></font></p> + +<p>The problem here is that visually they work, but screenreaders can't make any sense of what they are at all, and their users just get told that they can see a jumble of elements with no semantics to describe what they mean.</p> + +<h3 id="Enter_WAI-ARIA">Enter WAI-ARIA</h3> + +<p><a href="https://www.w3.org/TR/wai-aria-1.1/">WAI-ARIA</a> is a specification written by the W3C, defining a set of additional HTML attributes that can be applied to elements to provide additional semantics and improve accessibility wherever it is lacking. There are three main features defined in the spec:</p> + +<ul> + <li><strong>Roles</strong> — These define what an element is or does. Many of these are so-called landmark roles, which largely duplicate the semantic value of HTML5 structural elements e.g. <code>role="navigation"</code> ({{htmlelement("nav")}}) or <code>role="complementary"</code> ({{htmlelement("aside")}}), but there are also others that describe different pages structures, such as <code>role="banner"</code>, <code>role="search"</code>, <code>role="tabgroup"</code>, <code>role="tab"</code>, etc., which are commonly found in UIs.</li> + <li><strong>Properties</strong> — These define properties of elements, which can be used to give them extra meaning or semantics. As an example, <code>aria-required="true"</code> specifies that a form input needs to be filled in to be valid, whereas <code>aria-labelledby="label"</code> allows you to put an ID on an element, then reference it as being the label for anything else on the page, including multiple elements, which is not possible using <code><label for="input"></code>. As an example, you could use <code>aria-labelledby</code> to specify that a key description contained in a {{htmlelement("div")}} is the label for multiple table cells, or you could use it as an alternative to image alt text — specify existing information on the page as an image's alt text, rather than having to repeat it inside the <code>alt</code> attribute. You can see an example of this at <a href="/en-US/docs/Learn/Accessibility/HTML?document_saved=true#Text_alternatives">Text alternatives</a>.</li> + <li><strong>States</strong> — Special properties that define the current conditions of elements, such as <code>aria-disabled="true"</code>, which specifies to a screenreader that a form input is currently disabled. States differ from properties in that properties don't change throughout the lifecycle of an app, whereas states can change, generally programmatically via JavaScript.</li> +</ul> + +<p>An important point about WAI-ARIA attributes is that they don't affect anything about the web page, except for the information exposed by the browser's accessibility APIs (where screenreaders get their information from). WAI-ARIA doesn't affect webpage structure, the DOM, etc., although the attributes can be useful for selecting elements by CSS.</p> + +<div class="note"> +<p><strong>Note</strong>: You can find a useful list of all the ARIA roles and their uses, with links to futher information, in the WAI-ARIA spec — see <a href="https://www.w3.org/TR/wai-aria-1.1/#role_definitions">Definition of Roles</a>.</p> + +<p>The spec also contains a list of all the properties and states, with links to further information — see <a href="https://www.w3.org/TR/wai-aria-1.1/#state_prop_def">Definitions of States and Properties (all aria-* attributes)</a>.</p> +</div> + +<h3 id="Where_is_WAI-ARIA_supported">Where is WAI-ARIA supported?</h3> + +<p>This is not an easy question to answer. It is difficult to find a conclusive resource that states what features of WAI-ARIA are supported, and where, because:</p> + +<ol> + <li>There are a lot of features in the WAI-ARIA spec.</li> + <li>There are many combinations of operating system, browser, and screenreader to consider.</li> +</ol> + +<p>This last point is key — To use a screenreader in the first place, your operating system needs to run browsers that have the necessary accessibility APIs in place to expose the information screenreaders need to do their job. Most popular OSes have one or two browsers in place that screenreaders can work with. The Paciello Group has a fairly up-to-date post that provides data for this — see <a href="https://www.paciellogroup.com/blog/2014/10/rough-guide-browsers-operating-systems-and-screen-reader-support-updated/">Rough Guide: browsers, operating systems and screen reader support updated</a>.</p> + +<p>Next, you need to worry about whether the browsers in question support ARIA features and expose them via their APIs, but also whether screenreaders recognise that information and present it to their users in a useful way.</p> + +<ol> + <li>Browser support is generally quite good — at the time of writing, <a href="http://caniuse.com/#feat=wai-aria">caniuse.com</a> stated that global browser support for WAI-ARIA was around 88%.</li> + <li>Screenreader support for ARIA features isn't quite at this level, but the most popular screenreaders are getting there. You can get an idea of support levels by looking at Powermapper's <a href="http://www.powermapper.com/tests/screen-readers/aria/">WAI-ARIA Screen reader compatibility</a><span> article.</span></li> +</ol> + +<p>In this article, we won't attempt to cover every WAI-ARIA feature, and its exact support details. Instead, we will cover the most critical WAI-ARIA features for you to know about; if we don't mention any support details, you can assume that the feature is well-supported. We will clearly mention any exceptions to this.</p> + +<div class="note"> +<p><strong>Note</strong>: Some JavaScript libraries support WAI-ARIA, meaning that when they generate UI features like complex form controls, they add ARIA attributes to improve the accessibility of those features. If you are looking for a 3rd party JavaScript solution for rapid UI development, you should definitely consider the accessibility of its UI widgets as an important factor when making your choice. Good examples are jQuery UI (see <a href="https://jqueryui.com/about/#deep-accessibility-support">About jQuery UI: Deep accessibility support</a>), <a href="https://www.sencha.com/products/extjs/">ExtJS</a>, and <a href="https://dojotoolkit.org/reference-guide/1.10/dijit/a11y/statement.html">Dojo/Dijit</a>.</p> +</div> + +<h3 id="When_should_you_use_WAI-ARIA">When should you use WAI-ARIA?</h3> + +<p>We talked about some of the problems that prompted WAI-ARIA to be created earlier on, but essentially, there are four main areas that WAI-ARIA is useful in:</p> + +<ol> + <li><strong>Signposts/Landmarks</strong>: ARIA's <code>role</code> attribute values can act as landmarks that either replicate the semantics of HTML5 elements (e.g. {{htmlelement("nav")}}), or go beyond HTML5 semantics to provide signposts to different functional areas, e.g <code>search</code>, <code>tabgroup</code>, <code>tab</code>, <code>listbox</code>, etc.</li> + <li><strong>Dynamic content updates</strong>: Screenreaders tend to have difficulty with reporting constantly changing content; with ARIA we can use <code>aria-live</code> to inform screenreader users when an area of content is updated, e.g. via <a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a>, or <a href="/en-US/docs/Web/API/Document_Object_Model">DOM APIs</a>.</li> + <li><strong>Enhancing keyboard accessibility</strong>: There are built-in HTML elements that have native keyboard accessibility; when other elements are used along with JavaScript to simulate similar interactions, keyboard accessibility and screenreader reporting suffers as a result. Where this is unavoidable, WAI-ARIA provides a means to allow other elements to receive focus (using <code>tabindex</code>).</li> + <li><strong>Accessibility of non-semantic controls</strong>: When a series of nested <code><div></code>s along with CSS/JavaScript is used to create a complex UI-feature, or a native control is greatly enhanced/changed via JavaScript, accessibility can suffer — screenreader users will find it difficult to work out what the feature does if there are no semantics or other clues. In these situations, ARIA can help to provide what's missing with a combination of roles like <code>button</code>, <code>listbox</code>, or <code>tabgroup</code>, and properties like <code>aria-required</code> or <code>aria-posinset</code> to provide further clues as to functionality.</li> +</ol> + +<p>One thing to remember though — <strong>you should only use WAI-ARIA when you need to!</strong> Ideally, you should <em>always</em> use <a href="/en-US/docs/Learn/Accessibility/HTML">native HTML features</a> to provide the semantics required by screenreaders to tell their users what is going on. Sometimes this isn't possible, either because you have limited control over the code, or because you are creating something complex that doesn't have an easy HTML element to implement it. In such cases, WAI-ARIA can be a valuable accessibility enhancing tool.</p> + +<p>But again, only use it when necessary!</p> + +<div class="note"> +<p><strong>Note</strong>: Also, try to make sure you test your site with a variety of <em>real</em> users — non-disabled people, people using screenreaders, people using keyboard navigation, etc. They will have better insights than you about how well it works.</p> +</div> + +<h2 id="Practical_WAI-ARIA_implementations">Practical WAI-ARIA implementations</h2> + +<p>In the next section we'll look at the four areas in more detail, along with practical examples. Before you continue, you should get a screenreader testing setup put in place, so you can test some of the examples as you go through.</p> + +<p>See our section on <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">testing screenreaders</a> for more information.</p> + +<h3 id="SignpostsLandmarks">Signposts/Landmarks</h3> + +<p>WAI-ARIA adds the <a href="https://www.w3.org/TR/wai-aria-1.1/#role_definitions"><code>role</code> attribute</a> to browsers, which allows you to add extra semantic value to elements on your site wherever they are needed. The first major area in which this is useful is providing information for screenreaders so that their users can find common page elements. Let's look at an example — our <a href="https://github.com/mdn/learning-area/tree/master/accessibility/aria/website-no-roles">website-no-roles</a> example (<a href="http://mdn.github.io/learning-area/accessibility/aria/website-no-roles/">see it live</a>) has the following structure:</p> + +<pre class="brush: html"><header> + <h1>...</h1> + <nav> + <ul>...</ul> + <form> + <!-- search form --> + </form> + </nav> +</header> + +<main> + <article>...</article> + <aside>...</aside> +</main> + +<footer>...</footer></pre> + +<p>If you try testing the example with a screenreader in a modern browser, you'll already get some useful information. For example, VoiceOver gives you the following:</p> + +<ul> + <li>On the <code><header></code> element — "banner, 2 items" (it contains a heading and the <code><nav></code>).</li> + <li>On the <code><nav></code> element — "navigation 2 items" (it contains a list and a form).</li> + <li>On the <code><main></code> element — "main 2 items" (it contains an article and an aside).</li> + <li>On the <code><aside></code> element — "complementary 2 items" (it contains a heading and a list).</li> + <li>On the search form input — "Search query, insertion at beginning of text".</li> + <li>On the <code><footer></code> element — "footer 1 item".</li> +</ul> + +<p>If you go to VoiceOver's landmarks menu (accessed using VoiceOver key + U and then using the cursor keys to cycle through the menu choices), you'll see that most of the elements are nicely listed so they can be accessed quickly.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14420/landmarks-list.png" style="display: block; margin: 0 auto;"></p> + +<p>However, we could do better here. the search form is a really important landmark that people will want to find, but it is not listed in the landmarks menu or treated like a notable landmark, beyond the actual input being called out as a search input (<code><input type="search"></code>). In addition, some older browsers (most notably IE8) don't recognise the semantics of the HTML5 elements.</p> + +<p>Let's improve it by the use of some ARIA features. First, we'll add some role attributes to our HTML structure. You can try taking a copy of our original files (see <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/website-no-roles/index.html">index.html</a> and <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/website-no-roles/style.css">style.css</a>), or navigating to our <a href="https://github.com/mdn/learning-area/tree/master/accessibility/aria/website-aria-roles">website-aria-roles</a> example (<a href="http://mdn.github.io/learning-area/accessibility/aria/website-aria-roles/">see it live</a>), which has a structure like this:</p> + +<pre class="brush: html"><header> + <h1>...</h1> + <nav role="navigation"> + <ul>...</ul> + <form role="search"> + <!-- search form --> + </form> + </nav> +</header> + +<main> + <article role="article">...</article> + <aside role="complementary">...</aside> +</main> + +<footer>...</footer></pre> + +<p>We've also given you a bonus feature in this example — the {{htmlelement("input")}} element has been given the attribute <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-label">aria-label</a></code>, which gives it a descriptive label to be read out by a screenreader, even though we haven't included a {{htmlelement("label")}} element. In cases like these, this is very useful — a search form like this one is a very common, easily recognised feature, and adding a visual label would spoil the page design.</p> + +<pre class="brush: html"><input type="search" name="q" placeholder="Search query" aria-label="Search through site content"></pre> + +<p>Now if we use VoiceOver to look at this example, we get some improvements:</p> + +<ul> + <li>The search form is called out as a separate item, both when browsing through the page, and in the Landmarks menu.</li> + <li>The label text contained in the <code>aria-label</code> attribute is read out when the form input is highlighted.</li> +</ul> + +<p>Beyond this, the site is more likely to be accessible to users of older browsers such as IE8; it is worth including ARIA roles for that purpose. And if for some reason your site is built using just <code><div></code>s, you should definitely include the ARIA roles to provide these much needed semantics!</p> + +<p>The improved semantics of the search form have shown what is made possible when ARIA goes beyond the semantics available in HTML5. You'll see a lot more about these semantics and the power of ARIA properties/attributes below, especially in the {{anch("Accessibility of non-semantic controls")}} section. For now though, let's look at how ARIA can help with dynamic content updates.</p> + +<h3 id="Dynamic_content_updates">Dynamic content updates</h3> + +<p>Content loaded into the DOM can be easily accessed using a screenreader, from textual content to alternative text attached to images. Traditional static websites with largely text content are therefore easy to make accessible for people with visual impairments.</p> + +<p>The problem is that modern web apps are often not just static text — they tend to have a lot of dynamically updating content, i.e. content that updates without the entire page reloading via a mechanism like <a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a>, <a href="/en-US/docs/Web/API/Fetch_API">Fetch</a>, or <a href="/en-US/docs/Web/API/Document_Object_Model">DOM APIs</a>. These are sometimes referred to as <strong>live regions</strong>.</p> + +<p>Let's look at a quick example — see <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/aria-no-live.html">aria-no-live.html</a> (also <a href="http://mdn.github.io/learning-area/accessibility/aria/aria-no-live.html">see it running live</a>). In this example we have a simple random quote box:</p> + +<pre class="brush: html"><section> + <h1>Random quote</h1> + <blockquote> + <p></p> + </blockquote> +</section></pre> + +<p>Our JavaScript loads a JSON file via <code><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> containing a series of random quotes and their authors. Once that is done, we start up a <code><a href="/en-US/docs/Web/API/WindowTimers/setInterval">setInterval()</a></code> loop that loads a new random quote into the quote box every 10 seconds:</p> + +<pre class="brush: js">var intervalID = window.setInterval(showQuote, 10000);</pre> + +<p>This works OK, but it is not good for accessibility — the content update is not detected by screenreaders, so their users would not know what is going on. This is a fairly trivial example, but just imagine if you were creating a complex UI with lots of constantly updating content, like a chat room, or a strategy game UI, or a live updating shopping cart display — it would be impossible to use the app in any effective way without some kind of way of alerting the user to the updates.</p> + +<p>WAI-ARIA fortunately provides a useful mechanism to provide these alerts — the <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-live">aria-live</a></code> property. Applying this to an element causes screenreaders to read out the content that is updated. How urgently the content is read out depends on the attribute value:</p> + +<ul> + <li><code>off:</code> The default. Updates should not be announced.</li> + <li><code>polite</code>: Updates should be announced only if the user is idle.</li> + <li><code>assertive</code>: Updates should be announced to the user as soon as possible.</li> +</ul> + +<p>We'd like you to take a copy of <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/aria-no-live.html">aria-no-live.html</a> and <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/quotes.json">quotes.json</a>, and update your <code><section></code> tag as follows:</p> + +<pre class="brush: html"><section aria-live="assertive"></pre> + +<p>This will cause a screenreader to read out the content as it is updated.</p> + +<div class="note"> +<p><strong>Note</strong>: Most browsers will throw a security exception if you try to do an <code>XMLHttpRequest</code> call from a <code>file://</code> URL, e.g. if you just load the file by loading it directly into the browser (via double clicking, etc.). To get it to run, you will need to upload it to a web server, for example <a href="/en-US/docs/Learn/Common_questions/Using_Github_pages">using GitHub</a>, or a local web server like <a href="http://www.pythonforbeginners.com/modules-in-python/how-to-use-simplehttpserver/">Python's SimpleHTTPServer</a>.</p> +</div> + +<p>There is an additional consideration here — only the bit of text that updates is read out. It might be nice if we always read out the heading too, so the user can remember what is being read out. To do this, we can add the <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-atomic">aria-atomic</a></code> property to the section. Update your <code><section></code> tag again, like so:</p> + +<pre class="brush: html"><section aria-live="assertive" aria-atomic="true"></pre> + +<p>The <code>aria-atomic="true"</code> attribute tells screenreaders to read out the entire element contents as one atomic unit, not just the bits that were updated.</p> + +<div class="note"> +<p><strong>Note</strong>: You can see the finished example at <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/aria-live.html">aria-live.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/aria/aria-live.html">see it running live</a>).</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: The <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-relevant">aria-relevant</a></code> property is also quite useful for controlling what gets read out when a live region is updated. You can for example only get content additions or removals read out.</p> +</div> + +<h3 id="Enhancing_keyboard_accessibility">Enhancing keyboard accessibility</h3> + +<p>As discussed in a few other places in the module, one of the key strengths of HTML with respect to accessibility is the built-in keyboard accessibility of features such as buttons, form controls, and links. Generally, you are able to use the tab key to move between controls, the Enter/Return key to select or activate controls, and occasionally other controls as needed (for example the up and down cursor to move between options in a <code><select></code> box).</p> + +<p>However, sometimes you will end up having to write code that either uses non-semantic elements as buttons (or other types of control), or uses focusable controls for not quite the right purpose. You might be trying to fix some bad code you've inherited, or you might be building some kind of complex widget that requires it.</p> + +<p>In terms of making non-focusable code focusable, WAI-ARIA extends the <code>tabindex</code> attribute with some new values:</p> + +<ul> + <li><code>tabindex="0"</code> — as indicated above, this value allows elements that are not normally tabbable to become tabbable. This is the most useful value of <code>tabindex</code>.</li> + <li><code>tabindex="-1"</code> — this allows not normally tabbable elements to receive focus programmatically, e.g. via JavaScript, or as the target of links. </li> +</ul> + +<p>We discussed this in more detail and showed a typical implementation back in our HTML accessibility article — see <a href="/en-US/docs/Learn/Accessibility/HTML#Building_keyboard_accessibility_back_in">Building keyboard accessibility back in</a>.</p> + +<h3 id="Accessibility_of_non-semantic_controls">Accessibility of non-semantic controls</h3> + +<p>This follows on from the previous section — when a series of nested <code><div></code>s along with CSS/JavaScript is used to create a complex UI-feature, or a native control is greatly enhanced/changed via JavaScript, not only can keyboard accessibility suffer, but screenreader users will find it difficult to work out what the feature does if there are no semantics or other clues. In such situations, ARIA can help to provide those missing semantics.</p> + +<h4 id="Form_validation_and_error_alerts">Form validation and error alerts</h4> + +<p>First of all, let's revisit the form example we first looked at in our CSS and JavaScript accessibility article (read <a href="/en-US/docs/Learn/Accessibility/CSS_and_JavaScript#Keeping_it_unobtrusive">Keeping it unobtrusive</a> for a full recap). At the end of this section we showed that we have included some ARIA attributes on the error message box that appears when there are validation errors when you try to submit the form:</p> + +<pre class="brush: html"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>div</span> <span class="attr-name token">class</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>errors<span class="punctuation token">"</span></span> <span class="attr-name token">role</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>alert<span class="punctuation token">"</span></span> <span class="attr-name token">aria-relevant</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>all<span class="punctuation token">"</span></span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"><</span>ul</span><span class="punctuation token">></span></span> + <span class="tag token"><span class="tag token"><span class="punctuation token"></</span>ul</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>div</span><span class="punctuation token">></span></span></code></pre> + +<ul> + <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#alert">role="alert"</a></code> automatically turns the element it is applied to into a live region, so changes to it are read out; it also semantically identifies it as an alert message (important time/context sensitive information), and represents a better, more accessible way of delivering an alert to a user (modal dialogs like <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> calls have a number of accessibility problems; see <a href="http://webaim.org/techniques/javascript/other#popups">Popup Windows</a> by WebAIM).</li> + <li>An <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-relevant">aria-relevant</a></code> value of <code>all</code> instructs the screenreader to read out the contents of the error list when any changes are made to it — i.e. when errors are added or removed. This is useful because the user will want to know what errors are left, not just what has been added or removed from the list.</li> +</ul> + +<p>We could go further with our ARIA usage, and provide some more validation help. How about indicating whether fields are required in the first place, and what range the age should be?</p> + +<ol> + <li>At this point, take a copy of our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/css/form-validation.html">form-validation.html</a> and <a href="https://github.com/mdn/learning-area/blob/master/accessibility/css/validation.js">validation.js</a> files, and save them in a local directory.</li> + <li>Open them both in a text editor and have a look at how the code works.</li> + <li>First of all, add a paragraph just above the opening <code><form></code> tag, like the one below, and mark both the form <code><label></code>s with an asterisk. This is normally how we mark required fields for sighted users. + <pre class="brush: html"><p>Fields marked with an asterisk (*) are required.</p></pre> + </li> + <li>This makes visual sense, but it isn't as easy to understand for screenreader users. Fortunately, WAI-ARIA provides the <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-required">aria-required</a></code> attribute to give screenreaders hints that they should tell users that form inputs need to be filled in. Update the <code><input></code> elements like so: + <pre class="brush: html"><input type="text" name="name" id="name" aria-required="true"> + +<input type="number" name="age" id="age" aria-required="true"></pre> + </li> + <li>If you save the example now and test it with a screenreader, you should hear something like "Enter your name star, required, edit text".</li> + <li>It might also be useful if we give screenreader users and sighted users an idea of what the age value should be. This is often presented as a tooltip, or placeholder inside the form field perhaps. WAI-ARIA does include <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-valuemin">aria-valuemin</a></code> and <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-valuemax">aria-valuemax</a></code> properties to specify min and max values, but these currently don't seem very well supported; a better supported feature is the HTML5 <code>placeholder</code> attribute, which can contain a message that is shown in the input when no value is entered, and is read out by a number of screenreaders. Update your number input like this: + <pre class="brush: html"><input type="number" name="age" id="age" placeholder="Enter 1 to 150" aria-required="true"></pre> + </li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: You can see the finished example live at <a href="http://mdn.github.io/learning-area/accessibility/aria/form-validation-updated.html">form-validation-updated.html</a>.</p> +</div> + +<p>WAI-ARIA also enables some advanced form labelling techniques, beyond the classic {{htmlelement("label")}} element. We already talked about using the <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-label">aria-label</a></code> property to provide a label where we don't want the label to be visible to sighted users (see the {{anch("Signposts/Landmarks")}} section, above). There are some other labelling techniques that use other properties such as <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-labelledby">aria-labelledby</a></code> if you want to designate a non-<code><label></code> element as a label or label multiple form inputs with the same label, and <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-describedby">aria-describedby</a></code>, if you want to associate other information with a form input and have it read out as well. See <a href="http://webaim.org/techniques/forms/advanced">WebAIM's Advanced Form Labeling article</a><span class="subtitle"> for more details.</span></p> + +<p><span class="subtitle">There are many other useful properties and states too, for indicating the status of form elements. For example, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-disabled">aria-disabled</a>="true"</code> can be used to indicate that a form field is disabled. Many browsers will just skip past disabled form fields, and they won't even be read out by screenreaders, but in some cases they will be perceived, so it is a good idea to include this attribute to let the screenreader know that a disabled input is in fact disabled.</span></p> + +<p><span class="subtitle">If the disabled state of an input is likely to change, then it is also a good idea to indicate when it happens, and what the result is. For example, in our <a href="http://mdn.github.io/learning-area/accessibility/aria/form-validation-checkbox-disabled.html">form-validation-checkbox-disabled.html</a> demo there is a checkbox that when checked, enables another form input to allow further information be entered. We've set up a hidden live region:</span></p> + +<pre class="brush: html"><p class="hidden-alert" aria-live="assertive"></p></pre> + +<p>which is hidden from view using absolute positioning. When this is checked/unchecked, we update the text inside the hidden live region to tell screenreader users what the result of checking this checkbox is, as well as updating the <code>aria-disabled</code> state, and some visual indicators too:</p> + +<pre class="brush: js">function toggleMusician(bool) { + var instruItem = formItems[formItems.length-1]; + if(bool) { + instruItem.input.disabled = false; + instruItem.label.style.color = '#000'; + instruItem.input.setAttribute('aria-disabled', 'false'); + hiddenAlert.textContent = 'Instruments played field now enabled; use it to tell us what you play.'; + } else { + instruItem.input.disabled = true; + instruItem.label.style.color = '#999'; + instruItem.input.setAttribute('aria-disabled', 'true'); + instruItem.input.removeAttribute('aria-label'); + hiddenAlert.textContent = 'Instruments played field now disabled.'; + } +}</pre> + +<h4 id="Describing_non-semantic_buttons_as_buttons">Describing non-semantic buttons as buttons</h4> + +<p>A few times in this course already, we've mentioned the native accessibilty of (and the accessibility issues behind using other elements to fake) buttons, links, or form elements (see <a href="/en-US/docs/Learn/Accessibility/HTML#UI_controls">UI controls</a> in the HTML accessibility article, and {{anch("Enhancing keyboard accessibility")}}, above). Basically, you can add keyboard accessibility back in without too much trouble in many cases, using <code>tabindex</code> and a bit of JavaScript.</p> + +<p>But what about screenreaders? They still won't see the elements as buttons. If we test our <a href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/accessibility/fake-div-buttons.html">fake-div-buttons.html</a> example in a screenreader, our fake buttons will be reported using phrases like "Click me!, group", which is obviously confusing.</p> + +<p>We can fix this using a WAI-ARIA role. Make a local copy of <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/accessibility/fake-div-buttons.html">fake-div-buttons.html</a>, and add <code><a href="https://www.w3.org/TR/wai-aria-1.1/#button">role="button"</a></code> to each button <code><div></code>, for example:</p> + +<pre><div data-message="This is from the first button" tabindex="0" role="button">Click me!</div></pre> + +<p>Now when you try this using a screenreader, you'll have buttons be reported using phrases like "Click me!, button" — much better.</p> + +<div class="note"> +<p><strong>Note</strong>: Don't forget however that using the correct semantic element where possible is always better. If you want to create a button, and can use a {{htmlelement("button")}} element, you should use a {{htmlelement("button")}} element!</p> +</div> + +<h4 id="Guiding_users_through_complex_widgets">Guiding users through complex widgets</h4> + +<p>There are a whole host of other <a href="https://www.w3.org/TR/wai-aria-1.1/#role_definitions">roles</a> that can identify non-semantic element structures as common UI features that go beyond what's available in standard HTML, for example <code><a href="https://www.w3.org/TR/wai-aria-1.1/#combobox">combobox</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#slider">slider</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tabpanel">tabpanel</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tree">tree</a></code>. You can see a number of userful examples in the <a href="https://dequeuniversity.com/library/">Deque university code library</a>, to give you an idea of how such controls can be made accessible.</p> + +<p>Let's go through an example of our own. We'll return to our simple absolutely-positioned tabbed interface (see <a href="/en-US/docs/Learn/Accessibility/CSS_and_JavaScript#Hiding_things">Hiding things</a> in our CSS and JavaScript accessibility article), which you can find at <a class="external external-icon" href="http://mdn.github.io/learning-area/css/css-layout/practical-positioning-examples/info-box.html">Tabbed info box example</a> (see <a class="external external-icon" href="https://github.com/mdn/learning-area/blob/master/css/css-layout/practical-positioning-examples/info-box.html">source code</a>).</p> + +<p>This example as-is works fine in terms of keyboard accessibility — you can happily tab between the different tabs and select them to show the tab contents. It is also fairly accessible too — you can scroll through the content and use the headings to navigate , even if you can't see what is happening on screen. It is however not that obvious what the content is — a screenreader currently reports the content as a list of links, and some content with three headings. It doesn't give you any idea of what the relationship is between the content. Giving the user more clues as to the structure of the content is always good.</p> + +<p>To improve things, we've created a new version of the example called <a href="https://github.com/mdn/learning-area/blob/master/accessibility/aria/aria-tabbed-info-box.html">aria-tabbed-info-box.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/aria/aria-tabbed-info-box.html">see it running live</a>). We've updated the structure of the tabbed interface like so:</p> + +<pre class="brush: html"><ul role="tablist"> + <li class="active" role="tab" aria-selected="true" aria-setsize="3" aria-posinset="1" tabindex="0">Tab 1</li> + <li role="tab" aria-selected="false" aria-setsize="3" aria-posinset="2" tabindex="0">Tab 2</li> + <li role="tab" aria-selected="false" aria-setsize="3" aria-posinset="3" tabindex="0">Tab 3</li> +</ul> +<div class="panels"> + <article class="active-panel" role="tabpanel" aria-hidden="false"> + ... + </article> + <article role="tabpanel" aria-hidden="true"> + ... + </article> + <article role="tabpanel" aria-hidden="true"> + ... + </article> +</div></pre> + +<div class="note"> +<p><strong>Note</strong>: The most striking change here is that we've removed the links that were originally present in the example, and just used the list items as the tabs — this was done because it makes things less confusing for screenreader users (the links don't really take you anywhere; they just change the view), and it allows the setsize/position in set features to work better — when these were put on the links, the browser kept reporting "1 of 1" all the time, not "1 of 3", "2 of 3", etc.</p> +</div> + +<p>The new features are as follows:</p> + +<ul> + <li>New roles — <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tablist">tablist</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tab">tab</a></code>, <code><a href="https://www.w3.org/TR/wai-aria-1.1/#tabpanel">tabpanel</a></code> — these identify the important areas of the tabbed interface — the container for the tabs, the tabs themselves, and the corresponding tabpanels.</li> + <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-selected">aria-selected</a></code> — Defines which tab is currently selected. As different tabs are selected by the user, the value of this attribute on the different tabs is updated via JavaScript.</li> + <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-hidden">aria-hidden</a></code> — Hides an element from being read out by a screenreader. As different tabs are selected by the user, the value of this attribute on the different tabs is updated via JavaScript.</li> + <li><code>tabindex="0"</code> — As we've removed the links, we need to give the list items this attribute to provide it with keyboard focus.</li> + <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-setsize">aria-setsize</a></code> — This property allows you to specify to screenreaders that an element is part of a series, and how many items the series has.</li> + <li><code><a href="https://www.w3.org/TR/wai-aria-1.1/#aria-posinset">aria-posinset</a></code> — This property allows you to specify what position in a series an element is in. Along with <code>aria-setsize</code>, it provides a screenreader with enough information to tell you that you are currently on item "1 of 3", etc. In many cases, browsers should be able to infer this information from the element hierarchy, but it certainly helps to provide more clues.</li> +</ul> + +<p>In our tests, this new structure did serve to improve things overall. The tabs are now recognised as tabs (e.g. "tab" is spoken by the screenreader), the selected tab is indicated by "selected" being read out with the tab name, and the screenreader also tells you which tab number you are currently on. In addition, because of the <code>aria-hidden</code> settings (only the non-hidden tab ever has <code>aria-hidden="false"</code> set), the non-hidden content is the only one you can navigate down to, meaning the selected content is easier to find.</p> + +<div class="note"> +<p><strong>Note</strong>: If there is anything you explicitly don't want screen readers to read out, you can give them the <code>aria-hidden="true"</code> attribute.</p> +</div> + +<h2 id="Summary">Summary</h2> + +<p>This article has by no means covered all that's available in WAI-ARIA, but it should have given you enough information to understand how to use it, and know some of the most common patterns you will encounter that require it.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://www.w3.org/TR/wai-aria-1.1/#role_definitions">Definition of Roles</a> — ARIA roles reference.</li> + <li><a href="https://www.w3.org/TR/wai-aria-1.1/#state_prop_def">Definitions of States and Properties (all aria-* attributes)</a> — properties and states reference.</li> + <li><a href="https://dequeuniversity.com/library/">Deque university code library</a> — a library of really useful practical examples showing complex UI controls made accessible using WAI-ARIA features.</li> + <li><a href="http://w3c.github.io/aria-practices/">WAI-ARIA Authoring Practices</a> — very detailed design patterns from the W3C, explaining how to implement different types of complex UI control whilst making them accessible using WAI-ARIA features.</li> + <li><a href="https://www.w3.org/TR/html-aria/">ARIA in HTML</a> — A W3C spec that defines, for each HTML feature, what accessibility (ARIA) semantics that feature implicitly has set on it by the browser, and what WAI-ARIA features you may set on it if extra semantics are required.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Accessibility/CSS_and_JavaScript","Learn/Accessibility/Multimedia", "Learn/Accessibility")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/Доступность/What_is_accessibility">Что такое доступность?</a></li> + <li><a href="/ru/docs/Learn/Accessibility/HTML">HTML: Хорошая основа для доступности</a></li> + <li><a href="/ru/docs/Learn/Accessibility/CSS_and_JavaScript">CSS и JavaScript доступность - лучшие практики</a></li> + <li><a href="/ru/docs/Learn/Accessibility/WAI-ARIA_basics">Основы WAI-ARIA</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Multimedia">Доступность мультимедиа</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Mobile">Мобильная доступность</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Accessibility_troubleshooting">Устранение проблем доступности</a></li> +</ul> diff --git a/files/ru/learn/доступность/what_is_accessibility/index.html b/files/ru/learn/доступность/what_is_accessibility/index.html new file mode 100644 index 0000000000..1a6e11f73e --- /dev/null +++ b/files/ru/learn/доступность/what_is_accessibility/index.html @@ -0,0 +1,210 @@ +--- +title: Что такое доступность? +slug: Learn/Доступность/What_is_accessibility +tags: + - CSS + - HTML + - JavaScript + - Изучение + - Клавиатура + - Написание скриптов + - Начинающий + - Программные средства + - Статья + - Считыватель экрана + - вспомогательная технология + - доступность +translation_of: Learn/Accessibility/What_is_accessibility +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Accessibility/HTML", "Learn/Accessibility")}}</div> + +<p class="summary">Данная статья открывает модуль, в котором рассматривается, что такое доступность на самом деле — она включает в себя группы людей, которые нам нужно учитывать и почему, какие инструменты используют разные пользователи для взаимодействия с вебом, и как мы можем сделать доступность частью нашего рабочего процесса веб-разработки.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Узнать, что такое доступность, и как она влияет на вас как на веб-разработчика.</td> + </tr> + </tbody> +</table> + +<h2 id="Итак_что_такое_доступность">Итак, что такое доступность?</h2> + +<p>Доступность — это практика, позволяющая использовать ваши сайты как можно большему числу людей. Мы традиционно думаем об этом как о доступности для людей с ограниченными возможностями, но на самом деле, в это число входят и другие группы пользователей, которые используют мобильные устройства либо имеют медленное сетевое соединение.</p> + +<p>Вы также можете думать о доступности как о способе предоставления равных прав и одинаковых возможностей, независимо от способностей или обстоятельств. Точно так же, как не правильно лишать человека права посещать разнообразные места, только потому что он перемещается в инвалидном кресле (общественные здания в наши дни обычно имеют пандусы для инвалидных колясок или лифты), так и не правильно исключать кого-либо из веб-пространства из-за того, что у них слабое зрение или они используют мобильный телефон. Мы все разные, но все мы люди, и поэтому имеем одинаковые (человеческие) права.</p> + +<p>Помимо того, что доступность это просто хороший тон, она также регулируется законодательством в некоторых странах и может поспособствовать открытию важных рынков, которые в противном случае не смогут использовать ваши услуги, покупать ваши продукты и т. д.</p> + +<p>Доступность и опыт её применения принесут пользу всем:</p> + +<ul> + <li>Семантический HTML (который улучшает доступность) также улучшает SEO, делая ваш сайт более доступным для поиска или продажи.</li> + <li>Забота о доступности демонстрирует хорошую этику и мораль, что улучшает ваш имидж в обществе.</li> + <li>Другие хорошие практики, улучшающие доступность, также делают сайт более удобным для использования другими группами, такими как пользователи мобильных телефонов, пользователи с низкой скоростью сети и т.д. На самом деле, каждый может извлечь выгоду из многих таких улучшений.</li> + <li>Мы упоминали, что это также закон в некоторых местах?</li> +</ul> + +<h2 id="Какие_виды_ограниченных_возможностей_мы_рассматриваем">Какие виды ограниченных возможностей мы рассматриваем?</h2> + +<p>Люди с ограниченными возможностями так же разнообразны, как и люди без них, так и своими недостатками. Ключевой урок заключается в том, чтобы думать за пределами вашего собственного компьютера и того, как вы используете Интернет, и начать изучать как его используют другие — <em>вы не ваши пользователи. </em>Ниже разъясняются основные виды инвалидности, а также любые специализированные инструменты, которые используются для доступа к веб-контенту (известные как <strong>вспомогательные технологии</strong>).</p> + +<div class="note"> +<p><strong>Примечание</strong>: в информационном бюллетене Всемирной организации здравоохранения по вопросам <a class="external external-icon" href="https://www.who.int/ru/news-room/fact-sheets/detail/disability-and-health">Инвалидности и Здоровья</a> говорится, что "Более 1 миллиарда людей, около 15% населения мира, имеют какую-либо форму инвалидности" и "От 110 до 190 миллионов взрослых испытывают значительные трудности в функционировании."</p> +</div> + +<h3 id="Люди_с_нарушениями_зрения">Люди с нарушениями зрения</h3> + +<p>Сюда относятся люди со слепотой, слабым зрением, дальтонизмом и другие. Многие из этих людей используют экранные лупы (либо физические лупы, либо программные возможности масштабирования — большинство браузеров и операционных систем в наши дни имеют возможности масштабирования), а некоторые будут использовать программы чтения с экрана, то есть программное обеспечение, которое читает цифровой текст вслух:</p> + +<ul> + <li>Некоторые платные коммерческие продукты, такие как <a class="external external-icon" href="http://www.freedomscientific.com/Products/Blindness/JAWS">JAWS</a> (Windows) и <a class="external external-icon" href="http://www.gwmicro.com/window-eyes/">Window Eyes</a> (Windows).</li> + <li>Некоторые бесплатные продукты, такие как <a class="external external-icon" href="http://www.nvaccess.org/">NVDA</a> (для Windows), <a class="external external-icon" href="http://www.chromevox.com/">ChromeVox</a> (браузер Chrome, Windows и Mac ОС Х) и <a class="external external-icon" href="https://wiki.gnome.org/Projects/Orca">Orca</a> (Linux).</li> + <li>Некоторые из них встроены в операционную систему, например <a class="external external-icon" href="http://www.apple.com/accessibility/osx/voiceover/">VoiceOver</a> (Mac OS X и iOS), <a class="external external-icon" href="https://support.microsoft.com/en-us/help/22798/windows-10-narrator-get-started">Экранный диктор</a>(<a class="external external-icon" href="https://support.microsoft.com/en-us/help/22798/windows-10-narrator-get-started">Narrator</a>) (Microsoft Windows), <a class="external external-icon" href="http://www.chromevox.com/">ChromeVox</a> (в Chrome OS) и <a class="external external-icon" href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">TalkBack</a> (Android).</li> +</ul> + +<p>Хорошая идея ознакомиться с экранными дикторами; вы можете настроить экранный считыватель и поиграть с ним, чтобы получить представление о том, как это работает. Более подробную информацию об их использовании см. в <a href="/ru/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">руководстве по кросс-браузерному тестированию</a>. Видео ниже предоставляет краткий пример взаимодействия с экранными читателями.</p> + +<p>{{EmbedYouTube("IK97XMibEws")}}</p> + +<p> </p> + +<p>Что касается статистики: по оценкам Всемирной Организации Здравоохранения: "285 миллионов человек во всем мире страдают нарушениями зрения: 39 миллионов слепы и 246 имеют слабовидение." (см. <a class="external external-icon" href="http://www.who.int/ru/news-room/fact-sheets/detail/blindness-and-visual-impairment">Нарушения зрения и слепота</a>). Это большая и значительная группа пользователей, которые просто упущены, потому что ваш сайт не закодирован должным образом — почти такой же размер, как и население Соединенных Штатов Америки.</p> + +<h3 id="Люди_с_нарушениями_слуха">Люди с нарушениями слуха</h3> + +<p>Эта группа людей либо имеет низкий уровень слуха, либо вообще не слышит. Люди с нарушениями слуха используют ATs (см. <a class="external external-icon" href="https://www.nidcd.nih.gov/health/assistive-devices-people-hearing-voice-speech-or-language-disorders">Вспомогательные устройства для людей с нарушениями слуха, голоса, речи или языка</a>), но на самом деле нет специальных ATs, специфичных для использования на компьютере или в интернете.</p> + +<p>Однако существуют специальные техники, которые следует учитывать для предоставления текстовых альтернатив аудиоконтенту, который люди смогут читать, от простых текстовых транскриптов до текстовых дорожек (т.е. подписей), которые могут отображаться вместе с видео. Об этом будет рассказано в статье позже.</p> + +<p>Люди с нарушениями слуха представляют значительную базу пользователей — "360 миллионов человек в мире страдают от инвалидизирующей потери слуха", — говорится в информационном бюллетене Всемирной Организации Здравоохранения о <a class="external external-icon" href="https://www.who.int/ru/news-room/fact-sheets/detail/deafness-and-hearing-loss">Глухоте и потере слуха</a>.</p> + +<h3 id="Люди_с_ограниченными_физическими_возможностями">Люди с ограниченными физическими возможностями </h3> + +<p>Это группа людей, которые имеют инвалидность в отношении движения, которая может включать в себя чисто физические проблемы (такие как потеря конечности или паралич), или неврологические/генетические расстройства, которые приводят к слабости или потере контроля в конечностях. Некоторые люди могут испытывать трудности с выполнением точных движений рук, необходимых для использования мыши, в то время как другие могут быть более серьезно затронуты, возможно, значительно парализованы до такой степени, что им нужно использовать <a class="external external-icon" href="https://www.performancehealth.com/baseball-cap-head-pointer">указатель головы</a> для взаимодействия с компьютером.</p> + +<p>Этот вид инвалидности также может быть результатом старости, а не какой-либо конкретной травмы или состояния, а также может быть результатом аппаратных ограничений — у некоторых пользователей может не быть мыши.</p> + +<p>Управление элементами с помощью клавиатуры является обычным требованием, которое влияет на процесс веб-разработки — мы обсудим доступ с клавиатруы в последующих статьях модуля. Хорошая идея, чтобы попробовать пользоваться веб-сайтами, только с помощью клавиатуры, чтобы увидеть, что из этого выйдет и как это работает. Например, можно ли использовать клавишу Tab для перемещения между различными элементами управления веб-формы? Вы можете найти больше деталей об использовании клавиатуры в нашей секции <a href="/ru/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Using_native_keyboard_accessibility">Cross browser testing Using native keyboard accessibility</a>.</p> + +<p>С точки зрения статистики, значительное количество людей имеют нарушения мобильности. Центры США по контролю и профилактике заболеваний <a class="external external-icon" href="http://www.cdc.gov/nchs/fastats/disability.htm">Инвалидности и Функционирования (Неинституционализированные взрослые в возрасте 18 лет и старше)</a> сообщают, что в США "Процент взрослых с любым физическим нарушением функционирования: 16,1%".</p> + +<h3 id="Люди_с_когнитивными_нарушениями">Люди с когнитивными нарушениями</h3> + +<p>Вероятно, самый широкий спектр инвалидности можно увидеть в этой категории — когнитивные нарушения в широком смысле могут относиться к инвалидности от психических заболеваний до трудностей в обучении, трудности в понимании и концентрации, такие как <a class="external external-icon" href="https://www.nimh.nih.gov/health/topics/attention-deficit-hyperactivity-disorder-adhd/index.shtml">СДВГ (синдром дефицита внимания и гиперактивности)</a>, людям <a class="external external-icon" href="https://www.nimh.nih.gov/health/topics/autism-spectrum-disorders-asd/index.shtml">аутистического спектра</a>, людям с <a class="external external-icon" href="https://www.nimh.nih.gov/health/topics/schizophrenia/index.shtml">шизофренией</a>, и множество других типов нарушений. Такие недостатки могут повлиять на многие детали повседневной жизни из-за проблем с памятью, решением, пониманием, вниманием и т. д.</p> + +<p>Наиболее распространенные способы, вызванные когнитивными нарушениями, которые могут повлиять на использование веб-сайта — трудности с пониманием того, как выполнить задачу; вспомнить, как сделать что-то, что было ранее выполнено; повышенное разочарование в запутанных рабочих процессах или непоследовательных макетах/навигации/других функциях страницы.</p> + +<p>В отличие от других проблем доступности интернета, невозможно назначить быстрые исправления для многих проблем доступности, связанных с когнитивными нарушениями; лучшее решение, которое у вас есть — это проектировать веб-сайты таким образом, чтобы они были логичными, последовательными и удобными для использования настолько, насколько это возможно. Например, убедитесь, что:</p> + +<ul> + <li>страницы согласованы — навигация, шапка и подвал (хедер и футер), а так же главный контент всегда находятся в одном месте.</li> + <li>инструменты хорошо разработаны и просты в использовании.</li> + <li>многоступенчатые процессы разбиты на логические этапы, с регулярными напоминаниями о том, как далеко вы прошли, и сколько осталось до завершения процесса, если это необходимо.</li> + <li>рабочие процессы логичны, просты и требуют как можно меньше взаимодействий. Например, регистрация и вход на веб-сайт зачастую неоправданно сложны.</li> + <li>страницы не слишком длинные или плотные с точки зрения количества информации, представленной сразу.</li> + <li>язык, используемый на ваших страницах, настолько прост и удобен, насколько это возможно, и не полон ненужного жаргона и сленга.</li> + <li>важные моменты и контент выделены некоторым способом.</li> + <li>ошибки пользователя четко выделены, с подсказкой и предлагаемым решением.</li> +</ul> + +<p>Это не "методы доступности" как таковые — это хорошая практика проектирования. Они принесут пользу всем, кто использует ваши сайты, и должны быть стандартной частью вашей работы.</p> + +<p>С точки зрения статистики, опять же цифры значительны. Отчет Корнелльского университета <a class="external external-icon" href="http://www.disabilitystatistics.org/StatusReports/2014-PDF/2014-StatusReport_US.pdf">О состоянии инвалидности за 2014 год</a> (PDF, 511 КБ)(en) показывает, что в 2014 году 4,5% людей в США в возрасте 21-64 лет имели ту или иную форму когнитивной инвалидности.</p> + +<div class="note"> +<p><strong>Примечание</strong>: <a href="http://webaim.org/articles/cognitive/">Страница о когнитивных расстройствах</a> на WebAIM обепечивает полезное распространение этих идей, и это, безусловно, стоит прочитать.</p> +</div> + +<h2 id="Реализация_доступности_в_проекте">Реализация доступности в проекте</h2> + +<p>Распространенный миф о доступности заключается в том, что доступность является дорогостоящим "дополнением" для реализации проекта. Этот миф на самом деле может быть правдой, если:</p> + +<ul> + <li>Вы пытаетесь "модифицировать" доступность на существующем сайте, который имеет значительные проблемы в этом плане.</li> + <li>Вы только начали рассматривать доступность и непокрытые смежные вопросы на последних этапах проекта.</li> +</ul> + +<p>Если вы рассматриваете доступность с самого начала проекта, то стоимость создания доступного контента должна быть весьма небольшой.</p> + +<p>При планировании проекта учитывайте тестирование доступности в своём режиме тестирования, как при тестировании любого другого важного сегмента целевой аудитории (например, настольный или мобильный браузер). Тестируйте на ранних этапах и часто, выполняя автоматические тесты, чтобы выявить программно обнаруживаемые отсутствующие функции (такие как отсутствующий <a href="https://developer.mozilla.org/ru/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Text_alternatives">альтернативный текст</a> изображения или неправильная ссылка — см. <a href="/ru/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Element_relationships_and_context">Element relationships and context</a>), и тестируйте с некоторыми нетрудоспособными групами пользователей, чтобы увидеть, насколько хорошо для них работают более сложные функции сайта. Например:</p> + +<ul> + <li>Может ли мой виджет выбора даты использоваться людьми, использующими программы чтения с экрана?</li> + <li>Если контент обновляется динамически, знают ли об этом люди с ослабленным зрением?</li> + <li>Мои интефейсные кнопки доступны с помощью клавиатуры и сенсорного интерфейса?</li> +</ul> + +<p>Вы можете и должны хранить заметку о потенциальных проблемных местах в контенте, которые будут нуждаться в доработке, чтобы сделать их доступыми, убедитесь, что они тщательно протестированы, и подумайте о решениях/альтернативах. Текстовый контент (как вы увидите в следующей статье) довольно прост, но как насчет вашего мультимедийного контента, и красивой 3D-графики? Вы должны смотреть на свой бюджет проекта и реально думать о том, какие решения у вас есть, чтобы сделать такой контент доступным? Вы можете заплатить за расшифровку всего вашего мультимедийного контента, это может быть дорогостоящим, но будет сделано.</p> + +<p>Кроме того, будьте реалистами. "100% доступность" является недостижимым идеалом — вы всегда столкнетесь с каким-то случаем, который приводёт к тому, что определенный пользователь найдёт определенный контент трудным в использовании, но вы должны сделать столько, сколько сможете. Если вы планируете использовать трехмерную круговую диаграмму, созданную с помощью WebGL, вы можете включить таблицу данных в качестве доступного альтернативного представления данных. Или, вы можете просто включить таблицу и избавиться от 3D круговой диаграммы-таблица доступна для всех, быстрее кодировать, меньше ресурсов процессора, и проще в обслуживании.</p> + +<p>С другой стороны, если вы работаете на веб-сайте галереи с интересным трехмерным искусством, было бы неразумно ожидать, что каждое произведение искусства будет идеально доступно для людей с нарушениями зрения, учитывая, что это полностью визуальная среда.</p> + +<p>Чтобы показать, что вы заботитесь о доступности и думали о ней, опубликуйте на своем сайте заявление о доступности, в котором подробно излагается, какова ваша политика в отношении доступности, и какие шаги вы предприняли для обеспечения доступности сайта. Если кто-то жалуется, что у вашего сайта есть проблема с доступностью, начните с ним диалог, проявите сочувствие и примите разумные меры, чтобы попытаться устранить проблему.</p> + +<div class="note"> +<p><strong>Note</strong>: В нашей статье <a href="https://developer.mozilla.org/ru/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Text_alternatives">«Об общих проблемах доступности»</a> рассматриваются особенности доступности, которые необходимо протестировать более подробно.</p> +</div> + +<p>Подведём итоги:</p> + +<ul> + <li>Думайте о доступности с самого начала проекта, тестируйте рано и часто. Как и любая другая ошибка, проблема доступности становится более дорогой, чтобы исправлять её позже.</li> + <li>Имейте в виду, что многие рекомендации по доступности выгодны всем, а не только пользователям с ограниченными возможностями. Например, семантическая разметка полезна не только для программ чтения с экрана, но и для быстрой загрузки и повышения производительности, так лучше для всех, особенно для мобильных устройств, и/или для медленных соединений.</li> + <li>Опубликуйте заявление о доступности на своем сайте и общайтесь с людьми, у которых есть проблемы.</li> +</ul> + +<h2 id="Руководство_по_доступности_и_закон">Руководство по доступности и закон</h2> + +<p>Существует множество чеклистов и наборов руководств, на которых можно основываться при тестировании доступности, которые на первый взгляд могут показаться ошеломляющими. Наш совет — ознакомиться с основными областями, о которых вам необходимо позаботиться, а также понять структуры руководящих принципов, которые наиболее актуальны для вас.</p> + +<ul> + <li>Для начала, W3C опубликовал большой и очень подробный документ, который включает в себя очень точные, независимые от технологии критерии соответствия доступности. Они называются <a class="external external-icon" href="https://www.w3.org/Translations/WCAG20-ru/WCAG20-ru-20130220/">Рекомендациями по доступности веб-контента</a> (<a class="external external-icon" href="https://www.w3.org/WAI/intro/wcag.php">Web Content Accessibility Guidelines</a> — WCAG), и они никоим образом не являются кратким описанием. Критерии разделяются на четыре основные категории, которые определяют, как реализации можно сделать восприимчивыми, работоспособными, понятными и устойчивыми. Лучшее место, чтобы получить легкое представление и начать обучение это <a class="external external-icon" href="https://www.w3.org/WAI/WCAG20/glance/Overview.html">WCAG at a Glance</a>. Нет необходимости изучать WCAG наизусть — знайте об основных проблемных областях и используйте различные методы и инструменты, чтобы выделить любые области, которые не соответствуют критериям WCAG (подробнее см. ниже).</li> + <li>В вашей стране также может быть предусмотрено специальное законодательство, регулирующее необходимость обеспечения доступности веб-сайтов, обслуживающих их население, например, <a class="external external-icon" href="http://www.section508.gov/content/learn">Раздел 508 Закона о реабилитации</a> в США, <a class="external external-icon" href="https://www.einfach-fuer-alle.de/artikel/bitv_english/">Федеральное постановление о безбарьерных информационных технологиях</a> в Германии, <a class="external external-icon" href="http://www.legislation.gov.uk/ukpga/2010/15/contents">Закон о равенстве</a> в Великобритании, <a class="external external-icon" href="http://www.agid.gov.it/agenda-digitale/pubblica-amministrazione/accessibilita">Accessibilità</a> в Италии, <a class="external external-icon" href="https://www.humanrights.gov.au/world-wide-web-access-disability-discrimination-act-advisory-notes-ver-41-2014">Закон о дискриминации инвалидов</a> в Австралии и т.д.</li> +</ul> + +<p>Поэтому, хотя WCAG представляет собой набор руководств, в вашей стране, вероятно, будут приняты законы, регулирующие доступность веба или, по крайней мере, доступность обществественных услуг (которые могут включать в себя веб-сайты, телевидение, физические пространства и т.д.). Это хорошая идея — узнать, каковы ваши законы. Если вы не предпримете никаких усилий, чтобы проверить, что ваш контент доступен, у вас могут возникнуть проблемы с законом, если люди с ограниченными возможностями жалуются на это.</p> + +<p>Это звучит серьезно, но на самом деле вам просто нужно рассматривать доступность в качестве основного приоритета вашей практики веб-разработки, как описано выше. В случае сомнений обратитесь за советом к квалифицированному юристу. Мы не собираемся предлагать больше советов, чем эти, потому что мы не юристы.</p> + +<h2 id="Специальные_API_доступа">Специальные API доступа</h2> + +<p>Веб-браузеры используют <strong>специальные API доступа</strong> (предоставляемые базовой операционной системой) которые предоставляют информацию, полезную для вспомогательных технологий (AT). AT обычно используют семантическую информацию, поэтому эта информация не включает такие вещи, как информация о стилях или JavaScript. Эта информация структурирована в дереве информации, которое называется <strong>деревом доступности</strong>.</p> + +<p>Различные операционные системы имеют разные API доступа:</p> + +<ul> + <li>Windows: MSAA/IAccessible, UIAExpress, IAccessible2</li> + <li>Mac OS X: NSAccessibility</li> + <li>Linux: AT-SPI</li> + <li>Android: Accessibility framework</li> + <li>iOS: UIAccessibility</li> +</ul> + +<p>Там, где нативная семантическая информация, предоставляемая элементами HTML в ваших веб-приложениях, падает, вы можете дополнить ее функциями из <a class="external" href="https://www.w3.org/TR/wai-aria/">спецификации WAI-ARIA</a>, которые добавляют семантическую информацию в дерево доступности для улучшения доступности. Вы можете узнать больше о WAI-ARIA в нашей статье <a href="/ru/docs/Learn/Accessibility/WAI-ARIA_basics">основы WAI-ARIA</a>.</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Эта статья должна была дать вам полезный обзор специальных возможностей, показать, почему это так важно, и посмотреть, как вы можете вписать его в свой рабочий процесс. Теперь у вас также должна быть жажда узнать о деталях реализации, которые помогут сделать сайты доступными, и мы начнем с этого в следующем разделе, рассматривая, почему HTML является хорошей основой для доступности.</p> + +<p>{{NextMenu("Learn/Accessibility/HTML", "Learn/Accessibility")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/Доступность/What_is_accessibility">Что такое доступность?</a></li> + <li><a href="/ru/docs/Learn/Accessibility/HTML">HTML: Хорошая основа для доступности</a></li> + <li><a href="/ru/docs/Learn/Accessibility/CSS_and_JavaScript">CSS и JavaScript доступность - лучшие практики</a></li> + <li><a href="/ru/docs/Learn/Accessibility/WAI-ARIA_basics">Основы WAI-ARIA</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Multimedia">Доступность мультимедиа</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Mobile">Мобильная доступность</a></li> + <li><a href="/ru/docs/Learn/Accessibility/Accessibility_troubleshooting">Устранение проблем доступности</a></li> +</ul> diff --git a/files/ru/learn/как_сделать_вклад/index.html b/files/ru/learn/как_сделать_вклад/index.html new file mode 100644 index 0000000000..caed3b7970 --- /dev/null +++ b/files/ru/learn/как_сделать_вклад/index.html @@ -0,0 +1,85 @@ +--- +title: Как сделать вклад в Обучающую Зону MDN +slug: Learn/Как_сделать_вклад +tags: + - Вклад + - Документация + - Новичку + - Новичок + - Обучение + - Правила + - Руководство +translation_of: Learn/How_to_contribute +--- +<div>{{LearnSidebar}}</div> + +<p>Оказались ли вы здесь впервые или в результате глубокого поиска, вас, вероятно, привело сюда желание помочь Обучающей Зоне MDN. И это отличная новость!</p> + +<p><span class="seoSummary">На этой странице вы найдёте всё необходимое для того, чтобы помочь улучшить обучающий контент MDN. Здесь есть много вещей, которые вы можете сделать, в зависимости от того, сколько времени у вас есть и кем вы являетесь <a href="#Я_новичок">новичком</a>, <a href="#Я_веб_разработчик">веб-разработчиком</a> или <a href="#Я_учитель">учителем</a>.</span></p> + +<div class="note"> +<p>Руководство по написанию новой статьи в обучающем пространстве можно посмотреть на странице <a href="https://developer.mozilla.org/en-US/docs/MDN/Contribute/Howto/Write_an_article_to_help_learn_about_the_Web">How to write an article to help people learn about the Web</a>.</p> +</div> + +<h2 id="Найдите_конкретные_задачи">Найдите конкретные задачи</h2> + +<p><strong>Для организации своих задач участники сообщества используют <a href="https://trello.com/b/LDggrYSV">Trello board</a>. Там вы можете найти конкретные задачи проекта, ожидающие выполнения. Если вы хотите использовать её, просто <a href="https://trello.com/signup">создайте Trello аккаунт</a> и напишите Chris Mills, чтобы он дал доступ к записи на доску.</strong></p> + +<p>Принятие участия - это также отличный способ повеселиться, одновременно изучая новое. Если вы запутались или у вас есть вопросы, не стесняйтесь написать нам в <a href="/en-US/docs/MDN/Community#Join_our_mailing_lists">наш список рассылки</a> или <a href="/en-US/docs/MDN/Community#Get_into_IRC">IRC канал</a> (подробности указаны внизу этой страницы). <a href="https://developer.mozilla.org/en-US/profiles/chrisdavidmills">Chris Mills</a> заведует Обучающей Зоной — вы также можете попробовать написать ему напрямую.</p> + +<p>В следующих разделах описаны некоторые идеи касательно задач, которыми вы могли бы заняться.</p> + +<h2 id="Я_новичок">Я новичок</h2> + +<p>Это круто! Новички очень важны для создания и предоставления отзывов об материалах для обучения. Ваш уникальный взгляд представителя целевой аудитории данных статей может сделать вас бесценным участником нашей команды. В самом деле, если вы "застряли" в процессе изучения какой-либо темы по одной из наших статей, или находите эту статью в некотором роде запутанной, вы можете либо исправить её сами, либо сообщить об этой проблеме нам, чтобы мы позаботились о её исправлении.</p> + +<p>Вот как, например, вы можете помочь:</p> + +<dl> + <dt><a href="/ru/docs/MDN/Contribute/Howto/Tag">Добавьте теги к нашим статьям</a> (<em>5 мин</em>)</dt> + <dd>Добавление тегов к контенту MDN - один из самых легких способов внести свой вклад. Помощь в этом направлении очень ценна, поскольку теги широко применяются в MDN, чтобы вписать информацию в контекст. Начать можно с просмотра списков <a href="/en-US/docs/MDN/Doc_status/Glossary#No_tags">словарных</a> и <a href="/en-US/docs/MDN/Doc_status/Learn#No_tags">обучающих статей</a>.</dd> + <dt><a href="/ru/docs/Словарь">Прочитайте и проверьте статью в словаре</a> (<em>5 мин</em>)</dt> + <dd>Нам очень важен ваш взгляд, как начинающего, на наш контент. Если вы считаете, что статья в словаре слишком сложна, значит, её необходимо улучшить. Не стесняйтесь вносить любые необходимые, на ваш взгляд, изменения. Если вам кажется, что у вас недостаточно навыков, чтобы самостоятельно отредактировать статью, можете сообщить нам о ней в нашем <a href="/en-US/docs/MDN/Community#Join_our_mailing_lists">списке рассылки</a>.</dd> + <dt><a href="ru/MDN/Contribute/Howto/Write_a_new_entry_in_the_Glossary">Напишите новую статью для словаря</a> (<em>20 минут</em>)</dt> + <dd>Это самый эффективный способ узнать что-то новое. Выберите понятие, которое вам хотелось бы изучить, и в процессе изучения пишите о нем статью для словаря. Объяснить какую-либо вещь другим - отличный способ закрепить знание в голове, и разобраться самому, при этом помогая другим. Everybody wins!</dd> + <dt><a href="/en-US/Learn/Index">Прочитайте и проверьте обучающую статью</a> (<em>2 часа</em>)</dt> + <dd>Эта задача очень похожа на проверку статей в словаре (см. выше), она лишь занимает больше времени, поскольку обычно такие статьи значительно длиннее.</dd> +</dl> + +<h2 id="Я_веб-разработчик">Я веб-разработчик</h2> + +<p>Фантастика! Ваши технические навыки - именно то, что помогает нам убедиться в технической точности контента для новичков. Поскольку данная конкретная часть MDN посвящена обучению Вебу, постарайтесь делать ваши объяснения максимально простыми, но не чересчур простыми, они не должны стать бесполезны. Понятность важнее, чем чрезмерная точность.</p> + +<dl> + <dt><a href="/ru/docs/Словарь">Прочитайте и проверьте статью в словаре</a> (<em>5 мин</em>)</dt> + <dd>Нам важно, чтобы вы, как веб-разработчик, убедились в том, что наш контент технически точен, но при этом не слишком сложен. Не стесняйтесь делать любые изменения, которые вам покажутся нужными. Если вы хотите обсудить контент до того, как приступать к редактированию, напишите нам в <a href="/en-US/docs/MDN/Community#Join_our_mailing_lists">список рассылки</a> или <a href="/en-US/docs/MDN/Community#Get_into_IRC">IRC канал</a>.</dd> + <dt><a href="/docs/MDN/Contribute/Howto/Write_a_new_entry_in_the_Glossary">Напишите новую статью для словаря </a>(<em>20 минут</em>)</dt> + <dd>Разъяснение технического жаргона - хороший способ научиться быть одновременно технически точным и простым. Новички будут вам за это благодарны. У нас есть <a href="/en-US/docs/Glossary#Contribute">много терминов без определений</a>, которые нуждаются в вашем внимании. Выберите один и приступайте!</dd> + <dt><a href="/en-US/Learn/Index">Прочитайте и проверьте обучающую статью</a> (<em>2 часа</em>)</dt> + <dd>Это тоже самое, что и проверка статьи в словаре (см.выше), но занимает больше времени, поскольку обычно такие статьи значительно длиннее.</dd> + <dt><a href="/en-US/docs/MDN/Contribute/Howto/Write_an_article_to_help_learn_about_the_Web">Напишите новую обучающую статью</a> (<em>4 часа или больше</em>)</dt> + <dd>MDN не хватает ясных и доходчивых статей об использовании веб-технологий (<a href="/en-US/docs/Learn/CSS">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>, и т.д). Кроме того, у нас есть старый контент, который нуждается в редактуре и изменениях. Доведите ваши умения до предела, чтобы сделать веб-технологии пригодными для использования даже начинающими.</dd> + <dt><a href="/en-US/docs/MDN/Contribute/Howto/Create_an_interactive_exercise_to_help_learning_the_web">Создайте упражнения, примеры кода или интерактивные обучающие инструменты</a> (<em>? часов</em>)</dt> + <dd>Все наши обучающие статьи требуют материалов, как мы это называем, "активного обучения", так как эффективнее всего люди учатся, выполняя что-либо самостоятельно. Под такого рода материалами подразумеваются упражнения или интерактивный контент, которые помогают пользователю применять и оперировать понятиями, описанными в статье. Существует множество способов создания контента активного обучения, от написания образцов кода с помощью <a href="http://jsfiddle.net" rel="external">JSFiddle</a> или подобных инструментов, до построения fully hackable интерактивного контента в <a href="https://thimble.mozilla.org/" rel="external">Thimble</a>. Раскройте ваш творческий потенциал!</dd> +</dl> + +<h2 id="Я_учитель">Я учитель</h2> + +<p>У MDN долгая история совершенствования в техническом плане, но нам не хватает глубины понимания того, как лучше обучать новичков. Именно на этом этапе мы нуждаемся в вас, как в преподавателях и педагогах. Вы можете помочь нам гарантировать, что наши материалы обеспечивают хороший, практикоориентированный образовательный путь для наших читателей.</p> + +<dl> + <dt><a href="/ru/docs/Словарь">Прочитайте и проверьте статью в словаре</a> (<em>15 мин</em>)</dt> + <dd>Просмотрите словарную статью и не стесняйтесь вносить любые необходимые, на ваш взгляд, изменения. Если вы хотели бы обсудить контент перед тем, как редактировать, напишите нам в наш <a href="/en-US/docs/MDN/Community#Join_our_mailing_lists">список рассылки</a> или <a href="/en-US/docs/MDN/Community#Get_into_IRC">IRC канал</a>.</dd> + <dt><a href="/docs/MDN/Contribute/Howto/Write_a_new_entry_in_the_Glossary">Напишите новую статью для словаря</a> (<em>1 час</em>)</dt> + <dd>Новички очень нуждаются в ясных, простых определениях терминов и базовом обзоре понятий в словаре. Ваш педагогический опыт может помочь нам создать превосходные словарные статьи; у нас есть <a href="/en-US/docs/Glossary#Contribute">множество терминов без определений</a>, которые нуждаются в вашем внимании. Выбирайте один из них и приступайте.</dd> + <dt><a href="/en-US/docs/tag/needsSchema">Добавьте илллюстрации и/или схемы в статью</a> (<em>1 час</em>)</dt> + <dd>Как вам, наверное, известно, иллюстрации - бесценная часть любого обучающего материала. Зачастую именно их нам не хватает на MDN, и ваши навыки могут улучшить ситуацию в данной области. Посмотрите список статей, у которых <a href="/en-US/docs/tag/needsSchema">отсутствует иллюстративный материал</a>, и выберите одну, к которой вам бы хотелось создать графику.</dd> + <dt><a href="/en-US/Learn/Index">Прочитайте и проверьте обучающую статью</a> (<em>2 часа</em>)</dt> + <dd>Это тоже самое, что и проверка статьи в словаре (см.выше), но занимает больше времени, поскольку обычно такие статьи значительно длиннее.</dd> + <dt><a href="/en-US/docs/MDN/Contribute/Howto/Write_an_article_to_help_learn_about_the_Web">Напишите новую обучающую статью</a> (<em>4 часа</em>)</dt> + <dd>Нам нужны простые, доходчивые статьи о Web экосистеме и прочих практических темах в связанных областях. Поскольку данные обучающие статьи должны быть скорее образовательными, чем охватывать целиком всю имеющуюся информацию, ваш опыт касательно того, что именно нужно осветить и как, будет очень ценен.</dd> + <dt><a href="/en-US/docs/MDN/Contribute/Howto/Create_an_interactive_exercise_to_help_learning_the_web">Создайте упражнения, <abbr title="Multiple Choice Tests">викторины</abbr> или интерактивные обучающие инструменты</a> (<em>? часа</em>)</dt> + <dd>Все наши обучающие статьи требуют материалов "активного обучения", то есть упражнений или интерактивного контента, которые помогают пользователю углубиться и научиться использовать концепции, описанные в статье. В этой области вы можете сделать многое, от создания викторин до построения fully hackable интерактивного контента с <a href="https://thimble.mozilla.org/" rel="external">Thimble</a>. Раскройте вашу творческую сторону!</dd> + <dt><a href="/en-US/docs/MDN/Contribute/Howto/Create_learning_pathways">Создайте пути обучения</a> (<em>? часа</em>)</dt> + <dd>Чтобы предоставить прогрессивные и доступные для понимания руководства, нам необходимо объединять контент в пути. Это способ собрать существующий контент и выяснить, чего в нем недостает для написания обучающей статьи.</dd> +</dl> diff --git a/files/ru/learn/фронтенд_разработчик/index.html b/files/ru/learn/фронтенд_разработчик/index.html new file mode 100644 index 0000000000..c219d6a069 --- /dev/null +++ b/files/ru/learn/фронтенд_разработчик/index.html @@ -0,0 +1,195 @@ +--- +title: Фронтенд разработчик +slug: Learn/Фронтенд_разработчик +tags: + - Начинающий + - Стандарты веб-разработки + - Фронт-енд +translation_of: Learn/Front-end_web_developer +--- +<p>{{learnsidebar}}<br> + <br> + Добро пожаловать на курс обучения Фронтенд разработчика!<br> + <br> + Здесь мы предлагаем вам структурированный курс, который научит вас всему, что вам необходимо знать, чтобы стать фронтенд разработчиком. Изучение в рекомендуемом порядке каждого раздела позволит получить новые навыки, или улучшить имеющиеся. Также в каждом разделе вы найдете упражнения и тесты. Прежде чем переходить к следующей теме обязательно проверьте себя.</p> + +<h2 id="Основные_темы">Основные темы:</h2> + +<p>В курсе рассматриваются темы:</p> + +<ul> + <li>Базовая настройка и как правильно проходить курс</li> + <li>Веб-стандарты и лучшие решения (такие как доступность и кросс-браузерная совместимость)</li> + <li>HTML, язык, описывающий структуру и смысл контента</li> + <li>CSS, язык, используемый для оформления страниц</li> + <li>JavaScript, язык сценариев, используемый для создания динамических функций в веб содержимом</li> + <li>Инструменты, используемые для облегчения современной веб-разработки на стороне клиента.</li> +</ul> + +<p>Различные разделы предназначены для проработки по порядку, но каждый из них также самодостаточен. Если вы, к примеру, уже хорошо знакомы с HTML, то можете перейти к разделу CSS.</p> + +<h2 id="Необходимые_условия">Необходимые условия</h2> + +<p>Вам не нужно никаких предварительных знаний, чтобы начать этот курс. Всё, что вам необходимо – это компьютер, который может работать с современными браузерами, интернет соединение и готовность учиться.<br> + <br> + Если вы не уверены, подходит ли вам фронтент разработка и/или вы хотите получить подробное представление, то прежде чем начинать полный курс, вам следует сначала изучить наш раздел <a href="/ru/docs/Learn/Getting_started_with_the_web">Начало работы с веб</a> модулем.</p> + +<h2 id="Получить_помощь">Получить помощь</h2> + +<p>Мы постарались сделать изучение фронтенд разработки настолько комфортным, насколько это возможно. Вероятно, вы всё равно рано или поздно попадёте в безвыходное положение, когда что-то будет непонятно или какой-то код не будет работать.</p> + +<p>Не беспокойтесь. Мы все иногда застреваем, и начинающие, и профессиональные веб-разработчики. Статья <a href="/en-US/docs//Learn/Learning_and_getting_help">Обучение и получение помощи</a> предоставит вам серию советов и подсказок для поиска информации и помощи самому себе. Если вы всё ещё в замешательстве, задайте вопрос по возникшей проблеме на нашем <a href="https://discourse.mozilla.org/c/mdn/learn/">Форуме</a>.</p> + +<p>Давайте начнём,</p> + +<p>Удачи!</p> + +<h2 id="Путь_обучения">Путь обучения</h2> + +<h3 id="Начало_работы">Начало работы</h3> + +<p>Время изучения: 1–2 часа</p> + +<h4 id="Необходимые_условия_2">Необходимые условия</h4> + +<p>Ничего, кроме базовой компьютерной грамотности.</p> + +<h4 id="Как_понять_что_я_могу_двигаться_дальше">Как понять, что я могу двигаться дальше?</h4> + +<p>В этой части курса нет оценок, но обязательно убедитесь, что вы ничего здесь не пропустили — важно всё настроить и подготовиться к выполнению упражнений в дальнейшем.</p> + +<h4 id="Основные_руководства">Основные руководства</h4> + +<ul> + <li><a href="/ru/docs/Learn/Getting_started_with_the_web/Установка_базового_программного_обеспечения">Установка базового программного обеспечения</a>— базовая настройка инструмента (15 минут чтения)</li> + <li><a href="ru/docs/Learn/Getting_started_with_the_web/%D0%92%D0%B5%D0%B1_%D0%B8_%D0%B2%D0%B5%D0%B1_%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D1%8B">История всемирной сети и веб-стандартов</a> (45 минут чтения)</li> + <li><a href="/en-US/docs//Learn/Learning_and_getting_help">Обучение и получение помощи</a> (45 минут чтения)</li> +</ul> + +<h3 id="Семантика_и_структура_с_HTML">Семантика и структура с HTML</h3> + +<p>Время завершения: 35–50 часов</p> + +<h4 id="Необходимые_условия_3">Необходимые условия</h4> + +<p>Ничего, кроме базовой компьютерной грамотности и базовой среды разработки веб-приложений.</p> + +<h4 id="Как_понять_что_я_могу_двигаться_дальше_2">Как понять, что я могу двигаться дальше?</h4> + +<p>Оценки в каждом модуле предназначены для проверки ваших знаний по предмету - завершение каждого из них докажет, что вы можете перейти к следующему модулю.</p> + +<h4 id="Основные_модули">Основные модули</h4> + +<ul> + <li><a href="/ru/docs/Learn/HTML/Введение_в_HTML">Введение в HTML</a> (15–20 часов чтения/упражнений)</li> + <li><a href="/ru/docs/Learn/HTML/Multimedia_and_embedding">Мультимедиа и встраивание</a> (15–20 часов чтения/упражнений)</li> + <li><a href="/ru/docs/Learn/HTML/Tables">HTML таблицы</a> (5–10 часов чтения/упражнений)</li> +</ul> + +<h3 id="Стилизация_и_размещение_с_помощью_CSS"><span>Стилизация и размещение с помощью CSS</span></h3> + +<p>Время завершения: 90–120 часов</p> + +<h4 id="Необходимые_условия_4">Необходимые условия</h4> + +<p>Рекомендуется иметь базовые знания HTML перед началом изучения CSS. Сначала вы должны изучить <a href="/ru/docs/Learn/HTML/Введение_в_HTML">Введение в HTML</a>.</p> + +<h4 id="Как_понять_что_я_могу_двигаться_дальше_3">Как понять, что я могу двигаться дальше?</h4> + +<p>Оценки в каждом модуле предназначены для проверки ваших знаний по предмету - завершение каждого из них докажет, что вы можете перейти к следующему модулю.</p> + +<h4 id="Основные_модули_2">Основные модули</h4> + +<ul> + <li><a href="/ru/docs/Learn/CSS/First_steps">Первые шаги в CSS</a> (10–15 часов чтения/упражнений)</li> + <li>С<a href="/ru/docs/Learn/CSS/Building_blocks">труктурные элементы CSS</a> (35–45 часов чтения/упражнений)</li> + <li><a href="/ru/docs/Learn/CSS/Styling_text">Стилизирование текста</a> (15–20 часов чтения/упражнений)</li> + <li><a href="/ru/docs/Learn/CSS/CSS_layout">CSS разметка</a> (30–40 часов чтения/упражнений)</li> +</ul> + +<h4 id="Дополнительные_ресурсы">Дополнительные ресурсы</h4> + +<ul> + <li><a href="/ru/docs/Web/CSS/Layout_cookbook">Книга рецептов CSS</a></li> +</ul> + +<h3 id="Интерактивность_с_JavaScript">Интерактивность с JavaScript</h3> + +<p>Время завершения: 135–185 часов</p> + +<h4 id="Необходимые_условия_5">Необходимые условия</h4> + +<p>Рекомендуется иметь базовые знания HTML перед началом изучения JavaScript. Сначала вы должны изучить <a href="/ru/docs/Learn/HTML/Введение_в_HTML">Введение в HTML</a>.</p> + +<h4 id="Как_понять_что_я_могу_двигаться_дальше_4">Как понять, что я могу двигаться дальше?</h4> + +<p>Оценки в каждом модуле предназначены для проверки ваших знаний по предмету - завершение каждого из них докажет, что вы можете перейти к следующему модулю.</p> + +<h4 id="Основные_модули_3">Основные модули</h4> + +<ul> + <li><a href="/ru/docs/Learn/JavaScript/Первые_шаги">Первые шаги в JavaScript</a> (30–40 часов чтения/упражнений)</li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks">Структурные элементы Javascript</a> (25–35 часов чтения/упражнений)</li> + <li><a href="/ru/docs/Learn/JavaScript/Client-side_web_APIs">Клиентский веб API</a> (30–40 часов чтения/упражнений)</li> + <li><a href="/ru/docs/Learn/JavaScript/Объекты">Введение в объекты Javascript</a> (25–35 часов чтения/упражнений)</li> + <li><a href="/ru/docs/Learn/JavaScript/Asynchronous">Асинхронный Javascript</a> (25–35 часов чтения/упражнений)</li> +</ul> + +<h3 id="Веб_формы_—_Работаем_с_данными_пользователя">Веб формы — Работаем с данными пользователя</h3> + +<p>Время завершения: 40–50 часов</p> + +<h4 id="Необходимые_условия_6">Необходимые условия</h4> + +<p>Для эффективного использования форм требуется знание HTML, CSS и JavaScript. Они сложны и поэтому рассматриваются отдельно.</p> + +<h4 id="Как_понять_что_я_могу_двигаться_дальше_5">Как понять, что я могу двигаться дальше?</h4> + +<p>Упражнения и оценки в каждом модуле предназначены для проверки ваших знаний по предмету - завершение каждого из них докажет, что вы можете перейти к следующему модулю.</p> + +<h4 id="Основные_модули_4">Основные модули</h4> + +<ul> + <li><a href="/ru/docs/Learn/HTML/Forms">Веб формы</a> (40–50 часов)</li> +</ul> + +<h3 id="Заставляем_веб_работать_для_всех">Заставляем веб работать для всех</h3> + +<p>Время завершения: 60–75 часов</p> + +<h4 id="Необходимые_условия_7">Необходимые условия</h4> + +<p>Рекомендуется ознакомиться с HTML, CSS и JavaScript перед началом работы с этим разделом - многие из техник и лучших практик используются в нескольких технологиях.</p> + +<h4 id="Как_понять_что_я_могу_двигаться_дальше_6">Как понять, что я могу двигаться дальше?</h4> + +<p>Упражнения и оценки в каждом модуле предназначены для проверки ваших знаний по предмету - завершение каждого из них докажет, что вы можете перейти к следующему модулю.</p> + +<h4 id="Основные_модули_5">Основные модули</h4> + +<ul> + <li><a href="/ru/docs/Learn/Tools_and_testing/Cross_browser_testing">Кросс-браузерное тестирование</a> (25–30 часов чтения/упражнений)</li> + <li><a href="/ru/docs/Learn/Доступность">Доступность</a> (20–25 часов чтения/упражнений)</li> +</ul> + +<h3 id="Современные_инструменты">Современные инструменты</h3> + +<p>Время завершения: 55–90 часов</p> + +<h4 id="Необходимые_условия_8">Необходимые условия</h4> + +<p>Рекомендуется ознакомиться с HTML, CSS и JavaScript перед началом работы с этим разделом, так как обсуждаемые инструменты работают со многими из этих технологий.</p> + +<h4 id="Как_понять_что_я_могу_двигаться_дальше_7">Как понять, что я могу двигаться дальше?</h4> + +<p>В этом наборе модулей нет специальных статей для оценки, но учебные примеры в конце 2-го и 3-го модулей хорошо подготовят вас к пониманию основ современного инструментария.</p> + +<h4 id="Основные_модули_6">Основные модули</h4> + +<ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/GitHub">Git и Github</a> (5 часов чтения)</li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools">Понимание инструментов на стороне клиента</a> (20–25 часов чтения/упражнений)</li> + <li> + <p><a href="/ru/docs/Learn/Tools_and_testing/Фронтенд_JavaScript_фреймворки">Понимание JavaScript-фреймворков для фронтенда</a> (30-60 часов чтения/упражнений)</p> + </li> +</ul> diff --git a/files/ru/learn/что_такое_веб_сервер/index.html b/files/ru/learn/что_такое_веб_сервер/index.html new file mode 100644 index 0000000000..efdc287ba9 --- /dev/null +++ b/files/ru/learn/что_такое_веб_сервер/index.html @@ -0,0 +1,128 @@ +--- +title: Что такое веб-сервер +slug: Learn/Что_такое_веб_сервер +tags: + - Веб-сервер + - Динамический сайт + - Новичок + - Статический сайт +translation_of: Learn/Common_questions/What_is_a_web_server +--- +<div class="summary"> +<p>В этой статье мы узнаем, что из себя представляют веб-серверы, как они работают, и почему они так важны.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые<br> + знания:</th> + <td>Вы должны уже знать, <a href="/ru/docs/Learn/How_the_Internet_works">как работает Интернет</a> и <a href="/en-US/docs/Learn/page_vs_site_vs_server_vs_search_engine">понимать разницу между страницей, сайтом, сервером и поисковой системой.</a></td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td> + <p>Вы узнаете, что такое веб-сервер и получите общее представление о том, как он работает.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Введение">Введение</h2> + +<p>Понятие <span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">«</span>веб-сервер<span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">»</span> может относиться как к аппаратной начинке, так и к программному обеспечению. Или даже к обеим частям, работающим совместно.</p> + +<ol> + <li>С точки зрения "железа", <span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">«</span>веб-сервер<span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">»</span> — это компьютер, который хранит файлы сайта (HTML-документы, CSS-стили, JavaScript-файлы, картинки и другие) и доставляет их на устройство конечного пользователя (веб-браузер и т.д.). Он подключен к сети Интернет и может быть доступен через доменное имя, подобное <code>mozilla.org</code>.</li> + <li>С точки зрения ПО, <cite>веб-сервер</cite> включает в себя несколько компонентов, которые контролируют доступ веб-пользователей к размещенным на сервере файлам, как минимум — это <em><cite>HTTP-сервер</cite></em>. <cite>HTTP-сервер</cite> — это часть ПО, которая понимает {{Glossary("URL","URL’ы ")}} (веб-адреса) и {{Glossary("HTTP")}} (протокол, который ваш браузер использует для просмотра веб-страниц).</li> +</ol> + +<p>На самом базовом уровне, когда браузеру нужен файл, размещенный на веб-сервере, браузер запрашивает его через HTTP-протокол. Когда запрос достигает нужного веб-сервера ("железо"), сервер HTTP (ПО) принимает запрос, находит запрашиваемый документ (если нет, то сообщает об ошибке <a href="/ru/docs/Web/HTTP/Status/404">404</a>) и отправляет обратно, также через HTTP.</p> + +<p><img alt="Basic representation of a client/server connection through HTTP" src="https://mdn.mozillademos.org/files/8659/web-server.svg" style="height: 200px; width: 600px;"></p> + +<p>Чтобы опубликовать веб-сайт, необходим либо статический, либо динамический веб-сервер.</p> + +<p><strong>Статический веб-сервер</strong>, или стек, состоит из компьютера ("железо") с сервером HTTP (ПО). Мы называем это <span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">«</span>статикой<span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">»</span>, потому что сервер посылает размещенные файлы в браузер <span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">«</span>как есть<span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">»</span>.</p> + +<p><strong>Динамический веб-сервер</strong> состоит из статического веб-сервера и дополнительного программного обеспечения, чаще всего <em>сервера приложения </em>и <em>базы данных</em>. Мы называем его <span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">«</span>динамическим<span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">»</span>, потому что сервер приложений изменяет исходные файлы перед отправкой в ваш браузер по HTTP.</p> + +<p>Например, для получения итоговой страницы, которую вы просматриваете в браузере, сервер приложений может заполнить HTML-шаблон данными из базы данных. Такие сайты, как MDN или Википедия, состоят из тысяч веб-страниц, но они не являются реальными HTML документами — лишь несколько HTML-шаблонов и гигантские базы данных. Эта структура упрощает и ускоряет сопровождение веб-приложений и доставку контента.</p> + +<h2 id="Активное_изучение">Активное изучение</h2> + +<p><em>Активное изучение пока не доступно. <a href="https://developer.mozilla.org/en-US/docs/MDN/Getting_started">Пожалуйста, рассмотрите возможность внести свой вклад</a>.</em></p> + +<h2 id="Погружаемся_глубже">Погружаемся глубже</h2> + +<p>Чтобы загрузить веб-страницу, как мы уже говорили, ваш браузер отправляет запрос к веб-серверу, который приступает к поиску запрашиваемого файла в своем собственном пространстве памяти. Найдя файл, сервер считывает его, обрабатывает как ему это необходимо, и отсылает в браузер. Давайте рассмотрим эти шаги более подробно.</p> + +<h3 id="Хостинг_файлов">Хостинг файлов</h3> + +<p>Прежде всего, веб-сервер должен содержать файлы веб-сайта, а именно все HTML-документы и связанные с ними ресурсы, включая изображения, CSS-стили, JavaScript-файлы, шрифты и видео.</p> + +<p>Технически, вы можете разместить все эти файлы на своем компьютере, но гораздо удобнее хранить их на выделенном веб-сервере, который:</p> + +<ul> + <li>всегда запущен и работает</li> + <li>всегда подключен к Интернету</li> + <li>имеет неизменный IP адрес (не все {{Glossary("ISP", "провайдеры")}} предоставляют статический IP-адрес для домашнего подключения)</li> + <li>обслуживается третьей, сторонней компанией</li> +</ul> + +<p>По всем этим причинам поиск хорошего хостинг-провайдера является ключевой частью создания вашего сайта. Рассмотрите многочисленные предложения компаний и выберите то, что соответствует вашим потребностям и бюджету (предложения варьируются от бесплатных до тысяч долларов в месяц). Вы можете найти подробности в <a href="https://developer.mozilla.org/en-EU/Learn/How_much_does_it_cost#Hosting">этой статье.</a></p> + +<p>Как только вы решили проблему с хостингом, вам понадобится только <a href="/en-US/docs/Learn/Upload_files_to_a_web_server">загрузить свои файлы на ваш веб-сервер</a>.</p> + +<h3 id="Связь_по_HTTP">Связь по HTTP</h3> + +<p>Во-вторых, веб-сервер обеспечивает поддержку {{Glossary("HTTP")}} (англ. <em><strong>H</strong>yper<strong>t</strong>ext <strong>T</strong>ransfer <strong>P</strong>rotocol - гипертекстовый транспортный протокол</em>). Как следует из названия, HTTP указывает, как передавать гипертекст (т.е. связанные веб-документы) между двумя компьютерами.</p> + +<p>Протокол представляет собой набор правил для связи между двумя компьютерами. HTTP является текстовым протоколом без сохранения состояния.</p> + +<dl> + <dt><strong>Текстовый</strong></dt> + <dd>Все команды являются простым человекочитаемым текстом.</dd> + <dt><strong>Не сохраняет состояние</strong></dt> + <dd>Ни клиент, ни сервер не помнят о предыдущих соединениях. Например, опираясь только на HTTP, сервер не сможет вспомнить введенный вами пароль или на каком шаге транзакции вы находитесь. Для таких задач, вам потребуется сервер приложения. (Мы остановимся на этих технологиях в следующих статьях.)</dd> +</dl> + +<p>HTTP задает строгие правила взаимодействия клиента и сервера. Мы рассмотрим сам протокол HTTP в <a href="/ru/docs/Web/HTTP">технической статье</a> немного позднее. Пока достаточно знать об этих правилах:</p> + +<ul> + <li>Исключительно <em>клиенты</em> могут производить HTTP-запросы, и только на <em>сервера</em>. Сервера способны только отвечать на HTTP-<em>запросы клиента</em>.</li> + <li>При запросе файла по HTTP, клиент должен сформировать файловый {{Glossary("URL")}}.</li> + <li>Веб-сервер <em>должен ответить</em> на каждый HTTP-запрос, по крайней мере сообщением об ошибке.</li> +</ul> + +<p><a href="https://developer.mozilla.org/en-US/404"><img alt="The MDN 404 page as an example of such error page" src="https://mdn.mozillademos.org/files/8661/mdn-404.jpg" style="float: right; height: 300px; width: 300px;"></a>На веб-сервере HTTP-сервер отвечает за обработку входящих запросов и ответ на них.</p> + +<ol> + <li>При получении запроса, HTTP-сервер сначала проверяет, существует ли ресурс по данному URL.</li> + <li>Если это так, веб-сервер отправляет содержимое файла обратно в браузер. Если нет, сервер приложения генерирует необходимый ресурс.</li> + <li>Если ничто из этого не возможно, веб-сервер возвращает сообщение об ошибке в браузер, чаще всего “404 Not Found”. (Это ошибка настолько распространена, что многие веб-дизайнеры тратят большое количество времени на разработку <a href="http://www.404notfound.fr/">404 страниц об ошибках</a>.)</li> +</ol> + +<h2 id="Статический_и_Динамический_контент">Статический и Динамический контент</h2> + +<p>Грубо говоря, сервер может отдавать статическое или динамическое содержимое.<strong> </strong><span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">«</span>Статическое<span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">»</span> означает <span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">«</span>отдается как есть<span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">»</span>. Статические веб-сайты делаются проще всего, поэтому мы предлагаем вам сделать свой первый сайт статическим.</p> + +<p><span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">«</span>Динамическое<span style="background-color: #ffffff; color: #222222; display: inline !important; float: none; font-family: sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">»</span> означает, что сервер обрабатывает данные или даже генерирует их на лету из базы данных. Это обеспечивает большую гибкость, но технически сложнее в реализации и обслуживании, из-за чего процесс создания сайта очень сильно усложняется.</p> + +<p>Возьмем для примера страницу, которую вы сейчас читаете. На веб-сервере, где она хостится, есть сервер приложения, который извлекает содержимое статьи из базы данных, форматирует его, добавляет в HTML-шаблоны и отправляет вам результат. В нашем случае, сервер приложения называется <a href="/en-US/docs/MDN/Kuma">Kuma</a>, написан он на языке программирования <a href="https://www.python.org/">Python</a> (используя фреймворк <a href="https://www.djangoproject.com/">Django</a>). Команда Mozilla создала <cite>Kuma</cite> для конкретных нужд MDN, но есть множество подобных приложений, построенных совершенно на других технологиях.</p> + +<p>Существует так много серверов приложений, что довольно трудно предложить какой-то один. Некоторые серверы приложений заточены под определенные категории веб-сайтов, такие как блоги, вики-страницы или интернет-магазины; другие, называемые {{Glossary("CMS", "CMSs")}} (системы управления контентом), более универсальны. Если вы создаете динамический сайт, потратьте немного времени на выбор инструмента, который соответствует вашим потребностям. Если вы не хотите изучать веб-программирование (хотя это увлекательно само по себе!), то вам не нужно создавать свой собственный сервер приложения. Это будет изобретением очередного велосипеда.</p> + +<h2 id="Следующие_шаги">Следующие шаги</h2> + +<p>Теперь, когда вы познакомились с веб-серверами, вы можете:</p> + +<ul> + <li>прочитать <a href="/en-US/docs/Learn/How_much_does_it_cost">насколько сложно делать что-либо в веб</a></li> + <li>узнать больше о <a href="/en-US/docs/Learn/What_software_do_I_need">разнообразии ПО, которое может пригодиться для создания веб-сайта</a></li> + <li>двигаться к практике: например, <a href="/en-US/docs/Learn/Upload_files_to_a_web_server">узнать как загружать файлы на веб-сервер</a>.</li> +</ul> + +<div id="s3gt_translate_tooltip" style="left: 140px; top: 658px; opacity: 0.75;"></div> + +<div id="s3gt_translate_tooltip" style="left: 60px; top: 2380px;"></div> |