Який виглядає красивий HTML код? Як писати чистий та красивий код

Щоб усі подальші описи були Вам більш зрозумілими, скачайте цей PDF фаїл або просто відкрийте в новій вкладці Вашого браузера це зображення .

Іноді цікаво звернути увагу на те, чи завжди у красивому зовнішньому вебсайті використаний "красивий" html код, тобто. точний, структурований, безпомилковий. Html код це своєрідне мистецтво. Він не такий розвинений і різноманітний, як динамічна мова, проте може бути написаний досить витончено і майстерно.

Ось список тих особливостей за допомогою яких можна визначити, чи написаний код з майстерністю чи ні.

1. DOCTYPE,визначений належним чином. Цей рядок дозволяє не тільки визначити ваш код, а й "говорить" браузеру про те, як слід відобразити вашу сторінку.

2. Охайний розділ у тегах
Заголовок встановлено. Кодування оголошено. Таблиці стилів підключено. Скрипти підключено, а не написано повністю.

3. Присвоєння ID вашому документудозволяє створювати властивості CSS, які є унікальними для кожної сторінки. Наприклад, ви можете захотіти, щоб Ваш

тег виглядав особливо, наприклад, на домашній сторінці. У таблиці стилів CSS можна написати: #home h2 (), щоб досягти цього.

4. Чисте меню.Ви, мабуть, часто зустрічалися з тим, що меню використовуються списки. Це зручно, т.к. дає можливість контролювати його.

5. Укладання всього змісту сторінки до головного тегу

. Цей пункт дасть вам можливість контролювати все. Тобто ви зможете встановити максимальну та мінімальну ширину сторінки.

6. Важливе потрібно розміщувати на початку.Новини та важливі події в коді повинні слідувати першими, а меню, маловажний зміст, слід розміщувати в кінці.

7. "Включення" елементів сайту.Більшість елементів сайту повторюються на кожній сторінці, отже, їх потрібно включати, за допомогою php-команди include.

8. Код має бути табульований за розділами.Якщо кожен розділ коду буде виділено відступом, то структура коду буде набагато зрозумілішою. Код, який вирівняний по лівому краю, важко читати і зрозуміти.

9. Правильні заключні теги. Виключіть заключні теги у непарних тегах і перевірте, щоб парні теги були закриті.

10. Використовуйте теги заголовків. Використання заголовків необхідне, т.к. вони показують ієрархію розділів і більше впорядковують їх.

12. Жодних стилів!Ваш html код має бути зосереджений на структурі та змісті, а не на оформленні сторінки! Усі стилі виносьте в окремий файл CSS.

Я наведу основні правила, яких потрібно дотримуватися при розробці коду, щоб через тиждень можна було подивитися код і визначити, яка функція що робити. Ще однією перевагою написання читабельного коду, це простота пошуку та усунення помилок. Відразу скажу, що приклади, які я позначаю як «некоректний», означають не те, що вони не працюють, а те, що вони некоректні з точки зору розробки читабельного коду.

1. Виносьте змінні за дужки

Завжди при виведенні на екран тексту змінні в рядку необхідно виносити за дужки. Це не тільки зручно для перегляду, а й ефективно, тому що при цьому виведення на екран здійснюється швидше.

Приклад некоректний:

echo "Value is $val"

Приклад коректний:

echo "Value is ".$val

2. Обов'язково використовуйте коментарі

Кожна функція, по можливості, повинна бути описана невеликим коментарем. Кожен фрагмент, якщо ви вважаєте, що він досить складний для розуміння, має бути описаний невеликим коментарем. І взагалі, коментарем має бути описано все, що ви вважаєте за необхідне. Вибір вигляду коментаря ви повинні визначити собі самі. Це може бути один текстовий рядок або блок рядків, в якому описано призначення функції, інформація про її автора і т.п.

3. Використовуйте скорочений режим echo. Наприклад, запис виду

можна спокійно замінити на

4. По можливості виносите великі блоки HTML межі конструкцій php. Чи не зловживайте функцією php.

Приклад некоректний:

"; echo "Number before is ".($i - 1); echo "
"; } ?>

Приклад коректний:

Number is
Номер before is

Зверніть увагу, що тут відкривається дві конструкції PHP, а між ними вставляється HTML текст. Можливо, за даним прикладом і не видно явної переваги винесення тексту за межі php конструкції, але насправді, коли вам доведеться мати справу з таблицями, подібне правило може стати в нагоді.

5. Код має бути вирівняний щодо блоків.

Приклад некоректний:

Запам'ятайте, php це вам не паскал із його блоками begin…end. Тут блок повинен відкриватися в тому ж рядку, де він почався, а закривається вирівняним щодо початку блоку:

6. Спрощуйте складні конструкції. Розбивайте їх у прості.

Приклад некоректний:

$res = mysql_result(mysql_query("SELECT Num FROM db"), 0, 0)

Приклад коректний:

$query = mysql_query("SELECT Num FROM db"); $ res = mysql_result ($ query, 0, 0);

7. Використовуйте більше пробілів та порожні рядки.

Насправді, це досить важливий елемент написання читабельного коду. Я бачив, як деякі не залишають порожні рядки і використовують якнайменше прогалин, вважаючи, що вони займають зайве місце. Це докорінно не так, оскільки зайві байти дозволять іншій людині заощадити час на розбір чужого коду.

Приклад некоректний:

Приклад коректний:

8. Використовуйте скорочені види математичних та рядкових операцій.

Пам'ятайте, що +1 можна замінити на ++, а +n на +=n.

Приклади замін:

$i = $i + 1 еквівалентно $i++
$i = $i - 1 еквівалентно $i-
$i = $i + $n еквівалентно $i+=$n
$i = $i."hello" еквівалентно $i.="hello"

Добре погано

Зіткнувшись із необхідністю контролювати роботу інших програмістів, починаєш розуміти, що, крім речей, яким люди навчаються досить легко і швидко, знаходяться проблеми, для усунення яких потрібен суттєвий час.

Порівняно швидко можна навчити людину користуватися необхідним інструментарієм і документацією, правильної комунікації із замовником і всередині команди, правильному цілепокладання та розстановці пріоритетів (ну, звичайно, тією мірою, якою сам усім цим володієш).

Але коли справа доходить до коду, все стає набагато менш однозначно. Так, можна вказати на слабкі місця, можна пояснити, що з ними не так. І наступного разу отримати реву з абсолютно новим набором проблем.

Професії програміста, як і більшості інших професій, доводиться вчитися щодня протягом кількох років, а за великим рахунком, і все життя. Спочатку ти освоюєш набір базових знань в обсязі N семестрових курсів, потім довго тупцюєш по різних граблях, переймаєш досвід старших товаришів, вивчаєш хороші та погані приклади (погані чомусь частіше).

