Hlavička (header) - pokročilá

Header a moduly

Header

{* Header *}

<header class="header header--top js--header js--fixed-header">
    <div class="header__content --content --flex">

        {* Header | Top *}


        
        <div class="header__top --flex-centre-y">

                {* Header | Logo *}

            
                <div class="header__logo --flex-inline">
                        <a class="header__logo-link" href="/{$lang}">
                            <img class="header__logo-img" src="/img/logo.svg"
                                 alt="{$web['DEFAULT_TITLE']}">
                        </a>
            </div>

           {* Header | Menu *}


            
                <div class="header__menu">
                        {include 'menu.latte', nav => $nav}
            </div>

            {* Header | Call *}
		    {include "./header-call.latte"}

		    {* Header | Language *}

                <div class="header__lang --flex-inline --flex-centre-y" n:if="count($activeLangs) > 1">
                    {include 'lang.latte'}
                </div>

        </div>


		{* Header | Bottom *}
        <div class="header__bottom --flex-inline --flex-centre-y">
            <div class="--w-12 --w-l-3 header__column header__column--left header__desktop-part">

                <a href="#" class="header__button
                js--toggler button button--brand" data-target="#menuDesktop">

                    <div class="header__button-bar-wrap">
                        <span class="header__button-bar"></span>
                        <span class="header__button-bar"></span>
                        <span class="header__button-bar"></span>
                    </div>
                    {$web['HEADER_CHOOSE_CATEGORY']}
                </a>

                {* Header | Menu *}
                <div n:class="'header__menu js--header-menu', $menuExpanded ? 'js--active'" id="menuDesktop">
                    {include 'menu.latte', nav => $categories}
                </div>
            </div>

            <div class="--w-12 --w-l-9 --flex
            header__column header__column--right">

                {* Header | Search *}


                
                <div class="header__search header__desktop-part --flex-inline --flex-centre-y icon icon--search">
                        {form search class => "header__search-form form form--search"}
                            <input n:name="search_text"
                                    data-use="typeahead"
                                    placeholder="{$web['SEARCH_PLACEHOLDER']}"
                                    class="form__input"
                                    type="text">
                            <button class="button form__button js--header-search">
                                {$web['HEADER_SEARCH']}
                            </button>
                        {/form}
                </div>


                {* Header | Logo *}

                
                <div class="header__logo --flex-inline header__mobile-part">
                        <a class="header__logo-link" href="/{$lang}">
                            <img class="header__logo-img" src="/img/logo.svg"
                                 alt="{$web['DEFAULT_TITLE']}">
                        </a>
                </div>


			    {* Header | Search *}


                
                <div class="header__search-toggle --flex-inline --flex-centre-y header__desktop-part">
                        <button class="header__search-toggle-button icon icon--search --hide-text js--header-search-toggle">
                            {$web['HEADER_SEARCH']}
                        </button>
                </div>


			    {* Header | Login *}
                    {include "./login.latte"}


                {* Header | Basket *}
                <basket></basket>


                <div class="header__mobile-part">
                    <a href="#" class="header__button js--toggler
                    button button--brand" data-target="#menuMobile">

                        <div class="header__button-bar-wrap">
                            <span class="header__button-bar"></span>
                            <span class="header__button-bar"></span>
                            <span class="header__button-bar"></span>
                        </div>

                        Menu
                    </a>

                    {* Header | Menu *}
                    <div n:class="'header__menu js--header-menu'"
                            id="menuMobile">
                        {include 'menu.latte', nav => $categories, secondaryNav => $nav}
                    </div>
                </div>


            </div>

            <div class="--w-12 header__mobile-part">
                <div class="header__search --flex-inline --flex-centre-y icon icon--search">
                    {form search class => "header__search-form form form--search"}
                        <input n:name="search_text"
                                data-use="typeahead"
                                placeholder="{$web['SEARCH_PLACEHOLDER']}"
                                class="form__input"
                                type="text">
                        <button class="button form__button js--header-search">
                            {$web['HEADER_SEARCH']}
                        </button>
                    {/form}
                </div>
            </div>
        </div>
    </div>
</header>

