承接 bugo/flexgrid 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

bugo/flexgrid

最新稳定版本:0.1

Composer 安装命令:

composer require bugo/flexgrid

包简介

Fluent PHP builder for CSS Grid and Flexbox layouts

README 文档

README

PHP Coverage Status

Fluent PHP library for generating CSS Grid and Flexbox layouts. Supports named areas, line-based placement, responsive breakpoints, and ready-made presets for common patterns.

Installation

composer require bugo/flexgrid

Quick start

use FlexGrid\Grid;

echo Grid::columns(3, '.grid', '1.5rem')->build();
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}

GridBuilder

GridBuilder is the main class. All methods return static, so they chain freely.

Columns and rows

use FlexGrid\GridBuilder;
use FlexGrid\Enums\GridValue;

GridBuilder::make('.layout')
    ->columns('200px', '1fr', '200px')   // fixed values
    ->rows('64px', '1fr', '48px')        // row tracks
    ->gap('1rem')
    ->build();

Use GridValue helpers to avoid writing CSS strings by hand:

GridBuilder::make('.layout')
    ->columns(
        GridValue::fr(1),                          // "1fr"
        GridValue::minmax('200px', '1fr'),         // "minmax(200px, 1fr)"
        GridValue::repeat(3, GridValue::fr(1)),    // "repeat(3, 1fr)"
    )
    ->autoRows(GridValue::minmax('100px', 'auto')) // grid-auto-rows
    ->build();

Shorthand methods for repeated tracks:

GridBuilder::make('.grid')
    ->repeatColumns(4, '1fr')         // repeat(4, 1fr)
    ->repeatRows(3, '200px')          // repeat(3, 200px)
    ->autoFillColumns('250px')        // repeat(auto-fill, minmax(250px, 1fr))
    ->autoFitColumns('250px', '1fr')  // repeat(auto-fit,  minmax(250px, 1fr))
    ->build();

Gap

->gap('1rem')           // gap: 1rem  (both axes)
->gap('1rem', '2rem')   // gap: 1rem 2rem  (row, column)
->rowGap('1rem')        // row-gap only
->columnGap('2rem')     // column-gap only

Named template areas

Use GridTemplate to define the visual layout as an ASCII-art grid:

use FlexGrid\GridTemplate;

GridBuilder::make('.page')
    ->columns('220px', '1fr')
    ->rows('60px', '1fr', '40px')
    ->areas(GridTemplate::create()
        ->row(['header', 'header'])
        ->row(['nav',    'main'])
        ->row(['nav',    'footer']))
    ->build();
.page {
  display: grid;
  grid-template-columns: 220px 1fr;
  grid-template-rows: 60px 1fr 40px;
  grid-template-areas:
    "header header"
    "nav main"
    "nav footer";
}

For a more compact syntax, pass the area names as strings directly:

GridBuilder::make('.page')
    ->areaRows(
        'header header',
        'nav    main',
        'nav    footer',
    )
    ->build();

Grid items (child elements)

Attach GridItem objects to the builder to generate child selectors alongside the container:

use FlexGrid\GridItem;
use FlexGrid\Enums\ItemAlignment;

GridBuilder::make('.page')
    ->columns('220px', '1fr')
    ->rows('60px', '1fr', '40px')
    ->areaRows('header header', 'nav main', 'nav footer')
    ->item(GridItem::select('.page__header')->namedArea('header'))
    ->item(GridItem::select('.page__nav')->namedArea('nav'))
    ->item(GridItem::select('.page__main')->namedArea('main'))
    ->item(
        GridItem::select('.page__aside')
            ->justifySelf(ItemAlignment::End)
            ->alignSelf(ItemAlignment::Start)
    )
    ->build();
.page {
  display: grid;
  grid-template-columns: 220px 1fr;
  grid-template-rows: 60px 1fr 40px;
  grid-template-areas:
    "header header"
    "nav main"
    "nav footer";
}