Говорячи про базові знання, треба відзначити, що вміння писати гарний професійний код - це те, що з тих чи інших причин, ці базові знання категорично не входить. Натомість, у відповідних закладах, а також у книжках нам розповідають про алгоритми, мови, принципи ОВП, патерни дизайну…

Так, все це потрібно знати. Але при цьому розуміння того, як має виглядати гідний код, зазвичай з'являється вже за наявності практичного (частіше в тій чи іншій мірі негативного) досвіду за плечима. І за умови, що життя “потикало” тебе не лише в соковиті зразки поганого коду, а й у приклади серйозно гідні наслідування.

У цьому й полягає вся складність: твоє уявлення про “гідний” та “красивий” код повністю засноване на особистому багаторічному досвіді. Спробуй тепер передати це уявлення в стислий термін людині з зовсім іншим досвідом або навіть зовсім без нього.

Але якщо для нас дійсно важлива якість коду, який пишуть люди, які працюють разом з нами, то спробувати все ж таки варто!

2. Навіщо нам потрібний гарний код?

Зазвичай, коли ми працюємо над конкретним програмним продуктом, естетичні якості коду турбують нас далеко не насамперед.
Нам набагато важливіша наша продуктивність, якість реалізації функціоналу, стабільність його роботи, можливість модифікації та розширення тощо.

Але чи є естетичні якості коду фактором, що позитивно впливає на перераховані вище показники?
Моя відповідь: так, і при цьому, однією з найважливіших!

Це так, тому що красивий код, незалежно від суб'єктивного трактування поняття про красу, має наступні (в тій чи іншій мірі зведені один до одного) найважливіші якості:

  • Читання. Тобто. можливість, дивлячись на код, швидко зрозуміти реалізований алгоритм, і оцінити, як поводитиметься програма в тому чи іншому окремому випадку.
  • Керованість. Тобто. можливість у мінімальні терміни внести до коду необхідні поправки, уникнувши у своїй різних неприємних передбачуваних і непередбачуваних наслідків.
Чому ці якості дійсно є найважливішими, і як вони сприяють підвищенню показників, зазначених на початку параграфа, впевнений, очевидно, будь-кому, хто займається програмуванням.

А тепер, щоб від загальних слів перейти до конкретики, давайте зробимо зворотний хід і скажемо, що саме код, що читається і керований зазвичай сприймається нами як красивий і професійно написаний. Відповідно, на обговоренні того, як досягти цих якостей, ми далі і зосередимося.

3. Три базові принципи.

Переходячи до викладу власного досвіду, зазначу, що, працюючи над читальністю та керованістю свого та чужого коду, я поступово прийшов до наступного розуміння.

Незалежно від конкретної мови програмування та розв'язуваних завдань, для того, щоб фрагмент коду в достатньо володів цими двома якостями необхідно, щоб він був:

  • максимально лінійним;
  • коротким;
  • самодокументованим.
Можна нескінченно перераховувати різні хінти та техніки, за допомогою яких можна зробити код красивішим. Але я стверджую, що найкращих, або, принаймні, досить добрих результатів можна досягти, орієнтуючись саме на ці три принципи.

4. Лінеарізація коду.

Мені здається, що з трьох базових принципів, саме лінійність є неочевидним, і саме їй найчастіше нехтують.
Напевно тому, що за роки навчання (і, можливо, наукової діяльності) ми звикли обговорювати від природи нелінійні алгоритми з оцінками типу O(n3), O(nlogn)і т.д.

Це все, звичайно, добре і важливо, але, говорячи про реалізацію бізнес-логіки в реальних проектах, зазвичай доводиться мати справу з алгоритмами зовсім іншої властивості, що більше нагадують ілюстрації до дитячих книжок із програмування. Щось типу такого (взято з):

Таким чином, з лінійністю я пов'язую не стільки асимптотичну складність алгоритму, скільки максимальна кількість вкладених один в одного блоків коду, або ж рівень вкладеності максимально довгої ділянки коду.

Наприклад, ідеально лінійний фрагмент:

Do_a(); do_b(); do_c();
І зовсім не лінійний:

Do_a(); if (check) ( something(); ) else ( anything(); if (whatever()) ( for (a in b) ( if (good(a)) ( something(); ) ) ) )
Саме “шматки” другого типу ми намагатимемося переписати за допомогою певних технік.

Примітка: оскільки тут і далі нам знадобляться приклади коду для ілюстрації тих чи інших ідей, відразу домовимося, що вони будуть написані абстрактною узагальненою C-like мовою, крім тих випадків, коли будуть потрібні особливості конкретної існуючої мови. Для таких випадків буде явно зазначено, якою мовою написаний приклад (конкретно будуть зустрічатися приклади на Java і Javascript).

4.1. Техніка 1. Виділяємо основну гілку алгоритму.
У переважній більшості випадків як основна гілка має сенс взяти максимально довгий успішний лінійний сценарій алгоритму.

Спробуємо зробити це на основі "алгоритму авторемонту" на діаграмі вище:

  1. Клієнт повідомляє побажання.
  2. Майстер оглядає та каже вартість.
  3. Пошук дефектів.
  4. Складаємо замовлення на запчастини.
  5. Беремо передоплату, позначаємо термін.
  6. Клієнт їде.
Саме ця основна гілка у нас в ідеалі має бути на нульовому рівні вкладеності.

Listen_client(); if (!is_clean()) ( ... ) check_cost(); if (!client_agree()) (...) find_defects(); if (defects_found()) (...) create_request(); take_money(); bye();
Давайте для порівняння розглянемо варіант, де на нульовому рівні знаходиться альтернативна гілка замість основної:

Listen_client(); if (!is_clean()) ( ... ) check_cost(); if (client_agree()) ( find_defects(); if (defects_found()) ( ... ) create_request(); take_money(); ) else ( ... ) bye();
Як видно, рівень вкладеності значної частини коду виріс, і дивитися на код загалом уже стало менш приємно.

4.2. Техніка 2. Використовуємо break, continue, returnабо throw, щоб позбутися блоку else.
Погано:

If (!client_agree()) ( ... ) else ( find_defects(); if (defects_found()) ( ... ) create_request(); take_money(); bye(); )

If (!client_agree()) ( ... return; ) find_defects(); if (defects_found()) (...) create_request(); take_money(); bye();

Зрозуміло, невірним був би висновок, що взагалі ніколи не потрібно використовувати оператор else. По-перше, не завжди контекст дозволяє поставити break, continue, returnабо throw(хоча часто таки дозволяє). По-друге, виграш від цього може бути не такий очевидний, як у прикладі вище, і простий elseбуде виглядати набагато простіше і зрозуміліше, ніж будь-що ще.