.header {
	background: $color__header;
	left: 0;
	position: absolute;
	right: 0;
	top: 0;
	z-index: 100;
	overflow: visible;
	border-bottom: 1px solid $color__gray;
	padding-bottom:25px;
	
}

.header--fixed{
	position: fixed;
	left:0;
	top:0;
	right:0;
}


.header--hide {
	top: -100%;
}

.header__menu{
	position: relative;
	
	.header__bottom &{
		max-height: 0px;
		transition: max-height 0.3s ease-in-out;
		overflow: hidden;
		right: -16px;
		left: -16px;
		
		@include media($large){
			left: 0;
			right: auto;
		}
	}
	
	
}

.header__menu{
	
	.header__top &{
		display: none;
		
		@include media($large){
			display: flex;
		}
	}
	
	.header__bottom &{
		position: absolute;
		z-index: 4;
		
		@include media($large){
			width: 100%;
		}
	}
}

.header__mobile-part{
	display: initial;
	
	@include media($large){
		display: none;
	}
}


.header__desktop-part{
	display: none;
	
	@include media($large){
		display: initial;
	}
}

.header__call{
	white-space: nowrap;
	margin-right: 15px;
	line-height: 1.2;
	
	@include media($large){
		margin-left: auto;
	}
	
	.header__top &{
		display: none;
		
		@include media($large){
			display: flex;
		}
	}
}

.header__call-link{
	color: $color__green;
	margin-right: 8px;
	
	&::before{
		font-size: 1.3rem;
	}
}

.header__call-content{
	flex-direction: column;
	@include media($large){
		flex-direction: row;
	}
}

.header__call-text{
	color: $color__gray-darker;
	display: block;
}

.header__logo{
	width: 110px;
	margin-right:15px;
	
	
	@include media(375px){
		width: 130px;
	}
	
	@include media($large){
		margin-right: 25px;
	}
	@include media($xlarge){
		margin-right: 40px;
		width: 190px;
	}
}


.header__bottom{
	align-items: center;
	width: 100%;
}

.header__top{
	padding: 25px 0;
	font-size: 1.4rem;
	display: none;
	width: 100%;
	
	@include media($large){
		display: flex;
	}
}

.header__button{
	width: 100%;
	flex-direction: row;
	
	
	padding: 4px 11px;
	
	@include media(375px){
		padding: 8px 17px;
	}
	
	@include media($large){
		padding: 8px 32px;
	}
}

.header__button-bar-wrap{
	margin-right: 10px;
	pointer-events: none;
}

.header__button-bar{
	display: block;
	background: white;
	width: 18px;
	height: 2px;
	
	&:not(:last-of-type){
		margin-bottom: 3px;
	}
}



.header__search{
	width: 100%;
	position: relative;
	max-width: 525px;
	
	
	&::before{
		position: absolute;
		left: 18px;
		top: 19px;
		color: $color__primary;
		font-size: 1.6rem;
	}
	
	@include media($xlarge){
		max-width: 665px;
	}
}

.header__search-form{
	width: 100%;
	display:flex;
}




.header__column{
	position:relative;
}


.header__column--right{
	align-items: center;
	padding: 15px 0;
	

	@include media($large){
		padding:  0 0 0 55px;
	}
}

.header__login{
	display: flex;
	align-items: center;
	margin-right: 10px;
	margin-left: auto;
	color: $color__text;
	
	@include media($large){
		margin-right: 25px;
	}
	
}

Menu

<nav class="menu">

    {default $secondaryNav = false}
	{* Menu | List *}
    <div class="menu__content --flex --flex-centre js--menu-content">
        <div class="menu__list">
            <div class="menu__top">

                {* Header | Call *}
		        {include "./header-call.latte"}

                {* Header | Lang *}
		        {include "./lang.latte"}

            </div>
            {foreach $nav as $item}
                <div class="menu__item">
                    <a n:class="'menu__link', $iterator->isLast() ? 'menu__link--last'" href="{$item|link|noescape}">
                        {$item|name|striptags}
                    </a>
                </div>
            {/foreach}
        </div>

        <div class="menu__additional-list --flex --flex-column" n:if="$secondaryNav">
            {foreach $secondaryNav as $item}
                <div class="menu__additional-item">
                    <a n:class="'menu__additional-link', $iterator->isLast() ? 'menu__link--last'" href="{$item|link|noescape}">
                        {$item|name|striptags}
                    </a>
                </div>
            {/foreach}
        </div>

    </div>
