Задать вопрос
  • Есть ли скрипт очень лёгкого календаря для выбора даты?

    delphinpro
    @delphinpro Куратор тега JavaScript
    Можно ли сэкономить на загрузке если на сервере средствами php сгенерить календарь, например, только на один конкретный месяц?


    Зачем? Любой месяц генерится на клиенте, джаваскриптом.

    очень лёгкого календаря


    Можно и свой скрипт накидать, строк на 100-200.

    Вот например, из недавнего. Там всплывающие подсказки, их можно урезать.
    Говнокалендарик, зато легкий =)
    //==
    //== Calendar
    //== ======================================= ==//
    
    (function () {
        const baseClass = 'calendar';
        const directions = {
            prev: { cls: 'prev', icon: 'arrow-left' },
            next: { cls: 'next', icon: 'arrow-right' },
        };
    
        const weekDays = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
    
        const months = [
            'Январь',
            'Февраль',
            'Март',
            'Апрель',
            'Май',
            'Июнь',
            'Июль',
            'Август',
            'Сентябрь',
            'Октябрь',
            'Ноябрь',
            'Декабрь',
        ];
    
        class Calendar {
            /**
             * @param {HTMLElement} el
             * @param {Array} events
             */
            constructor(el, events) {
                this.data = {
                    monthName: 'default',
                };
    
                this.events = events;
    
                /** @var {HTMLElement} */
                this.el = el;
                /** @var {HTMLElement} */
                this.elDays = null;
    
                /** @var {Date} */
                this.today = new Date();
                this.updateStartDate(this.today.getFullYear(), this.today.getMonth());
    
                this.el.appendChild(this.makeHeader());
                this.el.appendChild(this.makeWeekDays());
                this.el.appendChild(this.makeMonthDays());
    
                this.displayYear = this.today.getFullYear();
                this.displayMonthIndex = this.today.getMonth();
                this.displayMonth = months[this.displayMonthIndex] + ' ' + this.displayYear;
    
                this.el.addEventListener('mouseover', event => {
                    let handler = event.target.closest('.events');
                    if (handler) {
                        let content = handler.querySelector('.popper');
                        if (content) {
                            tippy(handler, {
                                content: `<div class="popper">${content.innerHTML}</div>`,
                                arrow: true,
                                arrowType: 'round', // sharp, round
                                interactive: true,
                                // trigger:'click'
                            });
                        }
                    }
                });
            }
    
            updateStartDate(fullYear, monthIndex){
                this.firstDayDate = new Date(fullYear, monthIndex, 1);
                this.firstDayOfMonth = this.firstDayDate.getDay();
                if (!this.firstDayOfMonth) this.firstDayOfMonth = 7;
                this.startDate = new Date(
                    this.firstDayDate.getFullYear(),
                    this.firstDayDate.getMonth(),
                    this.firstDayDate.getDate() - this.firstDayOfMonth + 1,
                );
            }
    
            get displayMonth() { return this.data.monthName; }
    
            set displayMonth(val) {
                this.data.monthName = val;
                this.elTitle.innerHTML = val;
            }
    
            makeHeader() {
                const el = document.createElement('div');
                const btnPrev = this.makeNavButton('prev');
                const btnNext = this.makeNavButton('next');
                el.classList.add(`${baseClass}__header`);
                el.appendChild(btnPrev);
                el.appendChild(this.makeMonthTitle());
                el.appendChild(btnNext);
    
                btnPrev.addEventListener('click', event => {
                    if (this.displayMonthIndex - 1 >= 0) {
                        this.displayMonthIndex--;
                    } else {
                        this.displayMonthIndex = 11;
                        this.displayYear--;
                    }
                    // console.log(this.displayMonthIndex, this.displayYear);
                    this.displayMonth = months[this.displayMonthIndex] + ' ' + this.displayYear;
                    this.updateStartDate(this.displayYear, this.displayMonthIndex);
                    this.updateMonthDays();
                });
    
                btnNext.addEventListener('click', event => {
                    if (this.displayMonthIndex + 1 <= 11) {
                        this.displayMonthIndex++;
                    } else {
                        this.displayMonthIndex = 0;
                        this.displayYear++;
                    }
                    console.log(this.displayMonthIndex, this.displayYear);
                    this.displayMonth = months[this.displayMonthIndex] + ' ' + this.displayYear;
                    this.updateStartDate(this.displayYear, this.displayMonthIndex);
                    this.updateMonthDays();
                });
    
                return el;
            }
    
            makeMonthTitle() {
                this.elTitle = document.createElement('div');
                this.elTitle.classList.add(`${baseClass}__month-title`);
                this.elTitle.innerHTML = this.displayMonth;
                return this.elTitle;
            }
    
            makeNavButton(direction) {
                if (!directions.hasOwnProperty(direction)) {
                    throw new Error('Неверный параметр (prev/next)');
                }
    
                const el = document.createElement('button');
                el.classList.add(`${baseClass}__button`);
                el.classList.add(`${baseClass}__button_${directions[direction].cls}`);
                el.innerHTML = App.makeSvgIcon(directions[direction].icon, `${baseClass}__btn-icon`);
                return el;
            }
    
            makeWeekDays() {
                const el = document.createElement('div');
                el.classList.add(`${baseClass}__weekdays`);
                el.innerHTML = weekDays.reduce((acc, cur) => acc + `<div class="${baseClass}__weekday">${cur}</div>`, '');
                return el;
            }
    
            updateMonthDays(){
                let html = '';
                let counter = 0;
                let isMuted = this.startDate.getDate() !== 1;
    
                let idCounter = 1;
                while (counter < 7 * 6) {
                    let start = this.startDate.getDate();
                    let mutedClass = isMuted ? ` ${baseClass}__day_muted` : '';
                    let events = this.events.find(item => {
                        let d1 = this.startDate.getFullYear().toString()
                            + this.startDate.getMonth().toString()
                            + this.startDate.getDate().toString();
                        let _T = new Date(item.date);
                        let d2 = _T.getFullYear().toString()
                            + _T.getMonth().toString()
                            + _T.getDate().toString();
                        return d1 === d2;
                    });
    
                    let pastEvent = false;
    
                    if (events) {
                        let eventDate = new Date(events.date);
                        if (eventDate < this.today) {
                            pastEvent = true;
                        }
                    }
    
                    let innerHtml = `<span>${start}</span>`;
    
                    if (events && events.events && events.events.length > 0) {
                        let eventsHtml = events.events.reduce((p, i) => `${p}<a href="${i.link}">${i.title}</a>`, '');
                        innerHtml = `<span class="events ${pastEvent
                            ? 'past'
                            : ''}">${start}<span class="popper" id="iddpr${idCounter++}" hidden>${eventsHtml}</span></span>`;
                    }
    
                    html += `<div class="${baseClass}__day${mutedClass}">${innerHtml}</div>`;
                    counter++;
                    this.startDate.setDate(this.startDate.getDate() + 1);
                    if (this.startDate.getDate() === 1) { isMuted = !isMuted; }
                }
    
                this.elDays.innerHTML = html;
            }
    
            makeMonthDays() {
                this.elDays = document.createElement('div');
                this.elDays.classList.add(`${baseClass}__days`);
                this.updateMonthDays();
                return this.elDays;
            }
        }
    
        App.calendar = function (el, data) {
            if (!el) return;
    
            return new Calendar(el, data);
        };
    
    })();
  • Как убрать отступ?

    delphinpro
    @delphinpro Куратор тега CSS
    Браузер применяет к некоторым элементам стили по-умолчанию.
    Откройте для себя инструмент в браузере — инспектор элементов. Там вы всё сможете увидеть своими глазами.
  • Кто как делает разметку по БЭМ?

    Заголовок вполне может быть, и чаще всего есть, отдельным блоком. Дополнительные стили в контексте родительского блока миксуются через элемент этого блока.

    Контейнер тоже есть самостоятельный блок. И к нему так же могут миксоваться дополнительные стили.

    Всё нормально, никаких противоречий.
  • Как сделать поиск по странице?

    delphinpro
    @delphinpro Куратор тега JavaScript
    Stalker_RED, Интересно, застаррил, посмотрю на досуге.
  • Кто может проверить верстку / сборку лендинга на flexbox / сделать код ревью?

    delphinpro
    @delphinpro Куратор тега CSS
    jupyter, насчет body я неточно написал — имел ввиду, что этот элемент не должен участвовать в раскладке страницы, быть частью сетки. Любые другие стили — пожалуйста.
  • Какой самый простой способ шаблонизации html-страниц (js)?

    delphinpro
    @delphinpro Куратор тега JavaScript
    А все эти паги от лукавого =)) ни к чему учить еще один синтаксис...
  • Какой самый простой способ шаблонизации html-страниц (js)?

    delphinpro
    @delphinpro Куратор тега JavaScript
    Spaceoddity, Вам для верстки, не для сайта, я так понимаю.

    Если хочется совсем простого и эйчтиэмэльного, посмотрите на gulp-twig (или другие порты этого шаблонизатора под нужную вам систему)

    Как раз то что вам нужно:

    {% include './blocks/header.twig' %}
    <div class="my-page">
      bla
    </div>
    {% include './blocks/footer.twig' %}


    Ну и остальные плюшки постепенно освоите в процессе использования.
  • Зачем нужен frontend, если всю начинку сайта или проекта можно реализовать с помощью backend'a?

    Ага. А давайте вы вконтактик напишете без html/css/javascript. Вот тогда будет о чем разговаривать.

    Не вопрос, а толстый троллинг.
  • Кто может проверить верстку / сборку лендинга на flexbox / сделать код ревью?

    delphinpro
    @delphinpro Куратор тега CSS
    Spaceoddity, но ведь это вы прицепились к БЭМу =))
    Я лишь упомянул его, как один из вариантов.
    Попробуем еще раз, снова.

    Порядок и система в стилях должны быть. С этим, надеюсь, не будете спорить.
    Какую методологию вы выберете - не суть важно. Вернемся к пресловутой кнопке, о которой я написал замечание.
    .button { margin-top: 40px; ... }
    Это очень плохо. Для примитивной единственной страницы — допустимо, для сайта — нет. Кнопки разные, по разному расположены, и нельзя в базовый стиль кнопки писать такое правило, чтобы потом не переопределять его везде где надо и не надо.

    Лирическое отступление для полного понимания:
    Читая слово "кнопка" подразумевайте любой блок на страницах.


    Используя бэм, мы примиксуем в кнопке элемент родительского блока

    <div class="super-block">
      <button class="button super-block__button"></button
    </div>
    .super-block__button { margin-top: 40px; }


    Используя AtomicCSS мы напишем утилитарный класс, что то типа:
    <button class="button mt40"></button>
    .mt40 { margin-top: 40px; }


    Используя OOCSS мы опять же разделим стили структуры и стили оформления.
    И т.д.

    В любом случае базовые стили кнопки будут содержать лишь ее оформление, но не положение на странице. И у вас не возникнет лишних проблем, когда заказчик вдруг скажет: "а давайте вот сюда тоже кнопочку втюхаем".

    Это вам заодно и ответ о независимых блоках. С ними верстка более гибкая, ее сложнее сломать. И на всякий случай уточню, чтобы избежать лишних вопросов: независимые блоки — это не только лишь БЭМ. Я бы даже сказал, это вовсе не БЭМ. БЭМ реализует эту идеологию, но имплементации могут быть разными.

    Что вы думаете по поводу каскадирования?


    Что тут думать? Богатство возможностей CSS прекрасно. И им стоит пользоваться. Я не впадаю в крайности.
  • Кто может проверить верстку / сборку лендинга на flexbox / сделать код ревью?

    delphinpro
    @delphinpro Куратор тега CSS
    Spaceoddity,
    Вы совершенно не поняли о чем я написал.
    Ответьте на один вопросик: по вашему нормально спорить, не разбираясь в предмете? Поучитесь еще годик-другой, тогда возможно, нам с вами будет о чем подискутировать.

    Поймите, я не позиционирую себя богом верстки. Хотя и опыт у меня огромный. И для споров открыт, когда предмет спора стоит того. Но когда речь идет о базовых вещах, которые давным давно устоялись, которые проверены сотнями разработчиков и по сути являются неписанными правилами, я не вижу смысла в дискуссии. Вы либо принимаете чужой опыт, либо сами его получаете путем проб и ошибок, придя в итоге в ту же точку.
  • Как сделать такой же текст с линией, как на скрине?

    delphinpro
    @delphinpro Куратор тега CSS
    google: "horizontal line with words", "line on side header"
  • Кто может проверить верстку / сборку лендинга на flexbox / сделать код ревью?

    delphinpro
    @delphinpro Куратор тега CSS
    Spaceoddity, Позиционировать от контекста. Как именно — зависит от выбранной методики. Если это БЭМ, то элементами, если это Атомик, то утилитарными классами, и т.д.

    На второе отвечать не буду, потому что глупость написали.
  • Блоки с разной длиной контента, как прижать кнопку к низу блока?

    delphinpro
    @delphinpro Куратор тега CSS
    Антон Вебсайтовский, в этом варианте достаточно добавить нижний внутренний отступ у текста равный высоте кнопки.
  • Блоки с разной длиной контента, как прижать кнопку к низу блока?

    delphinpro
    @delphinpro Куратор тега CSS
    Пересилил себя. Очень не хотелось ковыряться в этих дебильных именах классов. Не пишите так.
    Но все же вот — https://jsfiddle.net/bfm4gohj/
  • Каковы современные тенденции веб программирования?

    Разделяя клиент и сервер, вам еще нужно будет позаботится о SSR, ради поисковиков.
    Для этого на серваке потребуется нода или v8js. Оба случая практически исключают возможность использования shared хостингов.
    Ну конечно это дополнительные килобайты текста для изучения =))
    Если нужно сделать
    - чтобы оно было универсально, то есть корректно отображалось на смартфонах, планшетах, десктопах
    - чтобы оно корректно работало на старых/дешевых смартфонах

    просто возьмите ларку и сделайте.

    И вот этот тезис в корне неправильный:
    нужно изучать Bootstrap для адаптивной верстки


    Для адаптивной верстки нужно css знать на пятёрочку.
  • Кто может проверить верстку / сборку лендинга на flexbox / сделать код ревью?

    delphinpro
    @delphinpro Куратор тега CSS
    Я общие замечания сделаю, без оглядки на конкретный макет (я его даже смотреть не буду).

    https://github.com/DmitryBecker/golden_flexbox_gul...
    За это по рукам обычно бьют. Правильный путь — normalize.css.

    https://github.com/DmitryBecker/golden_flexbox_gul...
    Не должен body в верстке участвовать. Сделайте отдельный контейнер.

    https://github.com/DmitryBecker/golden_flexbox_gul... У всех кнопок марджин. А если нет? Не должно быть у кнопок (и вообще у блоков, раз уж вы на БЭМ замахнулись) внешних отступов. Здесь тоже, и еще много где:
    https://github.com/DmitryBecker/golden_flexbox_gul...

    https://github.com/DmitryBecker/golden_flexbox_gul... три одинаковых элемента примиксованы к одинаковым блокам. Отличие лишь в картинке, которое и следовало вынести в отдельные стили, одно правило background-image.

    https://github.com/DmitryBecker/golden_flexbox_gul... BR в верстке обычно не используют, за редким исключением. Это не тот случай.

    https://github.com/DmitryBecker/golden_flexbox_gul... пустые ссылки, нет ни текста, ни aria-label (в подвале тоже)

    https://github.com/DmitryBecker/golden_flexbox_gul... кнопка в форме не кнопка

    https://github.com/DmitryBecker/golden_flexbox_gul... здесь бардак с именами классов

    Итого:
    В целом нормально, прослеживается определенная структура и упорядоченность в верстке. Но все это не доведено до полного осмысления, вроде бы заметен бэм подход, а на деле он то есть, то нет. Можно придраться к оформлению scss кода в части использования возможностей препроцессора (&), но тут наверное дело вкуса. По крайней мере стили разбиты по файлам и не перемешаны, что уже хорошо.
  • Как правильно задавать стили для плагина?

    delphinpro
    @delphinpro Куратор тега CSS
    В плагине лучше не использовать семантические теги (p, article, strong, h1 и т.д), которые могут, и скорее всего будут стилизованы. Используйте только div и span, даже для кнопок.
    Имена классов максимально уникальные. Этого можно добиться пространством имён (.my-super-plugin-classname). В случае использования Vue уникальность достигается scoped стилями.
  • Как правильно задавать стили для плагина?

    delphinpro
    @delphinpro Куратор тега CSS
    У меня есть плагин для дебага.
    Панелька, кнопочки, информация.
    Сделан на Vue, встроенные стили, собрано вебпаком.

    Удобнее и проще подключить один файл. Тем более, если речь идет о дебаге. Т.е. это не прод, а дев окружение, и совершенно всем пофиг, что там внутри файла и как оно устроено.