Ну і по-третє, існують певні витрати при використанні багатьох returnу процедурах і функціях, через які багато хто взагалі розцінює даний підхід як антипаттерн (моя особиста думка: зазвичай переваги все-таки покривають ці витрати).

Тому ця (і будь-яка інша) техніка має сприйматися як підказка, а не як безумовна інструкція до дії.

4.3. Техніка 3. Виносимо складні підсценарії окремі процедури.
Т.к. у випадку "алгоритму ремонту" ми досить вдало вибрали основну гілку, то альтернативні гілки у нас усі залишилися дуже короткими.

Тому продемонструємо техніку на основі поганого прикладу з початку глави:

Do_a() if (check) ( something(); ) else ( anything(); if (whatever()) ( for (a in b) ( if (good(a)) ( something(); ) ) ) )
Краще:

Procedure do_on_whatever() ( for (a in b) ( if (good(a)) ( something(); ) ) ) do_a(); if (check) ( something(); ) else ( anything(); if (whatever()) ( do_on_whatever(); ) )
Зверніть увагу, що правильно вибравши ім'я виділеної процедури, ми, крім того, одразу підвищуємо самодокументованість коду. Тепер для цього фрагмента загалом має бути зрозуміло, що він робить і навіщо потрібний.

Однак слід мати на увазі, що та сама самодокументованістьсильно постраждає, якщо винесена частина коду не має загального закінченого завдання, яке цей код виконує. Труднощі у виборі правильного імені для процедури можуть бути індикатором саме такого випадку (див. п. 6.1).

4.4. Техніка 4. Виносимо все, що можливо, у зовнішній блок, залишаємо у внутрішньому лише те, що потрібно.
Погано:

If (check) ( do_a(); something(); if (whatever()) ( for (a in b) ( if (good(a)) ( something(); ) ) ) ) else ( do_a(); anything (); if (whatever()) ( for (a in b) ( if (good(a)) ( something(); ) ) ) )
Краще:

Do_a(); if (check) ( something(); ) else ( anything(); ) if (whatever()) ( for (a in b) ( if (good(a)) ( something(); ) ) )

4.5. Техніка 5 (приватний випадок попередньої). Поміщаємо в try...catchтільки те, що потрібно.
Слід зазначити, що блоки try...catchвзагалі є болем, коли йдеться про читання коду, т.к. часто, накладаючись один на одного, вони сильно підвищують загальний рівень вкладеності навіть для найпростіших алгоритмів.

Боротися з цим найкраще, мінімізуючи розмір ділянки усередині блоку. Тобто. всі рядки, що не передбачають появу виключення, мають бути винесені за межі блоку. Хоча в деяких випадках з точки зору читання більш виграшним може виявитися і суворо протилежний підхід: замість того, щоб писати безліч дрібних блоків try..catchкраще об'єднати їх в один великий.

Крім того, якщо ситуація дозволяє не обробляти виняток тут і зараз, а викинути вниз по стеку, зазвичай краще саме так і вчинити. Але треба мати на увазі, що варіативність тут можлива тільки в тому випадку, якщо ви самі можете задавати або змінювати контракт процедури, що редагується.

4.6. Техніка 6. Об'єднуємо вкладені if-и.
Тут усе очевидно. Замість:

If (a) ( if (b) ( do_something(); ) )
пишемо:

If (a && b) ( do_something(); )

4.7. Техніка 7. Використовуємо тернарний оператор ( a? b: c) замість if.
Замість:

If (a) ( var1 = b; ) else ( var1 = c; )
пишемо:

Var1 = a? b: c;
Іноді має сенс навіть написати вкладені тернарні оператори, хоча це передбачає від читача знання пріоритету, з яким обчислюються вирази тернарного оператора.

If (a) ( var1 = b; ) else if (aa) ( var1 = c; ) else ( var1 = d; )
пишемо:

Var1 = a? b: aa? c: d;
Але зловживати цим, мабуть, не варто.

Зауважимо, що ініціалізація змінної var1тепер здійснюється однією єдиною операцією, що знову ж таки сильно сприяє самодокументованості (див. п. 6.8).

4.8. Підсумовуючи сказане вище, спробуємо написати повну реалізацію алгоритму ремонту максимально лінійно.
listen_client(); if (!is_clean()) ( wash(); ) check_cost(); if (!client_agree()) ( pay_for_wash(); bye(); return; ) find_defects(); if (defects_found()) ( say_about_defects(); if (!client_agree()) ( pay_for_wash_and_dyagnosis(); bye(); return; ) ) create_request(); take_money(); bye();
На цьому можна було б і зупинитися, але не зовсім здорово виглядає те, що нам доводиться тричі викликати bye()і, відповідно, пам'ятати, що з додаванні нової гілки, його доведеться щоразу писати перед return (власне, витрати множинних return).

Можна було б вирішити проблему через try...finally, але це зовсім правильно, т.к. у разі не йдеться про обробку винятків. Та й справі лінеаризації такий підхід сильно завадив би.

Давайте зробимо так (насправді, я тут застосував п. 5.1ще до того, як його написав):

Procedure negotiate_with_client() ( check_cost(); if (!client_agree()) ( pay_for_wash(); return; ) find_defects(); if (defects_found())( say_about_defects(); if (!client_a ; return; ) ) create_request();take_money(); ) listen_client(); if (!is_clean()) ( wash(); ) negotiate_with_client(); bye();
Якщо ви вважаєте, що ми зараз записали щось тривіальне, то, в принципі, так і є. Проте запевняю, що у багатьох живих проектах ви побачили б зовсім іншу реалізацію цього алгоритму.

5. Мінімізація коду.

Думаю, було б зайвим пояснювати, що зменшуючи кількість коду, який використовується для реалізації заданого функціоналу, ми робимо код набагато більш читаним та надійним.

У цьому сенсі ідеальне інженерне рішення - це, коли нічого не зроблено, але все працює, як потрібно. Зрозуміло, у реальному світі дуже рідко доступні ідеальні рішення, і тому у нас, програмістів, поки що є робота. Але прагнути варто саме такого ідеалу.

5.1. Техніка 1. Усуваємо дублювання коду.
Про копіпаст і шкоду, що від нього виходить, сказано вже так багато, що додати щось нове було б складно. Проте, програмісти, покоління за поколінням інтенсивно використовують цей метод для реалізації програмного функціоналу.