</nav>

.menu__list {
	display: flex;
	
	.header__bottom & {
		background: $color__gray;
		flex-direction: column;
		position: relative;
		padding: 6px 15px;
		font-size: 1.5rem;
		margin-top: 15px;
		width: 100%;
		max-height: calc(100vh - 250px);
		overflow-y: auto;
		
		@include media($large){
			padding: 6px 30px;
			max-height: calc(100vh - 200px);
		}
		
		&::before {
			@include pseudo();
			bottom: 100%;
			width: 0;
			height: 0;
			border-style: solid;
			border-width: 0 16px 11px 16px;
			border-color: transparent transparent $color__gray transparent;
			right: 54px;
			
			@include media($large) {
				left: calc(50% - 16px);
				right: auto;
			}
		}
	}
}

.menu__top{
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding:15px 0 8px;
	flex-shrink: 0;
	
	
	@include media($large){
		display: none;
	}
}


.menu__additional-list {
	background: $color__gray;
	width: 100%;
	padding: 35px 15px;
	max-height: 150px;
}

.menu__additional-link{
	padding: 10px 0;
	text-transform:uppercase;
	font-size: 1.4rem;
	color: $color__text;
}

.menu__list--main {
	display: flex;
}


.menu__button {
	display: inline-block;
	height: 36px;
	padding: 3px;
	position: absolute;
	right: 8px;
	top: -4px;
	width: 40px;
	z-index: 1;
	
	@include media($large) {
		display: none;
	}
}


.menu__link {
	color: $color__text;
	display: block;
	
	&:hover, &:focus {
		color: $color__primary;
	}
	
	.header__top & {
		font-size: 1.4rem;
		text-transform: uppercase;
		padding: 3px 8px;
		
		@include media($xlarge) {
			padding: 5px 13px;
		}
	}
	
	.header__bottom & {
		width: 100%;
		padding: 9.65px 2px;
		
		
		@include media($xlarge) {
			padding: 12.3px 2px;
		}
		
		border-bottom: 1px solid $color__border;
	}
}

.menu__link--last {
	.header__bottom & {
		border-bottom: 0;
	}
}

Header-call

<div class="header__call --flex-centre-y">
    <div class="header__call-content --flex --flex-nowrap">
        <a class="header__call-link --flex --flex-centre icon icon--phone"
           href="tel:{$web['PER_PHONE']}
                        {$web['PHONE']}">
            <span>{$web['PER_PHONE']} <b>{$web['PHONE']}</b></span>
        </a>

        <span class="header__call-text">
						{$web['OPEN_HOURS']|noescape}
					</span>
    </div>
</div>

Lang

{* Lang *}

<div class="lang" n:if="count($activeLangs) > 1">

	{* Lang | List *}
	<ul class="lang__list --flex --flex-nowrap ">
		<li n:class="'lang__item', $activeLangId === $lang_id ? 'lang__item--selected'"
			n:foreach="$activeLangs as $activeLangId => $activeLang">
			<a class="lang__link --flex --flex-nowrap --flex-y-centre" role="button" title="{$activeLang}" href="/{$activeLang}">
				<img src="/img/flags/{$activeLang}.svg" alt="{$activeLang}">
			</a>
		</li>

	</ul>

</div>

.lang{
	.header__top &{
		display: none;
		
		@include media($large){
			display: block;
		}
	}
}

.lang__item{
	opacity: 0.4;
	transition: opacity $ease;
	
	&:not(:last-of-type){
		margin-right: 8px;
	}
	
	
	&:hover, &:focus{
		opacity: 1;
	}
}

.lang__item--selected{
	opacity: 1;
}

Login