.page__header { grid-area: header; }
.page__nav    { grid-area: nav; }
.page__main   { grid-area: main; }
.page__aside  { justify-self: end; align-self: start; }

Line-based placement

When named areas are not used, place items by grid line numbers:

use FlexGrid\GridArea;

GridBuilder::make('.gallery')
    ->repeatColumns(4, '1fr')
    ->gap('1rem')
    ->item(
        GridItem::select('.gallery__hero')
            ->area(GridArea::at(1, 1)->spanRows(2)->spanColumns(2))
    )
    ->item(
        GridItem::select('.gallery__wide')
            ->area(GridArea::at(3, 1)->spanColumns(3))
    )
    ->item(
        GridItem::select('.gallery__tall')
            ->area(GridArea::at(1, 4)->rowEnd(4))
    )
    ->build();
.gallery { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.gallery__hero  { grid-row: 1 / span 2; grid-column: 1 / span 2; }
.gallery__wide  { grid-row: 3 / auto;   grid-column: 1 / span 3; }
.gallery__tall  { grid-row: 1 / 4;      grid-column: 4 / auto;   }

Alignment

Grid alignment is split into two enums:

  • ItemAlignment: align-items, justify-items, align-self, justify-self
  • ContentAlignment: align-content, justify-content
use FlexGrid\Enums\ContentAlignment;
use FlexGrid\Enums\ItemAlignment;

GridBuilder::make('.grid')
    ->columns(GridValue::repeat(3, '200px'))
    ->placeItems(ItemAlignment::Center)                  // align-items + justify-items
    ->placeContent(ContentAlignment::Center)             // align-content + justify-content
    ->build();

// Or set each axis individually:
GridBuilder::make('.grid')
    ->alignItems(ItemAlignment::Start)
    ->justifyItems(ItemAlignment::End)
    ->alignContent(ContentAlignment::SpaceBetween)
    ->justifyContent(ContentAlignment::SpaceAround)
    ->build();

ItemAlignment cases: Start, End, Center, Stretch, Baseline.

ContentAlignment cases: Start, End, Center, Stretch, SpaceBetween, SpaceAround, SpaceEvenly.

Self-alignment on items:

GridItem::select('.box')
    ->placeSelf(ItemAlignment::Center)       // align-self + justify-self
    ->build();

GridItem::select('.box')
    ->alignSelf(ItemAlignment::Start)
    ->justifySelf(ItemAlignment::End)
    ->build();

Auto flow and implicit tracks

GridBuilder::make('.masonry')
    ->autoFillColumns('220px')
    ->autoRows('10px')           // fine-grained implicit rows for JS masonry
    ->autoFlow('row dense')      // fill gaps greedily
    ->build();

Responsive breakpoints

responsive(int $minWidth, callable) wraps a variant in @media (min-width: …). media(string $query, callable) accepts any media query string.

GridBuilder::make('.layout')
    ->columns('1fr')
    ->gap('1rem')
    ->responsive(640, fn(GridBuilder $g) =>
        $g->columns('1fr', '1fr')
    )
    ->responsive(1024, fn(GridBuilder $g) =>
        $g->columns('1fr', '1fr', '1fr')
          ->gap('2rem')
    )
    ->media('(prefers-reduced-motion: reduce)', fn(GridBuilder $g) =>
        $g->autoFlow('row')
    )
    ->build();
.layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

@media (min-width: 640px) {
  .layout { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1024px) {
  .layout { grid-template-columns: 1fr 1fr 1fr; gap: 2rem; }
}

@media (prefers-reduced-motion: reduce) {
  .layout { grid-auto-flow: row; }
}

Inline styles

toInlineStyle() returns a string suitable for the HTML style attribute — no selector, no braces:

$style = GridBuilder::make()
    ->columns('1fr', '2fr')
    ->gap('1rem')
    ->toInlineStyle();

// "display: grid; grid-template-columns: 1fr 2fr; gap: 1rem"
<div style="<?= $style ?>">…</div>

Inline grid

GridBuilder::make('.widget')
    ->inline()          // display: inline-grid
    ->columns('auto', '1fr')
    ->build();

Presets

The Grid facade provides one-liner factory methods for the most common layouts. Every preset returns a GridBuilder you can keep chaining.

Grid::columns()

Equal N-column layout.

Grid::columns(3, '.grid', '1.5rem')->build();
// grid-template-columns: repeat(3, 1fr); gap: 1.5rem

Grid::fluid()

Responsive fluid columns using auto-fill. Columns collapse automatically when the container is too narrow.

Grid::fluid('.cards', '280px', '1.25rem')->build();
// grid-template-columns: repeat(auto-fill, minmax(280px, 1fr))

Grid::sidebar()

Fixed-width sidebar on the left, fluid content on the right.

Grid::sidebar('.layout', '260px', '2rem')->build();
// grid-template-columns: 260px 1fr

Grid::centered()

Centers content at a max-width by placing fluid gutters on either side.

Grid::centered('.page', '860px')->build();
// grid-template-columns: 1fr minmax(0, 860px) 1fr

Place your content in the middle column:

GridItem::select('.page__content')->place(1, 2)->build();
// grid-row: 1 / auto; grid-column: 2 / auto

Grid::holyGrail()

Classic five-area layout: header across the top, sidebar + main content + aside in the middle, footer across the bottom.

Grid::holyGrail('.page', sideWidth: '220px', asideWidth: '160px')->build();
.page {
  display: grid;
  grid-template-columns: 220px 1fr 160px;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header  header  header"
    "sidebar main    aside"
    "footer  footer  footer";
}

Grid::dashboard()

Two-column dashboard with a persistent sidebar and a three-row main area.

Grid::dashboard('.app', sidebarWidth: '240px', headerHeight: '64px')->build();
.app {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: 64px 1fr auto;
  grid-template-areas:
    "header header"
    "nav    main"
    "nav    footer";
}

Grid::masonry()

Dense auto-flow grid for JavaScript masonry: items are placed greedily to fill gaps. Pair with JS to calculate grid-row-end per item.

Grid::masonry('.wall', '240px', '1rem')->build();
// grid-template-columns: repeat(auto-fill, minmax(240px, 1fr))
// grid-auto-rows: 10px
// grid-auto-flow: row dense

GridValue reference

Static helpers for CSS Grid value functions. All return plain strings.

Call Output
GridValue::fr(1) "1fr"
GridValue::fr(2.5) "2.5fr"
GridValue::minmax('200px', '1fr') "minmax(200px, 1fr)"
GridValue::repeat(3, '1fr') "repeat(3, 1fr)"
GridValue::repeat('auto-fill', '1fr') "repeat(auto-fill, 1fr)"
GridValue::fitContent('300px') "fit-content(300px)"
GridValue::Auto->value "auto"
GridValue::MaxContent->value "max-content"
GridValue::MinContent->value "min-content"

GridArea reference

// Named area (outputs grid-area)
GridArea::named('header');

// Line-based (outputs grid-row + grid-column)
GridArea::at(rowStart: 1, columnStart: 1)
    ->spanRows(2)
    ->spanColumns(3);

// Explicit end lines
GridArea::at(2, 1)
    ->rowEnd(5)
    ->columnEnd(4);

// Set lines individually
(new GridArea())
    ->rowStart(1)
    ->columnStart(3)
    ->spanRows(2);

GridItem reference

GridItem::select('.selector')
    ->namedArea('main')                      // grid-area: main
    ->place(2, 1)                            // grid-row: 2; grid-column: 1
    ->span(rowSpan: 2, colSpan: 3)           // span 2 rows, 3 columns
    ->area(GridArea::at(1, 2)->spanRows(2))  // full GridArea object
    ->alignSelf(ItemAlignment::Start)
    ->justifySelf(ItemAlignment::End)
    ->placeSelf(ItemAlignment::Center)       // both axes
    ->order(2)
    ->toCss();                               // returns CSS string

GridTemplate reference

$template = GridTemplate::create()
    ->row(['header', 'header', 'header'])
    ->row(['nav',    'main',   'aside'])
    ->row(['footer', 'footer', 'footer']);

$template->build();          // CSS value string for grid-template-areas
$template->getAreaNames();   // ['header', 'nav', 'main', 'aside', 'footer']
$template->columnCount();    // 3
$template->rowCount();       // 3

Flex Examples

Basic row with gap

use FlexGrid\Flex;

Flex::row('.menu', '1rem')->build();
.menu {
  display: flex;
  flex-direction: row;
  gap: 1rem;
}

Flexible cards with wrapping

use FlexGrid\Enums\FlexDirection;
use FlexGrid\Enums\FlexWrap;
use FlexGrid\FlexBuilder;

FlexBuilder::make('.cards')
    ->direction(FlexDirection::Row)
    ->wrap(FlexWrap::Wrap)
    ->gap('1rem')
    ->item(FlexItem::select('.cards > .card')->flex(1, 1, '240px'))
    ->build();
.cards {
  display: flex;
  flex-flow: row wrap;
  gap: 1rem;
}

.cards > .card { flex: 1 1 240px; }

Toolbar alignment

use FlexGrid\Enums\ContentAlignment;
use FlexGrid\Enums\FlexDirection;
use FlexGrid\Enums\ItemAlignment;
use FlexGrid\FlexBuilder;

FlexBuilder::make('.toolbar')
    ->direction(FlexDirection::Row)
    ->justifyContent(ContentAlignment::SpaceBetween)
    ->alignItems(ItemAlignment::Center)
    ->build();
.toolbar {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}

Responsive direction switch

use FlexGrid\Enums\FlexDirection;
use FlexGrid\FlexBuilder;

FlexBuilder::make('.layout')
    ->direction(FlexDirection::Column)
    ->gap('1rem')
    ->responsive(768, fn(FlexBuilder $f) => $f->direction(FlexDirection::Row))
    ->build();
.layout {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

@media (min-width: 768px) {
  .layout { flex-direction: row; }
}

Direction/wrap helpers and repeated gap calls

use FlexGrid\Enums\FlexDirection;
use FlexGrid\FlexBuilder;

FlexBuilder::make('.rail')
    ->direction(FlexDirection::ColumnReverse)
    ->noWrap()         // flex-wrap: nowrap
    ->gap('0.5rem')
    ->gap('1rem')      // last call wins
    ->build();
.rail {
  display: flex;
  flex-flow: column-reverse nowrap;
  gap: 1rem;
}

Flex Presets

The Flex facade provides one-liner factory methods for common Flexbox layouts.

Flex::row()

Flex::row('.menu', '0.75rem')->build();
// display: flex; flex-direction: row; gap: 0.75rem

Flex::column()

Flex::column('.stack', '0.5rem')->build();
// display: flex; flex-direction: column; gap: 0.5rem

Flex::cards()

Flex::cards('.cards', '240px', '1rem')->build();
// container: row + wrap + gap
// children (.cards > *): flex: 1 1 240px

Flex::sidebar()

Flex::sidebar('.layout', '260px', '1.5rem')->build();
// first child: flex: 0 0 260px
// last child:  flex: 1 1 0

FlexBuilder wrapping helpers

use FlexGrid\Enums\FlexDirection;
use FlexGrid\Enums\FlexWrap;
use FlexGrid\FlexBuilder;

FlexBuilder::make('.list')
    ->direction(FlexDirection::RowReverse)
    ->wrapReverse();   // flex-wrap: wrap-reverse

noWrap() is shorthand for wrap(FlexWrap::NoWrap). Repeated gap(...) calls do not accumulate: the last call replaces the previous value.

References

统计信息

  • 总下载量: 1
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-12

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固