Зрозуміло, найбільш очевидним методом боротьби з проблемою є винесення коду, що перевикористовується, в окремі процедури і класи.
При цьому завжди виникає проблема виділення спільного із приватного. Найчастіше навіть не завжди зрозуміло, чого більше у схожих шматків коду: подібності чи відмінностей. Вибір тут робиться виключно за ситуацією. Тим не менш, наявність однакових ділянок розміром у пів-екрана відразу говорить про те, що цей код можна і потрібно записати суттєво коротше.

Варто також згадати дуже корисну техніку усунення дублювання, описану в п. 4.3.
Поширити її можна далі лише операторів if. Наприклад, замість:

Procedure proc1() ( init(); do1(); ) procedure proc2() ( init(); do2(); ) proc1(); proc2();
запишемо:

Init(); do1(); do2();
Або зворотний варіант. Замість:
a = новий Object(); init(a); do(a); b = новий Object(); init(b); do(b);
запишемо:
procedure proc(a) ( init(a); do(a); ) proc(new Object()); proc(new Object());

5.2. Техніка 2. Уникаємо зайвих умов та перевірок.
Зайві перевірки – зло, яке можна зустріти практично у будь-якій програмі. Складно описати, наскільки найтривіальніші процедури та алгоритми можуть бути засмічені відверто непотрібними, дублюючими та безглуздими перевірками.

Особливо це стосується, звичайно ж, перевірок на null. Як правило, викликане подібне споконвічним страхом програмістів перед всюдисущими NPEі бажанням вкотре від них перестрахуватися.

Далеко не рідкісним видом непотрібної перевірки є такий приклад:

Obj = новий Object(); ... if (obj != null) ( obj.call(); )
Незважаючи на свою очевидну абсурдність, трапляються такі перевірки із вражаючою регулярністю. (Одразу ж зазначу, що приклад не стосується тих рідкісних мов та середовищ, де оператор new()може повернути null. У більшості випадків (в т.ч. Java) подібне в принципі неможливо).

Сюди ж можна включити десятки інших видів перевірок на свідомо виконану (чи свідомо не виконану) умову.
Ось, наприклад, такий випадок:

Obj = factory.getObject(); obj.call1(); // якби obj був null, ми вже померли) if (obj != null) ( obj.call2(); )
Зустрічається у рази частіше, ніж попередній тип перевірок.

Третій приклад трохи менш очевидний, ніж перші два, але поширений просто повсюдно:

Procedure proc1(obj) ( if (!is_valid(obj)) return; obj.call1(); ) procedure proc2(obj) ( if (!is_valid(obj)) return; obj.call2(); ) obj = factory. getObject(); if (is_valid(obj) ( proc1(obj); proc2(obj); )
Як видно, автор цього відрізку панічно боїться нарватися на невалідний об'єкт, тому перевіряє його перед кожним чхом. Незважаючи на те, що інколи така стратегія може бути виправдана (особливо, якщо proc1()і proc2()експортуються як API), у багатьох випадках це просто засмічення коду.

Варіанти тут можуть бути різними:

  • Для кожної процедури позначити вхідний контракт, що вимагає від дотримання певних умов валідності. Після цього видалити страхуючі перевірки і повністю перенести відповідальність за валідність вхідних даних на код, що викликає. Для Java, наприклад, гарною практикою може бути позначка "небезпечних" методів та полів анотацією @Nullable. Таким чином, ми неявно позначимо, що інші поля та методи можуть приймати/повертати значення null.
  • Загалом не створювати невалідних об'єктів! Цей підхід передбачає виконання всіх процедур валідації на етапі створення об'єкта, щоб сам факт успішного створення гарантував валідність. Зрозуміло, для цього, як мінімум, потрібно, щоб ми контролювали клас фабрики або інші механізми створення об'єктів. Або щоб існуюча реалізація давала нам таку гарантію.
Можливо, здавалося б, ці варіанти здаються чимось неможливим і навіть страшним, проте, насправді з допомогою можна значно підвищити читаність і надійність коду.

Ще одним корисним підходом є застосування патерну NullObject, що передбачає використання об'єкта з нічого не роблять, але й не викликають помилок, методами замість "небезпечного" null. Приватним випадком такого підходу можна вважати відмову від використання null для змінних колекцій на користь порожніх колекцій.

Сюди ж належать спеціальні null-safeбібліотеки, серед яких хотілося б виділити набір бібліотек apache-commonsдля Java. Він дозволяє заощадити величезну кількість місця і часу, позбавивши необхідності писати нескінченні рутинні перевірки на null.

5.3. Техніка 3. Уникаємо написання "велосипедів". Використовуємо максимум готові рішення.
Велосипеди – це майже як копіпаст: усі знають, що це погано, і всі їх регулярно пишуть. Можна лише порадити хоча б намагатися боротися із цим злом.

Більшу частину часу перед нами постають завдання чи підзавдання, які вже багато разів були вирішені, чи то сортування чи пошук по масиву, чи робота з форматами 2D графіки чи long-polling сервера на Javascript. Загальне правило полягає в тому, що стандартні завдання мають стандартне рішення і це рішення дає нам можливість отримати потрібний результат, написавши мінімум свого коду.

Часом є спокуса, замість того, щоб щось шукати, куштувати і підганяти, швиденько накидати на коліна свій велосипед. Іноді це може бути виправдано, але якщо йдеться про код, що підтримується в довгостроковій перспективі, хвилинна "економія" може обернутися годинами налагодження та виправлення помилок на пропущених корнер-кейсах.

З іншого боку, лише злегка торкаючись досить широку тему, хотілося б сказати, що іноді "велосипедна" реалізація може або навіть повинна бути віддана перевагу використанню готового рішення. Зазвичай це правильно у разі, коли довіру до якості готового рішення не вище, ніж до свого коду, або у разі, коли витрати від застосування нової зовнішньої залежності виявляються технічно неприйнятними.

Тим не менш, повертаючись до питання про стислості коду, безумовно, використання стандартних (наприклад, apache-commonsі guavaдля Java) та нестандартних бібліотек є одним з найбільш дієвих способів зменшити розміри власного коду.

5.4. Техніка 4. Залишаємо в коді лише те, що справді використовується.
"Висячі" функції, які ніким ніде не викликаються; ділянки коду, що ніколи не виконуються; цілі класи, які ніде не використовуються, але їх забули видалити - певен, кожен міг спостерігати такі речі у своєму проекті, і, можливо, навіть сприймав їх як належне.

Насправді ж, будь-який код, зокрема невикористовуваний, вимагає плату за зміст у вигляді витраченого уваги і часу.
Оскільки код, що не використовується, реально не виконується і не тестується, в ньому можуть містяться некоректні виклики тих чи інших процедур, непотрібні або неправильні перевірки, звернення до процедур і зовнішніх бібліотек, які більше ні для чого не потрібні, і безліч інших шкідливих, що збивають з пантелику. речей.

Таким чином, видаляючи непотрібні та не використовуються ділянки, ми не тільки зменшуємо розміри коду, але і, що не менш важливо, сприяємо його самодокументованості.

5.5. Техніка 5. Використовуємо свої знання мови та покладаємося на наявність цих знань у читача.
Одним із ефективних способів зробити свій код простіше, коротшим і зрозумілішим є вміле використання особливостей конкретної мови: різних умовчань, пріоритетів операцій, коротких форм запису тощо.

Як ілюстрацію наведу найбільш, на мою думку, яскравий приклад для мови Javascript.

Дуже часто при розборі рядкових виразів можна побачити такі нагромадження:
if (obj != null && obj != undefined && obj.s != null && obj.s != undefined && obj.s != "") ( // do something )
Виглядає лякаюче, в тому числі і з погляду "а чи не забув автор ще якусь перевірку". Насправді, знаючи особливість мови Javascript, у більшості подібних випадків усю перевірку можна звести до тривіальної:

If (obj & obj.s) ( // do something )
Справа в тому, що завдяки неявному приведенню до boolean, перевірка if (obj) ()відсіє:

  • false
  • null
  • undefined
  • порожній рядок
Загалом вона відсіє більшість тривіальних значень, які ми можемо собі уявити. На жаль, повторюся, програмісти використовують цю особливість досить рідко, через що їх перестрахувальні перевірки виглядають дуже громіздко.

Аналогічно, порівняйте такі форми запису:

If (!a) ( a = defaultValue; )
і

A = a | defaultValue;
Другий варіант виглядає простіше завдяки використанню специфічної семантики логічних операцій у скриптових мовах.

6. Самодокументований код.

Термін "самодокументованість" найчастіше використовується при описі властивостей таких форматів, як XML або JSON. У цьому контексті мається на увазі наявність у файлі не тільки набору даних, а й відомостей про їх структуру, про назви сутностей і полів, що задаються цими даними.

Читаючи XML файл, ми, навіть нічого не знаючи про контекст, майже завжди можемо скласти уявлення про те, що описує даний файл, що за дані в ньому представлені і навіть, можливо, як вони будуть використані.

Поширюючи цю ідею на програмний код, під терміном "самодокументованість" хотілося б об'єднати безліч властивостей коду, що дозволяють швидко, без детального розбору та глибокого вникання в контекст зрозуміти, що робить цей код.

Хотілося б протиставити такий підхід “зовнішньої” документованості, яка може виражатися у наявності коментарів чи окремої документації. Не заперечуючи потреби у певних випадках того й іншого, зазначу, що коли йдеться про читання коду, методи самодокументування виявляються значно ефективнішими.

6.1. Техніка 1. Ретельно вибираємо назви функцій, змінних та класів. Не варто обманювати людей, які читатимуть наш код.
Найголовніше правило, яке слід взяти за основу під час написання самодокументованого коду - ніколи не обманюйте свого читача.

Якщо поле називається name, там має зберігатися саме назва об'єкта, а не дата його створення, порядковий номер масиву або ім'я файлу, в який він серіалізується. Якщо метод називається compare(), він повинен саме порівнювати об'єкти, а не складати їх у хеш таблицю, звернення до якої можна буде знайти десь на 1000 рядків нижче за кодом. Якщо клас називається NetworkDevice, то в його публічних методах повинні бути операції, які застосовуються до пристрою, а не реалізація швидкого сортування в загальному вигляді.

Важко висловити словами, як часто, незважаючи на очевидність цього правила, програмісти його порушують. Думаю, не варто пояснювати, яким чином це позначається на їх читанні коду.

Щоб уникнути таких проблем, необхідно максимально ретельно продумувати назву кожної змінної, кожного методу та класу. При цьому треба намагатися не тільки коректно, а й, по можливості, максимально повноохарактеризувати призначення кожної конструкції.

Якщо цього зробити не виходить, причиною зазвичай є дрібні або грубі помилки дизайну, тому сприйняти таке треба як мінімум тривожний “дзвіночок”.

Очевидно, так само варто мінімізувати використання змінних із назвами i, j, k, s. Змінні з такими назвами можуть бути тільки локальними і мати лише загальноприйняту семантику. В разі i, jЦе можуть бути лічильники циклів або індекси в масиві. Хоча, по можливості, і таких лічильників варто позбуватися на користь циклів foreach і функціональних висловів.
Змінні ж із назвами ii, i1, ijk42, asdsaі т.д., не варто використовувати ніколи. Ну хіба що, якщо ви працюєте з математичними алгоритмами ... Ні, краще все-таки ніколи.

6.2. Техніка 2. Намагаємось називати однакові речі однаково, а різні – по-різному.
Одна з найбільших проблем, що бентежать, що виникають при читанні коду - це вживані в ньому синоніми та омоніми. Іноді в ситуації, коли дві різні сутності названі однаково, доводиться витрачати по кілька годин, щоб розділити всі випадки їх використання та зрозуміти, яка саме з сутностей мається на увазі у кожному конкретному випадку. Без такого поділу нормальний аналіз, а отже, і осмислена модифікація коду, неможливі в принципі. А трапляються подібні ситуації набагато частіше, ніж можна було б припустити.

Приблизно те саме можна сказати і про “зворотну” проблему - коли для однієї і тієї ж сутності/операції/алгоритму використовується кілька різних імен. Час на аналіз такого коду може зрости в порівнянні з очікуваним у рази.

Висновок простий: у своїх програмах до виникнення синонімів та омонімів треба ставитись вкрай уважно і всіма силами намагатися подібного уникати.

6.3. Техніка 3. "Бритва Оккама". Не створюємо сутностей, без яких можна обійтись.
Як уже говорилося в п. 5.4., будь-яка ділянка коду, будь-який об'єкт, функція або змінна, які ви створюєте, надалі, у процесі підтримки, вимагатиме собі плати у вигляді вашого (або чужого) часу та уваги.

З цього випливає найпряміший висновок: чим менше сутностей ви введете, тим простіше і краще в результаті виявиться ваш код.

Типовий приклад "зайвої" змінної:

Int sum = counSum(); int збільшуєтьсяSum = sum + 1; operate(increasedSum); ...
Очевидно, змінна збільшивсяСумє надмірною сутністю, т.к. опис об'єкта, який вона зберігає (sum + 1)характеризує цей об'єкт набагато краще і точніше, ніж назва змінної. Таким чином код варто переписати наступним чином (“заінлайнувати” змінну):

Int sum = counSum(); operate(sum + 1); ...
Якщо далі за кодом сума ніде не використовується, можна йти далі:

Operate(countSum() + 1); ...
Інлайн непотрібних змінних - це один із способів зробити ваш код коротшим, простішим і зрозуміліше.

Однак застосовувати його варто лише у випадку, якщо цей прийом сприяє самодокументованості, а чи не суперечить їй. Наприклад:

Double descr = b * b - 4 * a * c; double x1 = -b + sqrt (descr) / (2 * a);
В цьому випадку інлайн змінної descrнавряд чи піде на користь читання, т.к. дана змінна використовується для представлення певної сутності з предметної області, а отже наявність змінної сприяє самодокументованості коду, і сама змінна під “бритву Оккама” не потрапляє.

Узагальнюючи принцип, продемонстрований на даному прикладі, можна зробити таке: бажано у своїй програмі створювати змінні/функції/об'єкти, тільки якщо вони мають прототипи в предметній області. При цьому, відповідно до п. 6.1, Треба намагатися, щоб назва цих об'єктів максимально ясно виражала цю відповідність. Якщо ж такої відповідності немає, цілком можливо, що використання змінної/функції/об'єкта лише перевантажує ваш код і їх видалення піде програмі тільки на користь.

Загальний принцип простий: будь-які явно виписані алгоритми чи умови вже є самодокументованими, тому що їх призначення та принцип дії вже описані ними самими. Навпаки, будь-які непрямі умови та операції із сайд-ефектами сильно ускладнюють розуміння суті того, що відбувається.

Можна навести грубий приклад, маючи на увазі, що життя підкидає подібні приклади не рідко.

Непряма умова:

If (i == abs(i)) ( )
Пряма умова:

If (i >= 0) ( )
Оцінити різницю в читання, гадаю, нескладно.

6.5. Техніка 5. Все, що можна сховати в private (protected), має бути сховано туди. Інкапсуляція – наше все.
Говорити про користь та необхідність дотримання принципу інкапсуляції при написанні програм у цій статті я вважаю зайвим.
Хотілося б лише наголосити на ролі інкапсуляції, як механізму самодокументування коду. В першу чергу, інкапсуляція дозволяє чітко виділити зовнішній інтерфейс класу і позначити його "точки входу", тобто методи, в яких може бути розпочато виконання коду класу. Це дозволяє людині, що вивчає ваш код, зберегти величезну кількість часу, сфокусувавшись на функціональному призначенні класу та абстрагувавшись від деталей реалізації.
6.6. Техніка 6. (Узагальнення попереднього) Усі об'єкти оголошуємо у максимально вузькій області видимості.
Принцип максимального обмеження області видимості кожного об'єкта можна поширити ширше, ніж звична інкапсуляція з ООП.

Простий приклад:

Object someobj = createSomeObj(); if (some_check()) ( // Don"t need someobj here ) else ( someobj.call(); )
Очевидно, таке оголошення змінної деяке ускладнює розуміння її призначення, тому що читає ваш код буде шукати звернення до неї в значно ширшій області, ніж вона використовується і реально потрібна.

Неважко зрозуміти, як зробити цей код трохи краще:

If (some_check()) ( // Don"t need someobj here ) else ( Object someobj = createSomeObj(); someobj.call(); )

Ну або якщо змінна потрібна для єдиного виклику, можна скористатися ще й п. 6.3:

If (some_check()) ( // Don"t need someobj here ) else ( createSomeObj().call(); )
Окремо хотілося б обговорити випадок, коли ця техніка може не працювати або працювати на шкоду. Це змінні, які ініціалізуються поза циклами. Наприклад:

Object someobj = createSomeObj(); for (int i = 0; i< 10; i++) { someobj.call(); }
Якщо створення об'єкта через createSomeObj()- дорога операція, внесення її до циклу може неприємно позначитися на продуктивності програми, навіть якщо читаність від цього і поліпшиться.

Такі випадки не скасовують загального принципу, а просто служать ілюстрацією того, що кожна техніка має свою сферу застосування і має бути використана вдумливо.

6.7. Техніка 7. Чітко поділяємо статичний та динамічний контекст. Методи, які залежать від стану об'єкта, мають бути статичними.
Змішання чи взагалі відсутність поділу між статичним і динамічним контекстом - не найстрашніше, але дуже поширене зло.

Приводить воно до появи непотрібних залежностей стану об'єкта в потенційно статичних методах, або взагалі до неправильному управлінню станом об'єкта. Як наслідок - до скрути аналізу коду.

Тому необхідно намагатися звертати увагу і на даний аспект, явно виділяючи методи, які не залежать від стану об'єкта.

6.8. Техніка 8. Намагаємось не розділяти оголошення та ініціалізацію об'єкта.
Даний прийом дозволяє поєднати декларацію імені об'єкта з негайним описом того, що об'єкт являє собою. Саме це і є яскравим прикладом дотримання принципу самодокументованості.

Якщо цією технікою знехтувати, читачеві доведеться кожному за об'єкта шукати за кодом, де він було оголошено, чи немає в нього де-небудь ініціалізації іншим значенням тощо. Все це ускладнює аналіз коду та збільшує час, необхідний для того, щоб у коді розібратися.

Саме тому, наприклад, функціональні операції з apache CollectionUtilsі guava Collections2часто краще вбудованих в Java foreachциклів – вони дозволяють поєднати оголошення та ініціалізацію колекції.

Порівняємо:

lowercaseStrings = новий ArrayList (); /* collection is uninitialized here, потрібен для investigate the initializion */ for (String s: somestrings) ( lowercaseStrings.add(StringUtils.lowerCase(s)); )
з:
// getting “somestrings” collection somehow ... Collection lowercaseStrings = Collections2.transform(somestrings, New Function () ( @Override public String apply(String s) ( return StringUtils.lowerCase(s); ) ))));
Якщо ми використовуємо Java 8, можна записати трохи коротше:

Collection lowercaseStrings = somestrings.stream() .map(StringUtils::lowerCase).collect(Collectors.toList());
Ну і варто згадати випадок, коли розділяти оголошення та ініціалізацію змінних так чи інакше доводиться. Це випадок використання змінної в блоках finallyі catch(Наприклад, для звільнення якого-небудь ресурсу). Тут уже нічого не залишається, крім як оголосити змінну перед try, а ініціалізувати всередині блоку try.

6.9. Техніка 9. Використовуємо декларативний підхід та засоби функціонального програмування для позначення, а не приховування суті того, що відбувається.
Даний принцип може бути проілюстрований прикладом з попереднього пункту, в якому ми використовували емуляцію функціонального підходу Java з метою зробити наш код зрозумілішим.

Для більшої наочності розглянемо ще й приклад Javascript (взято звідси: http://habrahabr.ru/post/154105).

Порівняємо:

Var str = "mentioned by"; for(var i = 0; l = tweeps.length; i< l; ++i){ str += tweeps[i].name; if(i< tweeps.length-1) {str += ", "} }
з:

Var str = "mentioned by" + tweeps.map(function(t)( return t.name; )).join(", ");
Ну а приклади використання функціонального підходу, що вбивають читання ... Давайте цього разу заощадимо свої нерви і обійдемося без них.

6.10. Техніка 10. Пишемо коментарі лише, якщо без них взагалі не зрозуміло, що відбувається.
Як мовилося раніше вище, принцип самодокументування коду протиставляється документуванню з допомогою коментарів. Хотілося б коротко пояснити, чим так погані коментарі:
  • У добре написаному коді вони непотрібні.
  • Якщо підтримка коду часто стає трудомістким завданням, підтримкою коментарів зазвичай просто ніхто не займається і через деякий час коментарі старіють і починають дурити людей (comments lie).
  • Вони засмічують собою простір, тим самим погіршуючи зовнішній вигляд коду та ускладнюючи читання.
  • У переважній більшості випадків вони пишуться особисто Капітаном Очевидністю.
Ну а потрібні коментарі у випадках, коли написати код добре з тих чи інших причин неможливо. Тобто. писати їх треба для пояснення ділянок коду, без них важкочитаних. На жаль, у реальному житті таке трапляється регулярно, хоча розцінювати це слід лише як неминучий компроміс.

Також, як різновид подібного компромісу, слід розцінювати необхідність специфікації контракту методу/класу/процедури за допомогою коментарів, якщо його не виходить явно висловити іншими мовними засобами (див. п. 5.2).

7. Філософський висновок.

Закінчивши виклад основних технік та прийомів, за допомогою яких можна зробити код трохи красивішим, слід ще раз явно сформулювати: жодна з технік не є безумовним керівництвом до дії. Будь-яка техніка - лише можливий засіб досягнення тієї чи іншої мети.

У нашому випадку метою є отримання максимально читаного та керованого коду. Який одночасно буде приємний з естетичної точки зору.

Вивчаючи приклади, наведені у цій статті, можна легко помітити, що, як самі вихідні принципи (лінійність, мінімальність, самодокументованість), і конкретні техніки є незалежними друг від друга. Застосовуючи одну техніку ми можемо побічно слідувати і зовсім інший. Покращуючи один із цільових показників, ми можемо сприяти покращенню інших.

Однак, у цього явища є і зворотний бік: нерідкі ситуації, коли принципи вступають у пряму суперечність один з одним, а також з безліччю інших можливих правил і догм програмування (наприклад, з принципами ОВП). Сприймати це треба спокійно.
Трапляються й такі випадки, коли однозначно гарного вирішення тієї чи іншої проблеми взагалі не існує, або це рішення з ряду причин нереалізоване (наприклад, замовник не хоче приймати потенційно небезпечні зміни в коді, навіть якщо вони сприяють загальному поліпшенню якості).

У програмуванні, як і більшості інших сфер людської діяльності, неспроможна існувати універсальних інструкцій до виконання. Кожна ситуація вимагає окремого розгляду та аналізу, а рішення має прийматися виходячи з розуміння особливостей ситуації.

У цілому нині, цей факт анітрохи не скасовує корисності як висновку та розуміння загальних принципів, і володіння конкретними способами їх втілення у життя. Саме тому я сподіваюся, що все викладене у статті може виявитися справді корисним для багатьох програмістів.

Ну і ще кілька слів про те, з чого ми починали - про красу нашого коду. Навіть знаючи про "просунуті" техніки написання красивого коду, не варто нехтувати найпростішими речами, такими, як елементарне автоформатування і дотримання встановленого в проекті стилю кодування. Найчастіше лише форматування здатне створити з потворним шматком коду справжні дива. Як і розумне групування ділянок коду за допомогою порожніх рядків та переносів. Додати теги

Вміти писати код - значить вміти робити це правильно. Хороший код - це як красиво оформлений пост - його зручно читати, в ньому легко орієнтуватися і розробнику завжди зрозуміло, як його розширити, налагодити або використовувати для інших цілей.
Тому завжди важливо приділяти увагу оформленню коду, коментувати складні ділянки коду.

Спочатку трохи теорії. Один і той самий код можна писати різними способами. Код може бути процедурним, функціональнимі об'єктно-орієнтованим.

Процедурний підхід

Процедурний підхід найпростіший. Під ним мається на увазі скрипт, в якому суцільником написано команди та викликані елементарні php функції.
Наприклад:

$a = 10;
$c = $a % $b;
$e + $d;
echo round($e);
?>

Такий підхід доречний, якщо у вас дуже маленький код або він виконує строго одне завдання (наприклад, генерує картинку), як то кажуть "ні крок вправо, ні крок вліво".

Функціональний підхід

У функціональному підході ваш код поділено на частини і кожна з них поміщена у свою функцію. Це дозволить уникнути дублювання коду, надасть коду лаконічність та його простіше читати.
Також у кожної функції буде своя власна область видимості змінних. Тобто змінні, "що живуть всередині неї" ніколи не проникнуть назовні і змінні, що використовуються поза функцією так само не потраплять у саму функцію.
Визначаючи функцію, ви самі можете вказати які змінні повинні потрапити в функцію і що вона повинна повернути, тобто ви суворо контролюєте цей процес.

Тепер пробуємо функціонально.

//Верне вартість
function getPrice($price, $weight) (
$result_price * $weight;
return $result_price;
}
//поверне всі ваги
function getWeights() (
return array(5, 12, 14, 16, 22, 135, 150, 200, 254, 300, 400);
}

//отримуємо ваги змінну
$weights всі фрукти
foreach ($fruits as $fruit) (
foreach ($weights as $weight) (
echo $fruit["name"] . " ". $weight. "кг стоять". getPrice($fruit["price"], $weight) . "Руб.
";
}
}
?>

Код вийшов набагато читабельнішим. Ваги вказані у функції getWeightsі простим додаваннямїх туди порахувати скільки б коштувала інша вага кожних фруктів.
Я перебрав усі фрукти і при кожному переборі перебирав усі ваги. Можна було зробити й навпаки.
Вихідник на pastebin http://pastebin.com/07QTBihX

І нарешті реалізація на ООП.

class Fruiting (
public $fruits;
public $weights;

public function setData($fruits, $weights) (
$this->fruits = $fruits;
$this->weights = $weights;
}

private function getPrice($price, $weight) (
$result_price = $price * $weight;
return $result_price;
}

public function getResult() (
//перебираємо всі фрукти
foreach ($this->fruits as $fruit) (
//перебираємо всі ваги для кожного фрукта
foreach ($this->weights as $weight) (
echo $fruit["name"] . " ". $weight. "кг стоять". self::getPrice($fruit["price"], $weight) . "Руб.
";
}
}
}
}

$fruiting = new Fruiting();
$fruiting->setData($fruits, array(5, 12, 14, 16, 22, 135, 150, 200, 254, 300, 400));
$fruiting->getResult();
?>

Як бачите - код більший. При простих обчисленнях можна обійтися і функціональним підходом, але всі справді великі та складні проекти написані з використанням ОВП.

При написанні матеріалу намагався дотримуватися порад @ontofractal :)

P.S.Коли пишете код - уявіть, що підтримуватиме його психічно неврівноважений маніяк, який знає де ви живете.

Доброї доби всім, хто зараз читає цю публікацію. Сьогодні я хочу розповісти вам про один із інструментів сайтобудування, без якого жоден веб-ресурс не може обійтися. Це меню сайту, або як ще кажуть карта сайту. На сьогоднішній день існує безліч видів і підвидів меню.

Розробники інтернет-магазинів, блогів, навчальних сервісів та інших ресурсів експериментують та створюють все новіші та незвичайні карти. Після прочитання статті ви дізнаєтеся, на які основні групи діляться всі види навігаційних панелей, зможете випробувати кожну з них, а також навчитися писати код меню для сайту html. А тепер перейдемо безпосередньо до справи!

Інструменти для створення навігаційної панелі

У мові розмітки є кілька способів створення меню. Основна їхня концепція полягає у використанні ненумерованого списку. Таким чином, у звичному для нас html 4 розробники прописують на станиці теги

    і
  • .

    Як зазначалося в попередніх публікаціях, парний елемент

      створює маркований список, а
    • один елемент списку. Для наочності давайте напишемо код простого меню:

      Навігація

      Навігація сайту

      • Головна
      • Новини тижня
      • Технологічні досягнення
      • Чат


      Однак з появою платформи мова розмітки поповнилася додатковими тегами. Саме тому меню сучасних веб-сайтів створюється за допомогою спеціального тега< menu>. Цей елемент нічим не відрізняється від маркованих списків.

      Замість одиниці < ul>прописується < menu>. Однак суттєві відмінності з'являються, якщо судити з боку роботи. Так, другий приклад прискорює роботу пошукових програмта роботів в . При аналізі структури сайту вони відразу розуміють, що цей шмат коду відповідає за карту сайту.

      Бувають горизонтальні, вертикальні та випадаючі меню. Іноді навігаційну панель оформляють у вигляді зображення. Оскільки сегмент технологій розширився, веб-сервіси роблять адаптивними, тобто. структура сторінок автоматично адаптується під розмір екрана девайсів. Розглянемо перелічені групи меню.

      Створимо горизонтальну навігаційну модель

      Такий вид навігації найпопулярніший. При горизонтальному оформленні панелі всі пункти меню розташовані в шапці сторінки або в підвалі (іноді навігаційні елементи дублюються, відображаючись одночасно і зверху, і знизу).

      Як приклад, ми створимо горизонтальну панель, пункти меню якого будуть оформлені за допомогою css (каскадних таблиць стилів), а точніше трансформовані. Так, кожен окремий елементбуде у скошеному прямокутнику. Заінтригував?

      Для трансформації ми використовуємо властивість css під назвою transform. Щоб вказати трансформацію, використовується вбудована функція skewX, В якій кут нахилу вказується в градусах.

      На жаль, кожен браузер працює з цією властивістю по-своєму, незважаючи на прописані стандарти. Тому для позначення того чи були створені спеціальні префікси:

      • -ms- (Internet Explorer)
      • -o- (Opera)
      • -webkit- (Chrome, Safari)
      • -moz- (Firefox)

      А тепер отримані знання можна застосувати до написання прикладу.

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <a href="https://redcomrade.ru/uk/case/sistemnyi-blok-svoimi-rukami-oformlyaem-perednyuyu-panel-korpusa-svoimi-rukami/">Горизонтальна панель</a>
    • Головна
    • Про компанію
    • Продукція
    • Контакти


    • Горизонтальна панель

    • Головна
    • Про компанію
    • Продукція
    • Контакти


    • А тепер вертикально. Я сказав вертикально!

      Для другої програми використовуємо за основу попередній код. Я захотів, щоб пункти мого вертикального меню були не скошені, а із заокругленими кутами.

      Для цього я скористався ще одним властивістю css border-radius.

      У попередніх статтях я вже працював із цим параметром, тож складнощів з розумінням його функціонування, думаю, не виникне.

      Вертикальна панель

    • Головна
    • Про компанію
    • Продукція
    • Контакти


    • Як ви вже помітили, головна зміна в цьому коді – відсутність оголошення display: inline-block, який власне і відповідав за горизонтальне розташування навігаційних пунктів.

      Підпункти в меню: список, що випадає

      Ми з вами розглянули основні групи навігаційних панелейПроте існує ще кілька різновидів або краще сказати доповнень.

      Іноді виникають такі ситуації, коли деякі пункти доповнюють основні. У цьому випадку не обійтися без списків, що випадають. Вони створюються шляхом перетворень інструментами CSS.

      Нижче я прикріпив код маленької програми, в якій реалізується даний підхід.

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 Випадаючий список

      Випадаючий список



      У даному прикладія розділив одиниці меню на два класи:

      1. m-menu
      2. s-menu

      Перший клас відповідає за основне меню, а s-menu за підменю.

      У коді можна зустріти такий прийом, як .m-menu > li:hoverабо .m-menu > li.

      Так, за допомогою: hover вказується, як поводитиметься елемент при наведенні на нього курсора.

      У цьому знак «>» видозмінює селектор те щоб блочно-рядковими були лише об'єкти, які стосуються верхнього рівня.

      Спочатку підменю було поставлено display:none, що повідомляє обробник приховувати даний об'єкт. Після наведення на елемент навігації із зазначенням hover, значення властивості displayзмінюється на blockі тому відкривається список, що випадає.

      Як бачите, реалізація такого прийому дуже проста.

      Тепер ви освоїли основні види навігаційних панелей та можете самостійно їх видозмінювати, доповнювати та модернізувати. Якщо вам сподобалась моя стаття, підписуйтесь на оновлення блогу і ділитеся джерелом знань з друзями та колегами. Бувай!

      З повагою, Роман Чуєшов

      Прочитано: 1010 разів