<div class="header__login js--login login"
     data-target=".js--login-wrap">
    <span class="login__icon icon icon--user"></span>
    <div class="login__wrap js--login-wrap">
        <div class="login__box --flex --flex-column --flex-end">
            {if $user->isLoggedIn()}
                <a class="login__link --link-underline"
                   href="/{$lang}/account/orders">{$web['ACCOUNT_ORDERS']}</a>
                <a class="login__link --link-underline"
                   href="/{$lang}/account/address">{$web['ACCOUNT_ADDRESS']}</a>
                <a class="login__link --link-underline"
                   href="/{$lang}/account/setting">{$web['ACCOUNT_SETTING']}</a>
                <a class="login__link --link-underline"
                   href="/{$lang}/logout">{_front.layout.logout}</a>
            {else}
                {form signInForm class => "login__form form form--contact"}
                    <label class="form__label" n:name="$form['email']">
                        {_}{$form['email']->caption}{/_}
                        {input email class => "form__input"}
                    </label>

                    <label class="form__label" n:name="$form['password']">
                        {_}{$form['password']->caption}{/_}
                        {input password class => "form__input"}
                    </label>

                    <label>
                        {input send class => "--hide"}
                        <span class="form__button button button--brand">
                            {_}{$form['send']->caption}{/_}
                        </span>
                    </label>
                {/form}

                <a class="login__link --link-underline" href="/{$lang}/register">{$web['LOGIN_REGISTER']}</a>
                <a class="login__link --link-underline" href="/{$lang}/password">{$web['LOGIN_FORGOTTEN_PASS']}</a>
            {/if}
        </div>
    </div>
</div>

.login{
	position: relative;
	cursor:pointer;
}

.login__form{
	width: 100%;
	margin: 0 0 10px 0;
}

.login__icon{
	
	&:hover, &:focus{
		color: $color__primary;
	}

	&::before{
		font-size: 2.1rem;
		
		@include media(375px){
			font-size: 2.6rem;
		}
	}
}

.login__wrap{
	position: absolute;
	background: #fff;
	right: -92px;
	top: 100%;
	width: 290px;
	z-index: 2;
	max-height: 0px;
	overflow: hidden;
	transition: max-height $ease;
	
	
	@include media(375px){
		right: -107px;
	}
	
	@include media($large){
		right: 0px;
	}
}

.login__box{
	padding: 10px;
	border: 1px solid $color__gray;
	
}
.login__title{
	width: 100%;
	font-size: 1.5rem;
}

Potřebný javascript

const headerBasket = document.querySelector(".js--basket");
    headerBasket.addEventListener("mouseenter", function (e) {
        collapseElement(headerBasket.dataset.target, 'show');
    })
    headerBasket.addEventListener("mouseleave", function (e) {
        collapseElement(headerBasket.dataset.target, 'hide');
    })

    const headerLogin = document.querySelector(".js--login");
    headerLogin.addEventListener("mouseenter", function (e) {
        collapseElement(headerLogin.dataset.target, 'show');
    })
    headerLogin.addEventListener("mouseleave", function (e) {
        collapseElement(headerLogin.dataset.target, 'hide');
    })


    }

    const collapseFnMap = {
        'toggle': 'toggle',
        'show': 'add',
        'hide': 'remove'
    };

    function collapseElement(selector, cmd = 'toggle') {
        let target = document.querySelector(selector);
        if(cmd === 'toggle'){
            if (target.classList.contains("js--active")) {
                target.style.maxHeight = "0px";
            } else {
                target.style.maxHeight = target.scrollHeight + "px";
            }
        }
        else if(cmd === 'show'){
            target.style.maxHeight = target.scrollHeight + "px";
        }
        else if(cmd === 'hide'){
            target.style.maxHeight = "0px";
        }

        target.classList[collapseFnMap[cmd]]('js--active');
    }

Nevíte si rady?
Neváhejte se zeptat

Nevíte si rady nebo potřebujete něco konzultovat? Nápovědu stále zdokonalujeme na základě vašich požadavků a postřehů. Uvádíme co nejvíce možných variant, které používáme na řešení jednotlivých částí webu, mějte ale na paměti, že projekty řešíme individuálně na základě konkrétních potřeb.

Nádražní 876
560 02 Česká Třebová

honza.cech@czechgroup.cz

+420 774 201 483

*
*